58 } |
52 } |
59 |
53 |
60 #pragma mark - |
54 #pragma mark - |
61 #pragma mark Provider functions |
55 #pragma mark Provider functions |
62 // unpacks team data from the selected team.plist to a sequence of engine commands |
56 // unpacks team data from the selected team.plist to a sequence of engine commands |
63 -(void) provideTeamData:(NSString *)teamName forHogs:(NSInteger) numberOfPlayingHogs withHealth:(NSInteger) initialHealth ofColor:(NSNumber *)teamColor { |
57 - (void)provideTeamData:(NSString *)teamName forHogs:(NSInteger)numberOfPlayingHogs withHealth:(NSInteger)initialHealth ofColor:(NSNumber *)teamColor { |
64 /* |
58 /* |
65 addteam <32charsMD5hash> <color> <team name> |
59 addteam <32charsMD5hash> <color> <team name> |
66 addhh <level> <health> <hedgehog name> |
60 addhh <level> <health> <hedgehog name> |
67 <level> is 0 for human, 1-5 for bots (5 is the most stupid) |
61 <level> is 0 for human, 1-5 for bots (5 is the most stupid) |
68 */ |
62 */ |
69 |
63 |
70 NSString *teamFile = [[NSString alloc] initWithFormat:@"%@/%@", TEAMS_DIRECTORY(), teamName]; |
64 NSString *teamFile = [[NSString alloc] initWithFormat:@"%@/%@", TEAMS_DIRECTORY(), teamName]; |
71 NSDictionary *teamData = [[NSDictionary alloc] initWithContentsOfFile:teamFile]; |
65 NSDictionary *teamData = [[NSDictionary alloc] initWithContentsOfFile:teamFile]; |
72 [teamFile release]; |
|
73 |
66 |
74 NSString *teamHashColorAndName = [[NSString alloc] initWithFormat:@"eaddteam %@ %@ %@", |
67 NSString *teamHashColorAndName = [[NSString alloc] initWithFormat:@"eaddteam %@ %@ %@", |
75 [teamData objectForKey:@"hash"], [teamColor stringValue], [teamName stringByDeletingPathExtension]]; |
68 [teamData objectForKey:@"hash"], [teamColor stringValue], [teamName stringByDeletingPathExtension]]; |
76 [self sendToEngine: teamHashColorAndName]; |
69 [self sendToEngine: teamHashColorAndName]; |
77 [teamHashColorAndName release]; |
|
78 |
70 |
79 NSString *grave = [[NSString alloc] initWithFormat:@"egrave %@", [teamData objectForKey:@"grave"]]; |
71 NSString *grave = [[NSString alloc] initWithFormat:@"egrave %@", [teamData objectForKey:@"grave"]]; |
80 [self sendToEngine: grave]; |
72 [self sendToEngine: grave]; |
81 [grave release]; |
|
82 |
73 |
83 NSString *fort = [[NSString alloc] initWithFormat:@"efort %@", [teamData objectForKey:@"fort"]]; |
74 NSString *fort = [[NSString alloc] initWithFormat:@"efort %@", [teamData objectForKey:@"fort"]]; |
84 [self sendToEngine: fort]; |
75 [self sendToEngine: fort]; |
85 [fort release]; |
|
86 |
76 |
87 NSString *voicepack = [[NSString alloc] initWithFormat:@"evoicepack %@", [teamData objectForKey:@"voicepack"]]; |
77 NSString *voicepack = [[NSString alloc] initWithFormat:@"evoicepack %@", [teamData objectForKey:@"voicepack"]]; |
88 [self sendToEngine: voicepack]; |
78 [self sendToEngine: voicepack]; |
89 [voicepack release]; |
|
90 |
79 |
91 NSString *flag = [[NSString alloc] initWithFormat:@"eflag %@", [teamData objectForKey:@"flag"]]; |
80 NSString *flag = [[NSString alloc] initWithFormat:@"eflag %@", [teamData objectForKey:@"flag"]]; |
92 [self sendToEngine: flag]; |
81 [self sendToEngine: flag]; |
93 [flag release]; |
|
94 |
82 |
95 NSArray *hogs = [teamData objectForKey:@"hedgehogs"]; |
83 NSArray *hogs = [teamData objectForKey:@"hedgehogs"]; |
96 for (int i = 0; i < numberOfPlayingHogs; i++) { |
84 for (int i = 0; i < numberOfPlayingHogs; i++) { |
97 NSDictionary *hog = [hogs objectAtIndex:i]; |
85 NSDictionary *hog = [hogs objectAtIndex:i]; |
98 |
86 |
99 NSString *hogLevelHealthAndName = [[NSString alloc] initWithFormat:@"eaddhh %@ %ld %@", |
87 NSString *hogLevelHealthAndName = [[NSString alloc] initWithFormat:@"eaddhh %@ %ld %@", |
100 [hog objectForKey:@"level"], (long)initialHealth, [hog objectForKey:@"hogname"]]; |
88 [hog objectForKey:@"level"], (long)initialHealth, [hog objectForKey:@"hogname"]]; |
101 [self sendToEngine: hogLevelHealthAndName]; |
89 [self sendToEngine: hogLevelHealthAndName]; |
102 [hogLevelHealthAndName release]; |
|
103 |
90 |
104 NSString *hogHat = [[NSString alloc] initWithFormat:@"ehat %@", [hog objectForKey:@"hat"]]; |
91 NSString *hogHat = [[NSString alloc] initWithFormat:@"ehat %@", [hog objectForKey:@"hat"]]; |
105 [self sendToEngine: hogHat]; |
92 [self sendToEngine: hogHat]; |
106 [hogHat release]; |
93 } |
107 } |
|
108 |
|
109 [teamData release]; |
|
110 } |
94 } |
111 |
95 |
112 // unpacks ammostore data from the selected ammo.plist to a sequence of engine commands |
96 // unpacks ammostore data from the selected ammo.plist to a sequence of engine commands |
113 -(void) provideAmmoData:(NSString *)ammostoreName forPlayingTeams:(NSInteger) numberOfTeams { |
97 - (void)provideAmmoData:(NSString *)ammostoreName forPlayingTeams:(NSInteger)numberOfTeams { |
114 NSString *weaponPath = [[NSString alloc] initWithFormat:@"%@/%@",WEAPONS_DIRECTORY(),ammostoreName]; |
98 NSString *weaponPath = [[NSString alloc] initWithFormat:@"%@/%@",WEAPONS_DIRECTORY(),ammostoreName]; |
115 NSDictionary *ammoData = [[NSDictionary alloc] initWithContentsOfFile:weaponPath]; |
99 NSDictionary *ammoData = [[NSDictionary alloc] initWithContentsOfFile:weaponPath]; |
116 [weaponPath release]; |
|
117 |
100 |
118 // if we're loading an older version of ammos fill the engine message with 0s |
101 // if we're loading an older version of ammos fill the engine message with 0s |
119 int diff = HW_getNumberOfWeapons() - [[ammoData objectForKey:@"ammostore_initialqt"] length]; |
102 int diff = HW_getNumberOfWeapons() - [[ammoData objectForKey:@"ammostore_initialqt"] length]; |
120 NSString *update = @""; |
103 NSString *update = @""; |
121 while ((int)[update length] < diff) |
104 while ((int)[update length] < diff) |
122 update = [update stringByAppendingString:@"0"]; |
105 update = [update stringByAppendingString:@"0"]; |
123 |
106 |
124 NSString *ammloadt = [[NSString alloc] initWithFormat:@"eammloadt %@%@", [ammoData objectForKey:@"ammostore_initialqt"], update]; |
107 NSString *ammloadt = [[NSString alloc] initWithFormat:@"eammloadt %@%@", [ammoData objectForKey:@"ammostore_initialqt"], update]; |
125 [self sendToEngine: ammloadt]; |
108 [self sendToEngine: ammloadt]; |
126 [ammloadt release]; |
|
127 |
109 |
128 NSString *ammprob = [[NSString alloc] initWithFormat:@"eammprob %@%@", [ammoData objectForKey:@"ammostore_probability"], update]; |
110 NSString *ammprob = [[NSString alloc] initWithFormat:@"eammprob %@%@", [ammoData objectForKey:@"ammostore_probability"], update]; |
129 [self sendToEngine: ammprob]; |
111 [self sendToEngine: ammprob]; |
130 [ammprob release]; |
|
131 |
112 |
132 NSString *ammdelay = [[NSString alloc] initWithFormat:@"eammdelay %@%@", [ammoData objectForKey:@"ammostore_delay"], update]; |
113 NSString *ammdelay = [[NSString alloc] initWithFormat:@"eammdelay %@%@", [ammoData objectForKey:@"ammostore_delay"], update]; |
133 [self sendToEngine: ammdelay]; |
114 [self sendToEngine: ammdelay]; |
134 [ammdelay release]; |
|
135 |
115 |
136 NSString *ammreinf = [[NSString alloc] initWithFormat:@"eammreinf %@%@", [ammoData objectForKey:@"ammostore_crate"], update]; |
116 NSString *ammreinf = [[NSString alloc] initWithFormat:@"eammreinf %@%@", [ammoData objectForKey:@"ammostore_crate"], update]; |
137 [self sendToEngine: ammreinf]; |
117 [self sendToEngine: ammreinf]; |
138 [ammreinf release]; |
|
139 |
118 |
140 // send this for each team so it applies the same ammostore to all teams |
119 // send this for each team so it applies the same ammostore to all teams |
141 NSString *ammstore = [[NSString alloc] initWithString:@"eammstore"]; |
120 NSString *ammstore = [[NSString alloc] initWithString:@"eammstore"]; |
142 for (int i = 0; i < numberOfTeams; i++) |
121 for (int i = 0; i < numberOfTeams; i++) { |
143 [self sendToEngine: ammstore]; |
122 [self sendToEngine: ammstore]; |
144 [ammstore release]; |
123 } |
145 |
|
146 [ammoData release]; |
|
147 } |
124 } |
148 |
125 |
149 // unpacks scheme data from the selected scheme.plist to a sequence of engine commands |
126 // unpacks scheme data from the selected scheme.plist to a sequence of engine commands |
150 -(NSInteger) provideScheme:(NSString *)schemeName { |
127 - (NSInteger)provideScheme:(NSString *)schemeName { |
151 NSString *schemePath = [[NSString alloc] initWithFormat:@"%@/%@",SCHEMES_DIRECTORY(),schemeName]; |
128 NSString *schemePath = [[NSString alloc] initWithFormat:@"%@/%@",SCHEMES_DIRECTORY(),schemeName]; |
152 NSDictionary *schemeDictionary = [[NSDictionary alloc] initWithContentsOfFile:schemePath]; |
129 NSDictionary *schemeDictionary = [[NSDictionary alloc] initWithContentsOfFile:schemePath]; |
153 [schemePath release]; |
130 |
154 NSArray *basicArray = [schemeDictionary objectForKey:@"basic"]; |
131 NSArray *basicArray = [schemeDictionary objectForKey:@"basic"]; |
155 NSArray *gamemodArray = [schemeDictionary objectForKey:@"gamemod"]; |
132 NSArray *gamemodArray = [schemeDictionary objectForKey:@"gamemod"]; |
156 int result = 0; |
133 int result = 0; |
157 int mask = 0x00000004; |
134 int mask = 0x00000004; |
158 |
135 |
331 } else { |
307 } else { |
332 DLog(@"ERROR - wrong protocol number: %d (expecting %d)", netProto, eProto); |
308 DLog(@"ERROR - wrong protocol number: %d (expecting %d)", netProto, eProto); |
333 clientQuit = YES; |
309 clientQuit = YES; |
334 } |
310 } |
335 break; |
311 break; |
336 case 'i': |
312 } |
|
313 case 'i': { |
337 if (statsArray == nil) { |
314 if (statsArray == nil) { |
338 statsArray = [[NSMutableArray alloc] initWithCapacity:10 - 2]; |
315 statsArray = [[NSMutableArray alloc] initWithCapacity:10 - 2]; |
339 NSMutableArray *ranking = [[NSMutableArray alloc] initWithCapacity:4]; |
316 NSMutableArray *ranking = [[NSMutableArray alloc] initWithCapacity:4]; |
340 [statsArray insertObject:ranking atIndex:0]; |
317 [statsArray insertObject:ranking atIndex:0]; |
341 [ranking release]; |
|
342 } |
318 } |
343 NSString *tempStr = [NSString stringWithUTF8String:&buffer[2]]; |
319 NSString *tempStr = [NSString stringWithUTF8String:&buffer[2]]; |
344 NSArray *info = [tempStr componentsSeparatedByString:@" "]; |
320 NSArray *info = [tempStr componentsSeparatedByString:@" "]; |
345 NSString *arg = [info objectAtIndex:0]; |
321 NSString *arg = [info objectAtIndex:0]; |
346 int index = [arg lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 3; |
322 int index = [arg lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 3; |
347 switch (buffer[1]) { |
323 switch (buffer[1]) { |
348 case 'r': // winning team |
324 case 'r': { // winning team |
349 [statsArray insertObject:[NSString stringWithUTF8String:&buffer[2]] atIndex:1]; |
325 [statsArray insertObject:[NSString stringWithUTF8String:&buffer[2]] atIndex:1]; |
350 break; |
326 break; |
|
327 } |
351 case 'D': // best shot |
328 case 'D': // best shot |
352 { |
329 { |
353 NSString *hogName = [NSString stringWithUTF8String:&buffer[index]]; |
330 NSString *hogName = [NSString stringWithUTF8String:&buffer[index]]; |
354 [statsArray addObject:[NSString stringWithFormat:NSLocalizedString(@"The best shot award won by %@ (with %@ points)", nil), hogName, arg]]; |
331 [statsArray addObject:[NSString stringWithFormat:NSLocalizedString(@"The best shot award won by %@ (with %@ points)", nil), hogName, arg]]; |
355 break; |
332 break; |
392 default: |
369 default: |
393 DLog(@"Unhandled stat message, see statsPage.cpp"); |
370 DLog(@"Unhandled stat message, see statsPage.cpp"); |
394 break; |
371 break; |
395 } |
372 } |
396 break; |
373 break; |
397 case 'q': |
374 } |
|
375 case 'q': { |
398 // game ended and match finished, statsArray is full of delicious statistics |
376 // game ended and match finished, statsArray is full of delicious statistics |
399 if (self.delegate != nil && [self.delegate respondsToSelector:@selector(gameEndedWithStatistics:)]) |
377 if (self.delegate != nil && [self.delegate respondsToSelector:@selector(gameEndedWithStatistics:)]) |
400 [self.delegate gameEndedWithStatistics:statsArray]; |
378 [self.delegate gameEndedWithStatistics:statsArray]; |
401 [statsArray release]; |
|
402 [HWUtils setGameStatus:gsEnded]; |
379 [HWUtils setGameStatus:gsEnded]; |
403 // closing connection here would trigger a "IPC connection lost" error, so we have to wait until recv fails |
380 // closing connection here would trigger a "IPC connection lost" error, so we have to wait until recv fails |
404 break; |
381 break; |
405 case 'Q': |
382 } |
|
383 case 'Q': { |
406 // game exited but not completed, skip this message in the savefile |
384 // game exited but not completed, skip this message in the savefile |
407 [HWUtils setGameStatus:gsInterrupted]; |
385 [HWUtils setGameStatus:gsInterrupted]; |
408 // same here, don't set clientQuit to YES |
386 // same here, don't set clientQuit to YES |
409 break; |
387 break; |
|
388 } |
410 default: |
389 default: |
411 [self dumpRawData:buffer ofSize:msgSize]; |
390 [self dumpRawData:buffer ofSize:msgSize]; |
412 break; |
391 break; |
413 } |
392 } |
414 } |
393 } |
415 DLog(@"Engine exited, ending thread"); |
394 DLog(@"Engine exited, ending thread"); |
416 |
395 |
417 [self.stream close]; |
396 [self.stream close]; |
418 [self.stream release]; |
|
419 |
397 |
420 // Close the client socket |
398 // Close the client socket |
421 [HWUtils freePort:self.enginePort]; |
399 [HWUtils freePort:self.enginePort]; |
422 SDLNet_TCP_Close(csd); |
400 SDLNet_TCP_Close(csd); |
423 SDLNet_Quit(); |
401 SDLNet_Quit(); |