From Ninja Metrics Developer Hub

IntegrationExamples: IOS

Getting Started

The iOS integration example is based on the open-source multiplayer game Wizard War.

In order to build and run this project, you’ll need a system running OS X.

  1. If you do not have an Apple developer account, register at http://developer.apple.com/register.
  2. Download and install Xcode 5 from https://developer.apple.com/devcenter/ios or the App Store.
  3. Install the CocoaPods dependency manager. From a Terminal window run: sudo gem install cocoapods
  4. Download the example project from https://bitbucket.org/ninja_metrics/katana-ios-integration-example.
  5. Open a Terminal window to the project root directory and download any missing dependencies by running: pod install
  6. Run XCode. Click “Open Other” in the Recent projects window and select the WizardWar.xcworkspace file in the project root directory.

Event Implementations

The following sections are the detailed notes for the implementation of various Katana API events. The Katana iOS library was integrated into the AnalyticsService class under \WizardWar\Service.

Katana API events can be called like so:
[AnalyticsService.shared.kAPI logSomeEvent:foo withParameter:bar];

For the timestamp parameter required by all events, we use the following constructor to create a new NSDate object initialized to the current UTC time:
[NSDate date]

For the account id and character id parameters required by most events, we use the uniquely generated "id" and user-defined "name" properties of the "User" object that may be already provided as a local variable or accessed via the UserService:
User *currentUser = [UserService.shared currentUser];

Since the game is not a complete virtual world with areas or locations we always use an empty string for the area name as well as "0" for area id, X, Y, and Z location parameters. The game also lacks different instances or shards, so "0" is also used for shard id in all locations. The string "iOS" is used for the platform parameter.

Back to Top


