1 /*
2 network_games.c
3
4 Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
5 and the "Aleph One" developers.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 This license is contained in the file "COPYING",
18 which is included with this source code; it is available online at
19 http://www.gnu.org/licenses/gpl.html
20
21 Wednesday, July 19, 1995 10:16:51 AM- rdm created.
22
23 Jul 1, 2000 (Loren Petrich):
24 Added Benad's changes
25 */
26
27 #if !defined(DISABLE_NETWORKING)
28
29 #include "cseries.h"
30 #include "map.h"
31 #include "items.h"
32 #include "lua_script.h"
33 #include "player.h"
34 #include "monsters.h"
35 #include "network.h"
36 #include "network_games.h"
37 #include "game_window.h" // for mark_player_network_stats_as_dirty
38 #include "SoundManager.h"
39
40 int32 team_netgame_parameters[NUMBER_OF_TEAM_COLORS][2];
41
42 // Benad
43 void destroy_players_ball(
44 short player_index);
45
46 #include <stdio.h>
47 #include <limits.h>
48
49 /* ----------- #defines */
50 #define SINGLE_BALL_COLOR (1)
51
52 /* ----------- enums */
53
54 /* Net game parameters */
55 enum { // for king of the hill
56 _king_of_hill_time= 0
57 };
58
59 enum { // for kill the man with the ball
60 _ball_carrier_time= 0
61 };
62
63 enum { // for offense/defense
64 _offender_time_in_base= 0, // for player->netgame_parameters
65 _defending_team= 0, // for game_information->paramters
66 _maximum_offender_time_in_base= 1 // for game_information->parameters
67 };
68
69 enum { // for rugby
70 _points_scored= 0
71 };
72
73 enum { // for tag
74 _time_spent_it= 0
75 };
76
77 enum { // for capture the flag.
78 _flag_pulls= 0, // for player->netgame_parameters
79 _winning_team= 0 // for game_information->parameters[]
80 };
81
82
83 /* ----------------- private prototypes */
84 static bool player_has_ball(short player_index, short color);
85 extern void destroy_players_ball(short player_index);
86
87 // for script controlled compass
88 extern bool use_lua_compass[MAXIMUM_NUMBER_OF_NETWORK_PLAYERS];
89 extern world_point2d lua_compass_beacons[MAXIMUM_NUMBER_OF_NETWORK_PLAYERS];
90 extern short lua_compass_states[MAXIMUM_NUMBER_OF_NETWORK_PLAYERS];
91
92 /* ------------------ code */
get_player_net_ranking(short player_index,short * kills,short * deaths,bool game_is_over)93 long get_player_net_ranking(
94 short player_index,
95 short *kills,
96 short *deaths,
97 bool game_is_over)
98 {
99 short index;
100 long total_monster_damage, monster_damage;
101 struct player_data *player= get_player_data(player_index);
102 long ranking = 0;
103
104 *kills= 0;
105 *deaths = player->monster_damage_taken.kills;
106 monster_damage= player->monster_damage_given.damage;
107
108 total_monster_damage= monster_damage;
109 for (index= 0; index<dynamic_world->player_count; ++index)
110 {
111 if (index!=player_index)
112 {
113 struct player_data *other_player= get_player_data(index);
114
115 (*kills)+= other_player->damage_taken[player_index].kills;
116 total_monster_damage+= other_player->monster_damage_given.damage;
117 }
118
119 (*deaths)+= player->damage_taken[index].kills;
120 }
121
122 switch(GET_GAME_TYPE())
123 {
124 case _game_of_kill_monsters:
125 ranking= (*kills)-(*deaths);
126 break;
127
128 case _game_of_cooperative_play:
129 ranking= total_monster_damage ? (100*monster_damage)/total_monster_damage : 0;
130 break;
131
132 case _game_of_custom:
133 switch(GetLuaScoringMode()) {
134 case _game_of_most_points:
135 case _game_of_most_time:
136 ranking = player->netgame_parameters[_points_scored];
137 break;
138 case _game_of_least_points:
139 case _game_of_least_time:
140 ranking = -player->netgame_parameters[_points_scored];
141 break;
142 }
143 break;
144
145 case _game_of_capture_the_flag:
146 ranking= player->netgame_parameters[_flag_pulls];
147 break;
148
149 case _game_of_king_of_the_hill:
150 ranking= player->netgame_parameters[_king_of_hill_time];
151 break;
152
153 case _game_of_kill_man_with_ball:
154 ranking= player->netgame_parameters[_ball_carrier_time];
155 break;
156
157 case _game_of_tag:
158 ranking= -player->netgame_parameters[_time_spent_it];
159 break;
160
161 // START Benad
162 case _game_of_defense: {
163 //ranking= (*kills)-(*deaths);
164
165 /* Bogus for now.. */
166 /*if(game_is_over && GET_GAME_PARAMETER(_winning_team)==player->team)
167 {
168 ranking += 50;
169 }
170 break;*/
171
172 //short defending_team= GET_GAME_PARAMETER(_defending_team);
173 short defending_team= 0;
174 if(player->team != defending_team)
175 {
176 ranking= player->netgame_parameters[_offender_time_in_base];
177 }
178 else
179 {
180 long biggest = 0;
181 for(player_index= 0; player_index<dynamic_world->player_count; ++player_index)
182 {
183 struct player_data *index_player= get_player_data(player_index);
184 if ((index_player->team != defending_team) &&
185 (index_player->netgame_parameters[_offender_time_in_base] > biggest))
186 {
187 biggest = index_player->netgame_parameters[_offender_time_in_base];
188 }
189 }
190 ranking= (dynamic_world->game_information.kill_limit * TICKS_PER_SECOND) - biggest; // in ticks
191 }
192 break;
193 // END Benad
194 }
195 case _game_of_rugby:
196 // Benad
197 ranking= player->netgame_parameters[_points_scored];
198 break;
199
200 default:
201 vhalt(csprintf(temporary, "What is game type %d?", GET_GAME_TYPE()));
202 break;
203 }
204
205 return ranking;
206 }
207
get_team_net_ranking(short team,short * kills,short * deaths,bool game_is_over)208 long get_team_net_ranking(short team, short *kills, short *deaths,
209 bool game_is_over)
210 {
211 long total_monster_damage, monster_damage;
212 long ranking = NONE;
213 *kills = team_damage_given[team].kills;
214 *deaths = team_damage_taken[team].kills + team_monster_damage_taken[team].kills;
215
216 total_monster_damage = 0;
217 for (int i = 0; i < NUMBER_OF_TEAM_COLORS; i++) {
218 total_monster_damage += team_monster_damage_given[i].damage;
219 }
220 monster_damage = team_monster_damage_given[team].damage;
221
222 switch(GET_GAME_TYPE())
223 {
224 case _game_of_kill_monsters:
225 ranking = (*kills)-(*deaths);
226 break;
227 case _game_of_custom:
228 switch(GetLuaScoringMode()) {
229 case _game_of_most_points:
230 case _game_of_most_time:
231 ranking = team_netgame_parameters[team][_points_scored];
232 break;
233 case _game_of_least_points:
234 case _game_of_least_time:
235 ranking = -team_netgame_parameters[team][_points_scored];
236 break;
237 }
238 break;
239 case _game_of_cooperative_play:
240 ranking = total_monster_damage ? (100*monster_damage)/total_monster_damage : 0;
241 break;
242 case _game_of_capture_the_flag:
243 ranking = team_netgame_parameters[team][_flag_pulls];
244 break;
245 case _game_of_king_of_the_hill:
246 ranking = team_netgame_parameters[team][_king_of_hill_time];
247 break;
248 case _game_of_kill_man_with_ball:
249 ranking = team_netgame_parameters[team][_ball_carrier_time];
250 break;
251 case _game_of_tag:
252 ranking = -team_netgame_parameters[team][_time_spent_it];
253 break;
254 case _game_of_defense:
255 {
256 short defending_team = 0;
257 if (team != defending_team) {
258 ranking = team_netgame_parameters[team][_offender_time_in_base];
259 } else {
260 long biggest = 0;
261 for (int i = 0; i < NUMBER_OF_TEAM_COLORS; i++) {
262 if ((i != defending_team) && (team_netgame_parameters[i][_offender_time_in_base] > biggest)) {
263 biggest = team_netgame_parameters[i][_offender_time_in_base];
264 }
265 }
266 ranking = (dynamic_world->game_information.kill_limit * TICKS_PER_SECOND) - biggest;
267 }
268 break;
269 }
270 case _game_of_rugby:
271 ranking = team_netgame_parameters[team][_points_scored];
272 break;
273 default:
274 vhalt(csprintf(temporary, "What is game type %d", GET_GAME_TYPE()));
275 break;
276 }
277
278 return ranking;
279 }
280
281
282
283
284
initialize_net_game(void)285 void initialize_net_game(
286 void)
287 {
288 for (int i = 0; i < NUMBER_OF_TEAM_COLORS; i++) {
289 team_netgame_parameters[i][0] = 0;
290 team_netgame_parameters[i][1] = 0;
291 }
292 switch (GET_GAME_TYPE())
293 {
294 case _game_of_king_of_the_hill:
295 // Benad
296 case _game_of_defense:
297 // calculate the center of the hill
298 {
299 int32 x = 0, y = 0;
300 int16 count = 0;
301 struct polygon_data *polygon;
302 short polygon_index;
303
304 for (polygon_index= 0, polygon= map_polygons; polygon_index<dynamic_world->polygon_count; ++polygon_index, ++polygon)
305 {
306 if (polygon->type==_polygon_is_hill)
307 {
308 count+= 1;
309 x+= polygon->center.x, y+= polygon->center.y;
310 }
311 }
312
313 if (count > 0) {
314 dynamic_world->game_beacon.x= static_cast<world_distance>(x/count);
315 dynamic_world->game_beacon.y= static_cast<world_distance>(y/count);
316 } else {
317 // KOTH map with no hill, nice
318 dynamic_world->game_beacon.x = 0;
319 dynamic_world->game_beacon.y = 0;
320 }
321 }
322 break;
323 // START Benad
324 case _game_of_rugby:
325 dynamic_world->game_player_index= NONE;
326 break;
327 // END Benad
328 case _game_of_kill_man_with_ball:
329 dynamic_world->game_player_index= NONE;
330 // play_local_sound(_snd_got_ball);
331 break;
332
333 case _game_of_tag:
334 dynamic_world->game_player_index= NONE; // nobody is it, yet
335 break;
336 }
337 }
338
339 #define NETWORK_COMPASS_SLOP SIXTEENTH_CIRCLE
340
get_network_compass_state(short player_index)341 short get_network_compass_state(
342 short player_index)
343 {
344 short state= _network_compass_all_off;
345 world_point2d *beacon= (world_point2d *) NULL;
346
347 if (use_lua_compass [player_index])
348 {
349 if (lua_compass_states [player_index] & _network_compass_use_beacon)
350 beacon = lua_compass_beacons + player_index;
351 else
352 state = lua_compass_states [player_index];
353 }
354 else
355 {
356 switch (GET_GAME_TYPE())
357 {
358 case _game_of_king_of_the_hill: // where�s the hill
359 // Benad
360 case _game_of_defense:
361 if (get_polygon_data(get_player_data(player_index)->supporting_polygon_index)->type==_polygon_is_hill)
362 {
363 state= _network_compass_all_on;
364 }
365 else
366 {
367 beacon= &dynamic_world->game_beacon;
368 }
369 break;
370
371 case _game_of_tag: // where�s it
372 if (dynamic_world->game_player_index==player_index)
373 {
374 state= _network_compass_all_on;
375 }
376 else
377 {
378 if (dynamic_world->game_player_index!=NONE)
379 {
380 beacon= (world_point2d *) &get_player_data(dynamic_world->game_player_index)->location;
381 }
382 }
383 break;
384 // START Benad
385 case _game_of_rugby:
386 if (player_has_ball(player_index, SINGLE_BALL_COLOR))
387 {
388 state= _network_compass_all_on;
389 }
390 else
391 {
392 if (dynamic_world->game_player_index!=NONE)
393 {
394 beacon= (world_point2d *) &get_player_data(dynamic_world->game_player_index)->location;
395 }
396 }
397 break;
398 //END Benad
399 case _game_of_kill_man_with_ball: // where�s the ball
400 if (player_has_ball(player_index, SINGLE_BALL_COLOR))
401 {
402 state= _network_compass_all_on;
403 }
404 else
405 {
406 if (dynamic_world->game_player_index!=NONE)
407 {
408 beacon= (world_point2d *) &get_player_data(dynamic_world->game_player_index)->location;
409 }
410 }
411 break;
412 }
413 }
414
415 if (beacon)
416 {
417 struct player_data *player= get_player_data(player_index);
418 struct world_point2d *origin= (world_point2d *) &player->location;
419 angle theta= NORMALIZE_ANGLE(get_object_data(player->object_index)->facing-arctangent(origin->x-beacon->x, origin->y-beacon->y));
420
421 if (theta>FULL_CIRCLE-NETWORK_COMPASS_SLOP || theta<QUARTER_CIRCLE+NETWORK_COMPASS_SLOP) state|= _network_compass_se;
422 if (theta>QUARTER_CIRCLE-NETWORK_COMPASS_SLOP && theta<HALF_CIRCLE+NETWORK_COMPASS_SLOP) state|= _network_compass_ne;
423 if (theta>HALF_CIRCLE-NETWORK_COMPASS_SLOP && theta<HALF_CIRCLE+QUARTER_CIRCLE+NETWORK_COMPASS_SLOP) state|= _network_compass_nw;
424 if (theta>HALF_CIRCLE+QUARTER_CIRCLE-NETWORK_COMPASS_SLOP || theta<NETWORK_COMPASS_SLOP) state|= _network_compass_sw;
425 }
426
427 return state;
428 }
429
430 // if false is returned, don�t attribute kill
player_killed_player(short dead_player_index,short aggressor_player_index)431 bool player_killed_player(
432 short dead_player_index,
433 short aggressor_player_index)
434 {
435 bool attribute_kill= true;
436
437 if (dynamic_world->player_count>1)
438 {
439 switch (GET_GAME_TYPE())
440 {
441 case _game_of_tag:
442 if (aggressor_player_index==dynamic_world->game_player_index || // killed by it
443 dead_player_index==aggressor_player_index || // killed themselves
444 dynamic_world->game_player_index==NONE) // died without an it
445 {
446 if (dynamic_world->game_player_index!=dead_player_index)
447 {
448 // change of �it�
449 player_data* player = get_player_data(dead_player_index);
450 play_object_sound(player->object_index, _snd_you_are_it);
451 dynamic_world->game_player_index= dead_player_index;
452 }
453 }
454 break;
455 }
456
457 if (attribute_kill)
458 {
459 switch (GET_GAME_TYPE())
460 {
461 case _game_of_kill_monsters:
462 mark_player_network_stats_as_dirty(current_player_index);
463 break;
464 }
465 }
466 }
467
468 return attribute_kill;
469 }
470
update_net_game(void)471 bool update_net_game(
472 void)
473 {
474 bool net_game_over= false;
475 short player_index;
476
477 if (dynamic_world->player_count>1)
478 {
479 switch(GET_GAME_TYPE())
480 {
481 case _game_of_kill_monsters:
482 case _game_of_cooperative_play:
483 case _game_of_custom:
484 /* These games have no housekeeping associated with them. */
485 break;
486
487 case _game_of_capture_the_flag:
488 // START Benad
489 for(player_index= 0; player_index<dynamic_world->player_count; ++player_index)
490 {
491 struct player_data *player= get_player_data(player_index);
492 struct polygon_data *polygon= get_polygon_data(player->supporting_polygon_index);
493
494 if ( (polygon->type==_polygon_is_base && polygon->permutation==player->team) ||
495 ((dynamic_world->game_information.kill_limit == 819) && (polygon->type==_polygon_is_hill)) )
496 {
497 short ball_color= find_player_ball_color(player_index);
498
499 if ((ball_color != NONE && ball_color != player->team) ||
500 (ball_color != NONE && dynamic_world->game_information.kill_limit == 819))
501 {
502 player->netgame_parameters[_flag_pulls]++;
503 team_netgame_parameters[player->team][_flag_pulls]++;
504 destroy_players_ball(player_index);
505 }
506 }
507 }
508 break;
509 // END Benad
510
511 case _game_of_king_of_the_hill:
512 for(player_index= 0; player_index<dynamic_world->player_count; ++player_index)
513 {
514 struct player_data *player= get_player_data(player_index);
515
516 if(!PLAYER_IS_DEAD(player))
517 {
518 struct polygon_data *polygon= get_polygon_data(player->supporting_polygon_index);
519
520 if(polygon->type==_polygon_is_hill)
521 {
522 player->netgame_parameters[_king_of_hill_time]++;
523 team_netgame_parameters[player->team][_king_of_hill_time]++;
524 }
525 }
526 }
527 break;
528
529 case _game_of_kill_man_with_ball:
530 dynamic_world->game_player_index= NONE;
531 for(player_index= 0; player_index<dynamic_world->player_count; ++player_index)
532 {
533 if (player_has_ball(player_index, SINGLE_BALL_COLOR))
534 {
535 struct player_data *player= get_player_data(player_index);
536
537 player->netgame_parameters[_ball_carrier_time]++;
538 team_netgame_parameters[player->team][_ball_carrier_time]++;
539 dynamic_world->game_player_index= player_index;
540
541 break;
542 }
543 }
544 break;
545
546 case _game_of_tag:
547 if (dynamic_world->game_player_index!=NONE)
548 {
549 struct player_data *player= get_player_data(dynamic_world->game_player_index);
550
551 if (!PLAYER_IS_DEAD(player) || PLAYER_IS_TOTALLY_DEAD(player))
552 {
553 player->netgame_parameters[_time_spent_it]+= 1;
554 team_netgame_parameters[player->team][_time_spent_it]+= 1;
555 }
556 }
557 break;
558
559 // START Benad
560 case _game_of_defense:
561 for(player_index= 0; player_index<dynamic_world->player_count; ++player_index)
562 {
563 struct player_data *player= get_player_data(player_index);
564 //short defending_team= GET_GAME_PARAMETER(_defending_team);
565 short defending_team= 0;
566
567 if((player->team != defending_team) && (!PLAYER_IS_DEAD(player)))
568 {
569 struct polygon_data *polygon= get_polygon_data(player->supporting_polygon_index);
570
571 /* They are in our base! */
572 if(polygon->type==_polygon_is_hill/* && polygon->permutation==defending_team*/)
573 {
574 player->netgame_parameters[_offender_time_in_base]++;
575 team_netgame_parameters[player->team][_offender_time_in_base]++;
576 /*if(player->netgame_parameters[_offender_time_in_base]>GET_GAME_PARAMETER(_maximum_offender_time_in_base))
577 {
578 dprintf("Game is over. Offender won.");
579 //��
580 dynamic_world->game_information.parameters[_winning_team]= player->team;
581 net_game_over= true;
582 }*/
583 }
584 break;
585 }
586 }
587 break;
588
589 case _game_of_rugby:
590 dynamic_world->game_player_index= NONE;
591 for(player_index= 0; player_index<dynamic_world->player_count; ++player_index)
592 {
593 struct player_data *player= get_player_data(player_index);
594 struct polygon_data *polygon= get_polygon_data(player->supporting_polygon_index);
595
596 if (player_has_ball(player_index, SINGLE_BALL_COLOR))
597 {
598 // START Benad changed oct. 1st
599 dynamic_world->game_player_index= player_index;
600 //if(polygon->type==_polygon_is_base && polygon->permutation != player->team)
601 if( ( (dynamic_world->game_information.kill_limit == 819) && (polygon->type==_polygon_is_hill)
602 && (!PLAYER_IS_DEAD(player)) ) ||
603 ( polygon->type==_polygon_is_base && polygon->permutation != player->team && (!PLAYER_IS_DEAD(player)) ) )
604 {
605 /* Goal! */
606 player->netgame_parameters[_points_scored]++;
607 team_netgame_parameters[player->team][_points_scored]++;
608
609 /* Ditch the ball.. (it will be recreated by the timer..) */
610 destroy_players_ball(player_index);
611 dynamic_world->game_player_index= NONE;
612 break; // Break out of loop; assuming there's only one ball.
613 }
614 // Can't take the ball back to you own goal, otherwise weird bugs could happen
615 // if an opponent touches the ball in your goal. Like real Rugby.
616 else if ( polygon->type==_polygon_is_base && polygon->permutation == player->team && (!PLAYER_IS_DEAD(player)))
617 {
618 /* Ditch the ball.. (it will be recreated by the timer..) */
619 destroy_players_ball(player_index);
620 dynamic_world->game_player_index= NONE;
621 break; // Break out of loop; assuming there's only one ball.
622 }
623 // END Benad changed oct. 1st
624 }
625 }
626 break;
627 // END Benad
628 default:
629 vhalt(csprintf(temporary, "What is game type: %d?", GET_GAME_TYPE()));
630 break;
631 }
632
633 if (--current_player->interface_decay<0 && GET_GAME_TYPE()!=_game_of_kill_monsters)
634 {
635 mark_player_network_stats_as_dirty(current_player_index);
636 }
637 }
638 // Benad: Warning! This is actually ignored! Instead, change game_is_over().
639 return net_game_over;
640 }
641
calculate_player_rankings(struct player_ranking_data * rankings)642 void calculate_player_rankings(
643 struct player_ranking_data *rankings)
644 {
645 struct player_ranking_data temporary_copy[MAXIMUM_NUMBER_OF_PLAYERS];
646 short player_index, count;
647
648 /* First get the stats. */
649 for(player_index= 0; player_index<dynamic_world->player_count; ++player_index)
650 {
651 short kills, deaths;
652
653 temporary_copy[player_index].player_index= player_index;
654 temporary_copy[player_index].ranking= get_player_net_ranking(player_index, &kills, &deaths,
655 false);
656 }
657
658 /* Now sort them.. */
659 count= 0;
660 while(count!=dynamic_world->player_count)
661 {
662 long highest_ranking= LONG_MIN;
663 short highest_index= NONE;
664
665 for(player_index= 0; player_index<dynamic_world->player_count; ++player_index)
666 {
667 if(temporary_copy[player_index].ranking>highest_ranking)
668 {
669 highest_index= player_index;
670 highest_ranking= temporary_copy[player_index].ranking;
671 }
672 }
673
674 assert(highest_index != NONE);
675 rankings[count++]= temporary_copy[highest_index];
676 temporary_copy[highest_index].ranking= LONG_MIN;
677 }
678 }
679
680 /* These aren't in resources for speed.... */
calculate_ranking_text(char * buffer,long ranking)681 void calculate_ranking_text(
682 char *buffer,
683 long ranking)
684 {
685 long seconds;
686
687 switch(GET_GAME_TYPE())
688 {
689 case _game_of_kill_monsters:
690 case _game_of_capture_the_flag:
691 case _game_of_rugby:
692 sprintf(buffer, "%ld", ranking);
693 break;
694
695 case _game_of_custom:
696 switch(GetLuaScoringMode()) {
697 case _game_of_most_points:
698 sprintf(buffer, "%ld", ranking);
699 break;
700 case _game_of_least_points:
701 sprintf(buffer, "%ld", -ranking);
702 break;
703 case _game_of_most_time:
704 case _game_of_least_time:
705 seconds= ABS(ranking)/TICKS_PER_SECOND;
706 sprintf(buffer, "%ld:%02ld", seconds/60, seconds%60);
707 break;
708 }
709 break;
710
711 case _game_of_cooperative_play:
712 sprintf(buffer, "%ld%%", ranking);
713 break;
714 // START Benad
715 case _game_of_king_of_the_hill:
716 case _game_of_kill_man_with_ball:
717 case _game_of_tag:
718 case _game_of_defense:
719 seconds= ABS(ranking)/TICKS_PER_SECOND;
720 sprintf(buffer, "%ld:%02ld", seconds/60, seconds%60);
721 break;
722 // END Benad
723 default:
724 vhalt(csprintf(temporary, "What is game type %d?", GET_GAME_TYPE()));
725 break;
726 }
727 }
728
729 enum {
730 strNETWORK_GAME_STRINGS= 140,
731 flagPullsFormatString= 0,
732 minutesPossessedFormatString,
733 pointsFormatString,
734 teamString,
735 timeWithBallString,
736 flagsCapturedString,
737 timeItString,
738 goalsString,
739 reignString,
740 // Benad
741 timeOnBaseString,
742 // SB
743 pointsString,
744 timeString,
745 };
746
calculate_ranking_text_for_post_game(char * buffer,long ranking)747 void calculate_ranking_text_for_post_game(
748 char *buffer,
749 long ranking)
750 {
751 long seconds;
752 char format[40];
753
754 switch(GET_GAME_TYPE())
755 {
756 case _game_of_kill_monsters:
757 case _game_of_cooperative_play:
758 break;
759
760 case _game_of_custom:
761 switch(GetLuaScoringMode()) {
762 case _game_of_most_points:
763 getcstr(format, strNETWORK_GAME_STRINGS, pointsFormatString);
764 sprintf(buffer, format, ranking);
765 break;
766 case _game_of_least_points:
767 getcstr(format, strNETWORK_GAME_STRINGS, pointsFormatString);
768 sprintf(buffer, format, -ranking);
769 break;
770 case _game_of_most_time:
771 case _game_of_least_time:
772 seconds= ABS(ranking)/TICKS_PER_SECOND;
773 getcstr(format, strNETWORK_GAME_STRINGS, minutesPossessedFormatString);
774 sprintf(buffer, format, seconds/60, seconds%60);
775 break;
776 }
777 break;
778
779 case _game_of_capture_the_flag:
780 getcstr(format, strNETWORK_GAME_STRINGS, flagPullsFormatString);
781 sprintf(buffer, format, ranking);
782 break;
783
784 case _game_of_rugby:
785 getcstr(format, strNETWORK_GAME_STRINGS, pointsFormatString);
786 sprintf(buffer, format, ranking);
787 break;
788 // START Benad
789 case _game_of_king_of_the_hill:
790 case _game_of_kill_man_with_ball:
791 case _game_of_tag:
792 case _game_of_defense:
793 seconds= ABS(ranking)/TICKS_PER_SECOND;
794 getcstr(format, strNETWORK_GAME_STRINGS, minutesPossessedFormatString);
795 sprintf(buffer, format, seconds/60, seconds%60);
796 break;
797 // END Benad
798 default:
799 vhalt(csprintf(temporary, "What is game type %d?", GET_GAME_TYPE()));
800 break;
801 }
802 }
803
get_network_score_text_for_postgame(char * buffer,bool team_mode)804 bool get_network_score_text_for_postgame(
805 char *buffer,
806 bool team_mode)
807 {
808 short string_id= NONE;
809
810 switch(GET_GAME_TYPE())
811 {
812 case _game_of_kill_monsters:
813 case _game_of_cooperative_play:
814 string_id= NONE;
815 break;
816
817 case _game_of_custom:
818 switch(GetLuaScoringMode()) {
819 case _game_of_most_points:
820 case _game_of_least_points:
821 string_id= pointsString;
822 break;
823 case _game_of_most_time:
824 case _game_of_least_time:
825 string_id= timeString;
826 break;
827 }
828 break;
829
830 case _game_of_capture_the_flag:
831 string_id= flagsCapturedString;
832 break;
833
834 case _game_of_rugby:
835 string_id= goalsString;
836 break;
837
838 case _game_of_king_of_the_hill:
839 string_id= reignString;
840 break;
841
842 case _game_of_kill_man_with_ball:
843 string_id= timeWithBallString;
844 break;
845 //START Benad
846 case _game_of_defense:
847 //dprintf("Not supported!");
848 //string_id= timeWithBallString;
849 string_id= timeOnBaseString;
850 break;
851 // END Benad
852 case _game_of_tag:
853 string_id= timeItString;
854 break;
855
856 default:
857 vhalt(csprintf(temporary, "What is game type %d?", GET_GAME_TYPE()));
858 break;
859 }
860
861 if(string_id != NONE)
862 {
863 char text[40];
864 char team[20];
865
866 if(team_mode)
867 {
868 getcstr(team, strNETWORK_GAME_STRINGS, teamString);
869 getcstr(text, strNETWORK_GAME_STRINGS, string_id);
870 sprintf(buffer, "%s %s", team, text);
871 } else {
872 getcstr(text, strNETWORK_GAME_STRINGS, string_id);
873 sprintf(buffer, "%s", text);
874 }
875 }
876
877 return (string_id!=NONE);
878 }
879
current_net_game_has_scores(void)880 bool current_net_game_has_scores(
881 void)
882 {
883 bool has_scores;
884
885 switch(GET_GAME_TYPE())
886 {
887 case _game_of_kill_monsters:
888 case _game_of_cooperative_play:
889 has_scores= false;
890 break;
891
892 case _game_of_custom:
893 case _game_of_capture_the_flag:
894 case _game_of_rugby:
895 case _game_of_king_of_the_hill:
896 case _game_of_kill_man_with_ball:
897 case _game_of_defense:
898 case _game_of_tag:
899 has_scores= true;
900 break;
901
902 default:
903 has_scores= false;
904 vhalt(csprintf(temporary, "What is game type %d?", GET_GAME_TYPE()));
905 break;
906 }
907
908 return has_scores;
909 }
910
current_game_has_balls(void)911 bool current_game_has_balls(
912 void)
913 {
914 bool has_ball;
915
916 switch(GET_GAME_TYPE())
917 {
918 case _game_of_kill_monsters:
919 case _game_of_cooperative_play:
920 case _game_of_king_of_the_hill:
921 case _game_of_defense:
922 case _game_of_tag:
923 case _game_of_custom:
924 has_ball= false;
925 break;
926
927 case _game_of_capture_the_flag:
928 case _game_of_rugby:
929 case _game_of_kill_man_with_ball:
930 has_ball= true;
931 break;
932
933 default:
934 has_ball= false;
935 vhalt(csprintf(temporary, "What is game type %d?", GET_GAME_TYPE()));
936 break;
937 }
938
939 return has_ball;
940 }
941
942 /* Note that kill limit means different things.. */
943 /* if capture the flag- the number of flag pulls */
game_is_over(void)944 bool game_is_over(
945 void)
946 {
947 bool game_over= false;
948
949 if (dynamic_world->game_information.game_time_remaining<=0)
950 {
951 game_over= true;
952 }
953 else if(GetLuaGameEndCondition() == _game_end_now_condition)
954 {
955 game_over = true;
956 }
957 else if(GetLuaGameEndCondition() == _game_no_end_condition)
958 {
959 game_over = false;
960 }
961 else if(GET_GAME_OPTIONS() & _game_has_kill_limit)
962 {
963 short player_index;
964
965 switch(GET_GAME_TYPE())
966 {
967 case _game_of_kill_monsters:
968 case _game_of_cooperative_play:
969 case _game_of_king_of_the_hill:
970 case _game_of_kill_man_with_ball:
971 case _game_of_tag:
972 /* Find out if the kill limit has been reached */
973 for(player_index= 0; player_index<dynamic_world->player_count; ++player_index)
974 {
975 struct player_data *player= get_player_data(player_index);
976
977 // make sure we subtract our suicides.
978 if (player->total_damage_given.kills-player->damage_taken[player_index].kills >= dynamic_world->game_information.kill_limit)
979 {
980 // we don't actually want the game to end right away, but give a second or
981 // two to see the player die.
982 dynamic_world->game_information.game_options &= ~_game_has_kill_limit;
983 dynamic_world->game_information.game_time_remaining= 2*TICKS_PER_SECOND;
984 break;
985 }
986 }
987 break;
988
989 case _game_of_custom: // default scoring behavior is like CTF
990 case _game_of_capture_the_flag:
991 /* Kill limit is the number of flag pulls */
992 for (int i = 0; i < NUMBER_OF_TEAM_COLORS; i++) {
993 if (team_netgame_parameters[i][_flag_pulls] >= dynamic_world->game_information.kill_limit) {
994 game_over = true;
995 break;
996 }
997 }
998 break;
999
1000 case _game_of_rugby:
1001 /* Kill limit is the number of flag pulls */
1002 for (int i = 0; i < NUMBER_OF_TEAM_COLORS; ++i)
1003 {
1004 if (team_netgame_parameters[i][_points_scored] >= dynamic_world->game_information.kill_limit)
1005 {
1006 game_over = true;
1007 break;
1008 }
1009 }
1010 break;
1011 // START Benad
1012 case _game_of_defense:
1013 for(player_index= 0; player_index<dynamic_world->player_count; ++player_index)
1014 {
1015 struct player_data *player= get_player_data(player_index);
1016 if(player->netgame_parameters[_offender_time_in_base] >
1017 (dynamic_world->game_information.kill_limit * TICKS_PER_SECOND)) // kill_limit is in seconds
1018 {
1019 //dprintf("Game is over. Offender won.");
1020 //dynamic_world->game_information.parameters[_winning_team]= player->team;
1021 game_over= true;
1022 }
1023 }
1024 break;
1025 // END Benad
1026 default:
1027 vhalt(csprintf(temporary, "What is game type %d?", GET_GAME_TYPE()));
1028 break;
1029 }
1030 }
1031
1032 return game_over;
1033 }
1034
1035 enum {
1036 joinNetworkStrings= 142,
1037 _standard_format= 0,
1038 _carnage_word,
1039 _cooperative_string,
1040 _capture_the_flag,
1041 _king_of_the_hill,
1042 _kill_the_man_with_the_ball,
1043 _defender_offender,
1044 _rugby,
1045 _tag,
1046 _custom_string
1047 };
1048
get_network_joined_message(char * buffer,short game_type)1049 void get_network_joined_message(
1050 char *buffer,
1051 short game_type)
1052 {
1053 short format_word= NONE; /* means cooperative */
1054
1055 switch(game_type)
1056 {
1057 case _game_of_kill_monsters: format_word= _carnage_word; break;
1058 case _game_of_custom:
1059 case _game_of_cooperative_play: format_word= NONE; break;
1060 case _game_of_capture_the_flag: format_word= _capture_the_flag; break;
1061 case _game_of_rugby: format_word= _rugby; break;
1062 case _game_of_king_of_the_hill: format_word= _king_of_the_hill; break;
1063 case _game_of_kill_man_with_ball: format_word= _kill_the_man_with_the_ball; break;
1064 case _game_of_defense: format_word= _defender_offender; break;
1065 case _game_of_tag: format_word= _tag; break;
1066 default:
1067 vhalt(csprintf(temporary, "What is game type %d?", GET_GAME_TYPE()));
1068 break;
1069 }
1070
1071 if(format_word != NONE)
1072 {
1073 char format_string[128];
1074 char game_type_word[50];
1075
1076 getcstr(format_string, joinNetworkStrings, _standard_format);
1077 getcstr(game_type_word, joinNetworkStrings, format_word);
1078 sprintf(buffer, format_string, game_type_word);
1079 } else {
1080 if(game_type == _game_of_cooperative_play)
1081 getcstr(buffer, joinNetworkStrings, _cooperative_string);
1082 else
1083 getcstr(buffer, joinNetworkStrings, _custom_string);
1084 }
1085 }
1086
1087 /* This function is used only at network.. */
get_entry_point_flags_for_game_type(size_t game_type)1088 long get_entry_point_flags_for_game_type(
1089 size_t game_type)
1090 {
1091 long entry_flags = 0;
1092
1093 switch(game_type)
1094 {
1095 case _game_of_kill_man_with_ball:
1096 entry_flags= _kill_the_man_with_the_ball_entry_point;
1097 break;
1098
1099 case _game_of_kill_monsters:
1100 case _game_of_tag:
1101 case _game_of_custom:
1102 entry_flags= _multiplayer_carnage_entry_point;
1103 break;
1104
1105 case _game_of_cooperative_play:
1106 entry_flags= _multiplayer_cooperative_entry_point;
1107 break;
1108
1109 case _game_of_king_of_the_hill:
1110 entry_flags= _king_of_hill_entry_point;
1111 break;
1112 // START Benad
1113 case _game_of_rugby:
1114 entry_flags= _rugby_entry_point;
1115 break;
1116 case _game_of_capture_the_flag:
1117 entry_flags= _capture_the_flag_entry_point;
1118 break;
1119 case _game_of_defense:
1120 entry_flags= _defense_entry_point;
1121 break;
1122 // END Benad
1123 default:
1124 vhalt(csprintf(temporary, "What is game type %zu?", game_type));
1125 break;
1126 }
1127
1128 return entry_flags;
1129 }
1130
1131 /* ------------------ local code */
player_has_ball(short player_index,short color)1132 static bool player_has_ball(
1133 short player_index,
1134 short color)
1135 {
1136 struct player_data *player= get_player_data(player_index);
1137 bool has_ball= false;
1138
1139 if(player->items[BALL_ITEM_BASE+color]>0)
1140 {
1141 has_ball= true;
1142 }
1143
1144 return has_ball;
1145 }
1146
1147 // START Benad
1148 // This function moved to weapons.c
1149 /*
1150 static void destroy_players_ball(
1151 short player_index)
1152 {
1153 short color, item_type;
1154 struct player_data *player= get_player_data(player_index);
1155
1156 color= find_player_ball_color(player_index);
1157 assert(color != NONE);
1158
1159 *//* Get rid of it. *//*
1160 item_type= BALL_ITEM_BASE+color;
1161 player->items[item_type]= NONE;
1162
1163 *//* Destroy the object (placement will recreate it..) *//*
1164 object_was_just_destroyed(_object_is_item, item_type);
1165
1166 *//* Mark the player inventory as dirty.. *//*
1167 mark_player_inventory_as_dirty(player_index, _i_knife);
1168 }
1169 */
1170 // END Benad
1171
1172 #endif // !defined(DISABLE_NETWORKING)
1173
1174