Login (Event ID #1)

There is no straightforward login process in this game for single or multiplayer. Therefore, it will be considered a Login event when the attribute "currentUser" from the UserService is assigned a User object. Also, a Login event is recorded when the application is brought back to the foreground after being minimized.

Parameters

ParameterValueNote
ACCOUNT ID The unique user id attribute of the User object
CHARACTER ID The user defined name attribute of the User object
SHARD ID0Zero since there's no notion of shards
PLATFORM"iOS"Denotes the application platform
AREA ID0Zero since there's no notion of areas
AREA NAME""An empty string is used since there's no notion of areas
Sample
From UserService.m Line 230:
self.currentUser = user;
// Login (Event #1)
// For the purpose of this demo, we consider it to be a Login event when the currentuser attribute is
then assigned.
[AnalyticsService.shared.kApi logLogin:[NSDate date] theAccountId:user.userId theCharacterId:user.name
theshardld:@ thePlatforn:@"ioS" theAreaId:@ theAreaName:@”"];

Back to Top


Logout (Event ID #2)

There is no straightforward logout process in this game for single or multiplayer. Therefore, it will be considered a Logout event when the application is terminated or moved to the background. Also by default, the iOS API wrapper uses the Logout event as a heartbeat to ping the Katana server on a regular interval.

Parameters

ParameterValueNote
ACCOUNT ID The unique user id attribute of the User object
CHARACTER ID The user defined name attribute of the User object
Sample
From AppDelegate.m Line 163, 190, 218:
//Logout Event #2
//For the purpose of this demo, we consider it to be a ‘ when the app terminates.
User aruscr = [UserService.shared currentllserl;
[AnalyticsService.shared.kApi logLogout:[NSDate date] theAccountId:user.userId theCharacterId:user.name];

Back to Top


Subscription Change (Event ID #3)

The game only has a free version and there is no notion of subscriptions or upgrading to a paid subscription. However, initially a player is considered a "guest user" until the user connects their Facebook account with the game. Therefore, it will be considered a Subscription Change event when the user is upgraded from a "guest user" after they connect their Facebook account.

Parameters

ParameterValueNote
SUBSCRIPTION STATUS"Active"Since the account is still active, only upgraded
SUBSCRIPTION TYPE"Premium"Since it's not paid, but different than free
SUBSCRIPTION VALUE0Zero since the game is free
SUBSCRIPTION EXPIRATION TIMESTAMP There is no expiration, but for testing a date one year in the future is used
Sample
From ProfileViewController.m Line 280:
// Subscription Change (Event #3)
            // For the purpose of this demo, we consider connecting with Facebook a Subscription Change event.
            [AnalyticsService.shared.kApi putSubChange:[NSDate date] theAccountId:user.userId theSubStatus:@"Active" theSubType:@"Premium" theSubValue:0 theExpireTs:[[NSDate date] dateByAddingTimeInterval:3.15569e7]]; // Expires in 1 year

Back to Top


Create Account (Event ID #9)

There is no process to create an account in this game. However, the first time the application is launched, a user is created with a unique identifier for their device and a random name is chosen. This unique identifier remains the same until the game is uninstalled. Therefore, it will be considered a Create Account event when the application is first launched and a new user with a unique identifier is created.

Parameters

ParameterValueNote
ACCOUNT TYPE"Free"The game is Free
LANGUAGE"en-US"Ninja Metrics US English language code
COUNTRY"US"Ninja Metrics United States country code
GENDER"N"Since you cannot denote a gender in game settings
DOB The game doesn't include DOB in game settings, so a dummy past date is used
CURRENCY BALACE0Zero since there is no notion of currency
Sample
From UserService.m Line 216:
        if (!user) {
            user = [ObjectStore.shared insertNewObjectForEntityForName:self.entityName];
            user.userId = [self generateUserId];
            user.isMain = YES;
            user.name = [self randomWizardName]; // [NSString stringWithFormat:@"Guest%@", [IdService randomId:4]];
            user.isGuestAccount = YES;
            user.wizardLevel = 1;
//            user.questLevel = 10;
            user.color = [UIColor blackColor];
            NSLog(@"UserService.currentUser: GENERATED %@", user.userId);
            // Check if this is the first run.
            NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
            if (![defaults objectForKey:@"firstRun"]) {
                // Create Account (Event #9)
                // For the purpose of this demo, we consider it to be a Create Account event when a new user is created on the first run.
                [AnalyticsService.shared.kApi loadAccountCreate:[NSDate date] theAccountId:user.userId theAccountType:@"Free" theAccLang:@"en-US" theAccCountry:@"US" theAccGender:@"N" theAccDateOfBirth:[NSDate dateWithTimeIntervalSinceReferenceDate:0] theAccCurrencyBal:0 thePlatform:@"iOS"];
                // Add a key to defaults to indicate the first run.
                [defaults setObject:[NSDate date] forKey:@"firstRun"];
                [[NSUserDefaults standardUserDefaults] synchronize];
            }

Back to Top


Initialize Item (Event ID #15)

The game does not have items in the classic sense, but an appropriate substitution is the spells that wizards cast against each other. Therefore, it will be considered an Initialize Item event when a player creates a Spell by moving their fingers in a particular pattern about the on screen Pentagram.

Parameters

ParameterValueNote
ITEM ID The randomly generated Spell id
ITEM NAME The name of the Spell
ITEM TYPE"Weapons"Since are used against other Wizards
ITEM SEGMENT"UGC"Since the player creates the Spell
Sample
From Combos.m Line 76:
if (spellToCast) {
        self.castSpell = spellToCast;
        self.lastSuccessfulSpell = self.castSpell;
        //User *user = [UserService.shared currentUser];
        // Initialize Item (Event #15)
        // For the purpose of the demo, we consider the creation of a valid spell an Initialize Item event.
        [AnalyticsService.shared.kApi loadItem:[NSDate date] theItemId: spellToCast.itemId theItemName:spellToCast.name theItemType:@"Weapons" theItemSegment:@"INGAME" createAccountId:@"" createCharacterId:@""];

Back to Top


Item Used (Event ID #16)

Since spells will be the representation of items in this game, it will be considered an Item Used event when a player casts a spell against another player.

Parameters

ParameterValueNote
ITEM ID The randomly generated Spell id
ITEM NAME The name of the Spell
ITEM Count0Zero since a Spell can be cast unlimited times
ITEM SEGMENT"UGC"Since the player creates the Spell
Sample
From Match.m Line 653:
-(BOOL)castSpell:(Spell *)spell {
    [self.ai opponent:self.currentWizard didCastSpell:spell atTick:self.timer.nextTick];
    BOOL success = [self player:self.currentWizard castSpell:spell currentTick:self.timer.nextTick];
    if (success) {
        [self.mainPlayerSpellHistory addObject:spell.type];
        // Item Used (Event #16)
        // For the purpose of the demo, we consider casting a spell an Item Used event.
        User *user = [UserService.shared currentUser];
        [AnalyticsService.shared.kApi logItem:[NSDate date] theAccountId:user.userId theCharacterId:user.name theCharacterLvl:user.wizardLevel theShardId:0 theItemId:spell.itemId theItemName:spell.name theItemCount:0 theAreaId:0 theAreaName:@"" theX:0 theY:0 theZ:0];

Back to Top


Level Begin (Event ID #27)

In the game, a match begins when a player starts a quest or a multiplayer duel. It will be considered a Level Begin event when a new match, either a quest or duel, begins.

Parameters

ParameterValueNote
LEVEL ID The current Quest level or 0 for duels
CHARACTER LEVEL The player's Wizard level
Sample
From MatchViewController.m Line 137:
// Match starts.... NOW
    [self.match connect];
    // Level Begin (Event #27)
    // For the purpose of this demo, we consider starting a match a Level Begin event.
    User *currentUser = [UserService.shared currentUser];
    long level = self.questLevel != nil ? self.questLevel.level : 0; // For quests use quest level, otherwise no level for challenges
    [AnalyticsService.shared.kApi levelBegin:[NSDate date] theAccountId:currentUser.userId theCharacterId:currentUser.name theCharacterLevel:currentUser.wizardLevel theShardId:0 theLevelId:level theX:0 theY:0 theZ:0 theAreaName:@""];

Back to Top


Level End (Event ID #28)

Similar to a Level Begin event, it will be considered a Level End event when a match, either a quest or duel, ends.

Parameters

ParameterValueNote
LEVEL ID The current Quest level or 0 for duels
CHARACTER LEVEL The player's Wizard level
Sample
From MatchViewController Line 376:
// Level End (Event #28)
    // For the purpose of this demo, we consider finishing a match a Level End event.
    long level = self.questLevel != nil ? self.questLevel.level : 0; // For quests use quest level, otherwise no level for challenges
    [AnalyticsService.shared.kApi levelEnd:[NSDate date] theAccountId:currentUser.userId theCharacterId:currentUser.name theCharacterLevel:currentUser.wizardLevel theShardId:0 theLevelId:level theX:0 theY:0 theZ:0 theAreaName:@""];

Back to Top


Non-Player Character (Event ID #31)

In the game, a player can play quest levels that are duels against AI based wizards. It will be considered a Non-Player Character when an enemy AI wizard is spawned at the beginning of a quest. This initializes the NPC in the dimension table for the other NPC related events.

Parameters

ParameterValueNote
NPC EVENT NAME"NPC Spawned"Since this is the NPC initialization event
NPC EVENT TYPE"Combat"Since players battle the NPC in a Quest
NPC ID The Quest level is used since each NPC is unique to a Quest level
NPC NAME The AI based Wizard name
NPC TYPE"Enemy"Since the player always fights the NPC in a Quest
MIN LEVEL The Wizard level required to play this Quest
MAX LEVEL There is no max level, so we use an arbitrarily high number that is unlikely to be achieved. Due to the current iOS API library implementation, values not required by the API or that use default values are not taken into account. Therefore where applicable values do not exist we must use placeholder values that might not make perfect sense in the current context.
TOUGHNESS The Quest level
TOUGHNESS ENUM The Quest level name
Sample
From MatchViewController.m Line 227:
 // NPC Event (#31)
    // For the purpose of this demo, we consider it an NPC event when an AI Wizard is created. There is no max level, so we use an arbitrarily high number that would most likely never be achieved.
    [AnalyticsService.shared.kApi logNpcInteraction:[NSDate date] theAccountId:user.userId theCharacterId:user.name theShardId:0 npcEventName:@"NPC Spawned" npcEventType:@"Combat" npcId:npcId npcName:ai.wizard.name npcType:@"Enemy" theMinLevel:level.wizardLevel theMaxLevel:9999 theToughness:level.level  theToughnessEnum:level.name];
    Match * match = [[Match alloc] initWithMatchId:@"Quest" hostName:wizard.name currentWizard:wizard withAI:ai multiplayer:nil sync:nil];

Back to Top


Recruitment Send (Event ID #33)

In the game, a player can challenge an opponent to a duel. The act of challenging another player to a duel will be considered a Recruitment Send event.

Parameters

ParameterValueNote
SEND ACCOUNT ID The user id of the player who initiated the duel challenge
SEND CHARACTER ID The wizard name of the player who initiated the duel challenge
RECEIVER ACCOUNT ID The user id of the player who was challenged to a duel
RECEIVER CHARACTER ID The wizard name of the player who was challenged to a duel
RECRUITMENT TYPE"Invited By Another User"Since one player challenges the other
Sample
From ChallengeService.m Line 190:
if (isRemote) {
        [self notifyOpponent:challenge];
    }
    // Recruitment Send (Event #33)
    // For the purpose of this demo, we will consider a Recruitment Send event when a user challenges an opponent.
    [AnalyticsService.shared.kApi recruitmentSend:[NSDate date] sendAccId:user.userId sendCharId:user.name recvAccId:opponent.userId recvCharId:opponent.name theRecruitmentType:@"Invited By Another User"];

Back to Top


Recruitment Receive Action (Event ID #34)

In the game, a player can respond to a duel challenge sent by another player. The act of the player responding to a duel challenge will be considered a Recruitment Send event.

Parameters

ParameterValueNote
SEND ACCOUNT ID The user id of the player who initiated the duel challenge
SEND CHARACTER ID The wizard name of the player who initiated the duel challenge
RECEIVER ACCOUNT ID The user id of the player who was challenged to a duel
RECEIVER CHARACTER ID The wizard name of the player who was challenged to a duel
RECRUITMENT TYPE"Invited By Another User"Since one player challenges the other
RECRUITMENT OUTCOME"Accepted" or "Declined"Depending the receiver's response
Sample
From ChallengeService.m Line 120:
- (void)acceptChallenge:(Challenge*)challenge {
    [AnalyticsService event:@"challenge-accept"];
    [self setChallenge:challenge status:ChallengeStatusAccepted];
    // Recruitment Receive (Event #34)
    // For the purpose of this demo, we will consider a Recruitment Receive event when a user accepts a challenge.
    [AnalyticsService.shared.kApi recruitmentReceive:[NSDate date] sendAccId:challenge.main.userId sendCharId:challenge.main.name recvAccId:challenge.opponent.userId recvCharId:challenge.opponent.name theRecruitmentType:@"Invited By Another User" theRecruitmentOutcome:@"Accepted"];
}
Sample
From ChallengeService.m Line 128:
- (void)declineChallenge:(Challenge*)challenge {
    [self setChallenge:challenge status:ChallengeStatusDeclined];
    // Recruitment Receive (Event #34)
    // For the purpose of this demo, we will consider a Recruitment Receive event when a user declines a challenge.
    [AnalyticsService.shared.kApi recruitmentReceive:[NSDate date] sendAccId:challenge.main.userId sendCharId:challenge.main.name recvAccId:challenge.opponent.userId recvCharId:challenge.opponent.name theRecruitmentType:@"Invited By Another User" theRecruitmentOutcome:@"Declined"];
}

Back to Top


Begin Combat (Event ID #21)

In the game, a quest is a match with an NPC AI based wizard. It will be considered a Begin Combat event when a quest's match status is changed to "Playing" and combat has begun.

Parameters

ParameterValueNote
NPC ID The Quest level is used since each NPC is unique to a Quest level
Sample
From Match.m Line 237:
// Is this a Quest?
        if (self.aiWizard) {
            // Begin Combat (Event #21)
            // For the purpose of this demo, it is considered a Begin Combat Event when a the MatchStatus changes to Playing during a Quest.
            User *user = [UserService.shared currentUser];
            [AnalyticsService.shared.kApi combatStart:[NSDate date] theAccountId:user.userId theCharacterId:user.name theShardId:0 theNpcId:self.aiWizard.npcId theAreaId:0 theX:0 theY:0 theZ:0 theBeginAreaName:@""];

Back to Top


End Combat (Event ID #22)

Similar to the Begin Combat event, it will be considered an End Combat event when a quest's match status is "Finished" and combat has ceased.

Parameters

ParameterValueNote
NPC ID The Quest level is used since each NPC is unique to a Quest level
Sample
From MatchViewController Line 339:
// End Combat (Event #22)
        // For the purpose of this demo, we consider the end of a quest an End Combat event.
        [AnalyticsService.shared.kApi combatEnd:[NSDate date] theAccountId:currentUser.userId theCharacterId:currentUser.name theShardId:0 theNpcId:npcId theAreaId:0 theX:0 theY:0 theZ:0 theEndAreaName:@""];

Back to Top


Kill NPC (Event ID #23)

It will be considered a Kill NPC event when a player has won a quest by defeating its NPC AI based wizard.

Parameters

ParameterValueNote
CHARACTER LEVEL The player's Wizard level
NPC ID The Quest level is used since each NPC is unique to a Quest level
Sample
From Match.m Line 571:
 } else if (wizard == self.aiWizard) {
                    // Kill NPC (Event #23)
                    // For the purpose of this demo, we consider it a Kill NPC event when the player kills the AI Wizard.
                    [AnalyticsService.shared.kApi logKillNpc:[NSDate date] theAccountId:user.userId theCharacterId:user.name theShardId:0 theCharacterLvl:user.wizardLevel theNpcId:self.aiWizard.npcId];

Back to Top


Player Versus Player Duel (Event ID #25)

It will be considered a Player Versus Player Duel event when a multiplayer match ends.

Parameters

ParameterValueNote
WIN FLAG:YES or NODepending on the outcome of the duel
Sample
From MatchViewController Line 339:
if (self.challenge) {
        // PVP Duel (Event #25)
        // For the purpose of this demo, we consider the end of a challenge a PVP Duel event.
        [AnalyticsService.shared.kApi logPvpDuel:[NSDate date] theAccountId:currentUser.userId theCharacterId:currentUser.name theShardId:0 isWinner:didWin];
    }

Back to Top


Player Death (Event ID #26)

It will be considered a Player Death event when an NPC AI kills the player's wizard and the player loses the quest.

Parameters

ParameterValueNote
NPC ID The Quest level is used since each NPC is unique to a Quest level
DEATH TYPE"NA"NA, since all deaths are the treated the same
Sample
From Match.m Line 566:
// Was the player or AI Wizard killed?
                if (wizard == self.currentWizard) {
                    // Player Death (Event #26)
                    // For the purpose of this demo, we consider it a Player Death event when the AI Wizard kills the player's Wizard.
                    [AnalyticsService.shared.kApi logPlayerDeath:[NSDate date] theAccountId:user.userId theCharacterId:user.name theShardId:0 theKillerNpcId:self.aiWizard.npcId theDeathType:@"NA" theAreaId:0 theX:0 theY:0 theZ:0 theAreaName:@""];

Back to Top


Challenge (Event ID #32)

In the game, a challenge could be considered a quest level where the player duels an NPC AI based wizard. It will be considered a Challenge event when a player chooses to play a quest level, leaves the quest level, or completes the quest level.

Parameters

ParameterValueNote
CHALLENGE ID The Quest level name
CHALLENGE TYPE"Kill An NPC or Multiple NPCs"Since all Quests are duels with NPCs
CHALLENGE STATUS"Accepted", "Completed", or "Abandoned"Depending on player action
Sample
From MatchViewController.m Line 206:
- (void)createMatchWithWizard:(Wizard *)wizard withLevel:(QuestLevel *)level {
    self.questLevel = level;
    [AnalyticsService event:@"match"];
    [AnalyticsService event:@"match-quest"];    
    // Challenge (Event #32)
    // For the purpose of this demo, we consider accepting a quest a Challenge event.
    User *user = [UserService.shared currentUser];
    [AnalyticsService.shared.kApi logChallenge:[NSDate date] theAccountId:user.userId theCharacterId:user.name theShardId:0 challengeId:level.name challengeType:@"Kill An NPC or Multiple NPCs" challengeStatus:@"Accepted"];
Sample
From MatchViewController.m Line 345, 351:
if (didFinish) {
            // Challenge (Event #32)
            // For the purpose of this demo, we consider completing a quest a Challenge event.
            [AnalyticsService.shared.kApi logChallenge:[NSDate date] theAccountId:currentUser.userId theCharacterId:currentUser.name theShardId:0 challengeId:self.questLevel.name challengeType:@"Kill An NPC or Multiple NPCs" challengeStatus:@"Completed"];
        } else {
            // Challenge (Event #32)
            // For the purpose of this demo, we consider leaving a quest a Challenge event.
            [AnalyticsService.shared.kApi logChallenge:[NSDate date] theAccountId:currentUser.userId theCharacterId:currentUser.name theShardId:0 challengeId:self.questLevel.name challengeType:@"Kill An NPC or Multiple NPCs" challengeStatus:@"Abandoned"];
        }

Back to Top


Reward (Event ID #49)

It will be considered a Reward event when the player's wizard level is increased as a result of completing a quest, casting spells, or winning a duel against another player who has a greater wizard level than their own.

Parameters

ParameterValueNote
REWARD TYPE0Zero since only recording one type of Reward
REWARD ID"Wizard Level"Since the only recorded Reward is gaining a Wizard level
ITEM TYPE0Zero since no item is being rewarded
REWARD COUNT The player's new Wizard level
Sample
From QuestService.m Line 80:
if (questLevel.wizardLevel > currentUser.wizardLevel) {
            currentUser.wizardLevel += 1;
            [achievements addObject:[Achievement wizardLevel:currentUser]];
            // Reward (Event #49)
            // For the purpose of the demo, we consider a Reward event when the user gains a Wizard level.
            [AnalyticsService.shared.kApi logReward:[NSDate date] theAccountId:currentUser.userId theCharacterId:currentUser.name theShardId:0 theRewardType:0 theRewardId:@"Wizard Level" theItemType:0 theRewardCount:currentUser.wizardLevel];
From SpellbookService.m Line 111:
if (record.level > beforeLevel) {
            [achievements addObject:[Achievement spellLevel:record]];
            [AnalyticsService event:[NSString stringWithFormat:@"spell-unlock-%@-%i", type, record.level]];
            if (record.level > SpellbookLevelNovice) {
                currentUser.wizardLevel += 1;
                [achievements addObject:[Achievement wizardLevel:currentUser]];
                // Reward (Event #49)
                // For the purpose of the demo, we consider a Reward event when the user gains a Wizard level.
                [AnalyticsService.shared.kApi logReward:[NSDate date] theAccountId:currentUser.userId theCharacterId:currentUser.name theShardId:0 theRewardType:0 theRewardId:@"Wizard Level" theItemType:0 theRewardCount:currentUser.wizardLevel];
            }
From UserFriendService.m Line 100:
if (friend.wizardLevel > user.wizardLevel) {
            user.wizardLevel += 1;
            [achievements addObject:[Achievement wizardLevel:user]];
            // Reward (Event #49)
            // For the purpose of the demo, we consider a Reward event when the user gains a Wizard level.
            [AnalyticsService.shared.kApi logReward:[NSDate date] theAccountId:user.userId theCharacterId:user.name theShardId:0 theRewardType:0 theRewardId:@"Wizard Level" theItemType:0 theRewardCount:user.wizardLevel];

Back to Top


Off-Game-Interaction Sender (Event ID #7)

The game allows a player to send a download link to others for the game via Facebook by posting on their Facebook friends' walls. It will be considered an OGI Sender event when the player sends a message about the game to one of their Facebook friends.

Parameters

ParameterValueNote
SENDER ACCOUNT ID The player's user id who shared to Facebook
SENDER ACCOUNT NAME The player's wizard name who shared to Facebook
RECEIVER ACCOUNT ID The Facebook id of the receiving friend
RECEIVER ACCOUNT NAME The Facebook id of the receiving friend
OGI LOCATION"Facebook" 
OGI CATEGORY"Posts on Social Media" 
Sample
From MatchmakingViewController.m Line 863:
[UserFriendService.shared openFeedDialogTo:friendIds complete:^{
        [AnalyticsService event:@"invite-facebook-friend-complete"];
        // OGI Sender (Event #7)
        // For the purpose of the demo, we consider when the user posts on a friends Facebook an OGI Sender event
        User *user = [UserService.shared currentUser];
        [AnalyticsService.shared.kApi logOgiSend:[NSDate date] sendAccId:user.userId sendCharId:user.name recvAccId:[friendIds lastObject] recvCharId:[friendIds lastObject]  theShardId:0 theOgiLocation:@"Facebook" theOgiCategory:@"Posts on Social Media"];

Back to Top


Friend Addition (Event ID #43)

When the first duel between two players ends, they are now considered "Frenemies" and will always appear in their Lobby, even if they are logged out. It will be considered a Friend Addition Event when the first duel ends between two players and they become "Frenemies".

Parameters

ParameterValueNote
SENDER ACCOUNT ID The player's user id who initiated the duel
SENDER ACCOUNT NAME The player's wizard name who initiated the duel
RECEIVER ACCOUNT ID The player's user id who was challenged to the duel
RECEIVER ACCOUNT NAME The player's wizard name who was challenged to the duel
Sample
From UserFriendService.m Line 84:
// Was this the first challenge with this friend?
    if (friend.gamesTotal == 0) {
        // Friend Additon (Event #43)
        // For the purpose of this demo, we consider the end of the first game against a new player a Friend Addition event
        [AnalyticsService.shared.kApi logFriendAdd:[NSDate date] sendAccId:user.userId sendCharId:user.name recvAccId:friend.userId recvCharId:friend.name];

Back to Top


Friend Deletion (Event ID #44)

After a player becomes the user's "Frenemy", the user can remove them as a "Frenemy" by swiping their entry on the Lobby list and pressing the "Defrenemy" button. It will be considered a Friend Deletion event when a user removes another player as a "Frenemy".

Parameters

ParameterValueNote
SENDER ACCOUNT ID The player's user id who removed the "Frenemy"
SENDER ACCOUNT NAME The player's wizard name who removed the "Frenemy"
RECEIVER ACCOUNT ID The player's user id who was removed as a "Frenemy"
RECEIVER ACCOUNT NAME The player's wizard name who was removed as a "Frenemy"
Sample
From MatchmakingViewController.m Line 465:
[UserFriendService.shared user:self.currentUser removeFrenemy:user];
            // Friend Deletion (Event #44)
            // For the purpose of this demo, we consider removing a Frenemy a Friend Deletion event.
            [AnalyticsService.shared.kApi logFriendDelete:[NSDate date] sendAccId:self.currentUser.userId sendCharId:self.currentUser.name recvAccId:user.userId recvCharId:user.name];

Back to Top


Custom Slot (Event ID #54)

The Katana API has an empty slot to allow for a Custom event to be recorded that is unique to the particular application. The custom event recorded here is a "Block". During a duel a player can cast a spell that prevents them from being hit by a spell cast by an opposing player or NPC.

Parameters

ParameterValueNote
CUSTOM ACTION"Block" 
CUSTOM ACTION TYPE"Spell Interaction" 
CUSTOM ACTION VALUE0Zero since there is only one state for a Block
Sample
From Match.m Line 522:
 // Did the main player destory the opponents attack Spell?
        if (main.creator != self.currentWizard
            && main.status == SpellStatusDestroyed
            && main.isWall == NO) {
            // Custom Slot - Block (Event #54)
            // For the purpose of this demo, we are using the Custom Slot event when the player blocks the opponents attack Spell.
            User *user = [UserService.shared currentUser];
            [AnalyticsService.shared.kApi logCustomAction:[NSDate date] theAccountId:user.userId theCharacterId:user.name theCustomAction:@"Block" theCustomActionType:@"Spell Interaction" theCustomActionValue:0];

Back to Top


Retrieved from https://developer.ninjametrics.com/IntegrationExamples/IOS
Page last modified on February 20, 2014, at 06:49 AM