Files
astromaddie--HaloCE-VR/source/game/game_engine.c
T
2026-10-01 09:12:07 +13:00

8082 lines
215 KiB
C

/*
GAME_ENGINE.C
symbols in this file:
00096780 0020:
_game_globals_get_weapon (0000)
000967A0 0070:
_game_engine_get_team_score (0000)
00096810 0020:
_linear_to_non_linear_alpha (0000)
00096830 0020:
_game_engine_dispose (0000)
00096850 0040:
_initialize_player_multiplayer_data (0000)
00096890 0120:
_game_engine_build_lighting (0000)
000969B0 0020:
_game_engine_dispose_from_old_map (0000)
000969D0 0020:
_game_engine_game_ending (0000)
000969F0 0020:
_game_engine_game_starting (0000)
00096A10 0040:
_players_in_game (0000)
00096A50 0020:
_game_engine_statistics_append (0000)
00096A70 0020:
_game_engine_handle_client_message (0000)
00096A90 0020:
_game_engine_handle_server_message (0000)
00096AB0 0030:
_sort_statistic_buffer (0000)
00096AE0 0050:
_sort_statistic_buffer_ranking (0000)
00096B30 0010:
_is_place_tied (0000)
00096B40 0010:
_place_get_position (0000)
00096B50 0050:
_get_place_string (0000)
00096BA0 0070:
_drawline (0000)
00096C10 0020:
_get_selected_color (0000)
00096C30 0050:
_get_postgame_hilite_colors (0000)
00096C80 0060:
_find_closest_player_callback (0000)
00096CE0 0020:
_game_engine_post_rasterize_objects (0000)
00096D00 0030:
_can_delete_item (0000)
00096D30 0100:
_game_engine_update_purge (0000)
00096E30 00a0:
_update_weapon_inventory (0000)
00096ED0 0150:
_game_engine_update_weapons (0000)
00097020 00b0:
_item_collection_get_total (0000)
000970D0 0050:
_game_engine_load_stage (0000)
00097120 0030:
_game_engine_playlist_begin (0000)
00097150 0060:
_game_engine_get_current_stage (0000)
000971B0 0030:
_game_engine_end_game (0000)
000971E0 0020:
_game_engine_allow_pick_up (0000)
00097200 0050:
_game_engine_player_damaged_player (0000)
00097250 00a0:
_game_engine_player_is_odd_man_out (0000)
000972F0 0040:
_game_engine_player_is_out_of_lives (0000)
00097330 0100:
_game_engine_should_spawn_player (0000)
00097430 0070:
_game_engine_player_get_team_index (0000)
000974A0 0040:
_game_engine_prespawn_player_update (0000)
000974E0 0010:
_game_engine_running (0000)
000974F0 0020:
_game_engine_can_score (0000)
00097510 0020:
_game_engine_force_single_screen (0000)
00097530 0030:
_get_blink_alpha (0000)
00097560 0010:
_game_engine_press_start_to_begin (0000)
00097570 00f0:
_nearby_vehicle (0000)
00097660 0100:
_game_engine_rasterize_message (0000)
00097760 00e0:
_game_engine_picking_up (0000)
00097840 0080:
_goal_matches_player (0000)
000978C0 00a0:
_game_engine_player_get_custom_motion_sensor_positions (0000)
00097960 0030:
_get_flag_definition_index (0000)
00097990 0030:
_get_ball_definition_index (0000)
000979C0 0040:
_game_engine_switch_to_postgame (0000)
00097A00 0010:
_game_engine_get_variant (0000)
00097A10 0020:
_game_engine_get_goal_in_use (0000)
00097A30 0060:
_game_engine_get_goal_position (0000)
00097A90 0080:
_game_engine_set_goal_position (0000)
00097B10 0020:
_game_engine_clear_goal_position (0000)
00097B30 00d0:
_game_engine_render_nav_points (0000)
00097C00 0020:
_game_engine_infinite_grenades_internal (0000)
00097C20 0030:
_game_engine_infinite_grenades (0000)
00097C50 0020:
_game_engine_has_teams (0000)
00097C70 0030:
_game_engine_display_team_indicators (0000)
00097CA0 0030:
_game_engine_has_shield (0000)
00097CD0 0060:
_weapon_definition_index_to_list_index (0000)
00097D30 0030:
_list_index_to_weapon_definition_index (0000)
00097D60 00c0:
_game_engine_remap_vehicle (0000)
00097E20 0190:
_game_engine_remap_weapon (0000)
00097FB0 0070:
_game_engine_man_out (0000)
00098020 0030:
_game_engine_state_message (0000)
00098050 0090:
_game_engine_player_get_change_color (0000)
000980E0 0070:
_game_engine_player_has_flag (0000)
00098150 0050:
_game_engine_player_depower_active_camo (0000)
000981A0 00e0:
_get_place_name (0000)
00098280 0170:
_game_engine_get_place (0000)
000983F0 0040:
_game_engine_hud_draw_motion_sensor (0000)
00098430 0020:
_game_engine_test_flag (0000)
00098450 0020:
_game_engine_test_trait (0000)
00098470 00a0:
_netgame_flag_verify_no_team_duplicates (0000)
00098510 0070:
_netgame_flag_verify_team_range (0000)
00098580 0070:
_game_engine_playlist_next (0000)
000985F0 0090:
_build_game_variant_slayer (0000)
00098680 0090:
_build_game_variant_slayer_pro (0000)
00098710 0090:
_build_game_variant_elimination (0000)
000987A0 0090:
_build_game_variant_phantoms (0000)
00098830 0090:
_build_game_variant_endurance (0000)
000988C0 0090:
_build_game_variant_rockets (0000)
00098950 0090:
_build_game_variant_snipers (0000)
000989E0 0090:
_build_game_variant_team_slayer (0000)
00098A70 0090:
_build_game_variant_oddball (0000)
00098B00 0090:
_build_game_variant_team_oddball (0000)
00098B90 0090:
_build_game_variant_reverse_tag (0000)
00098C20 00a0:
_build_game_variant_accumulation (0000)
00098CC0 00a0:
_build_game_variant_juggernaut (0000)
00098D60 00a0:
_build_game_variant_stalker (0000)
00098E00 0080:
_build_game_variant_king (0000)
00098E80 0090:
_build_game_variant_king_pro (0000)
00098F10 0080:
_build_game_variant_crazy_king (0000)
00098F90 0090:
_build_game_variant_team_king (0000)
00099020 0090:
_build_game_variant_ctf (0000)
000990B0 0090:
_build_game_variant_ctf_pro (0000)
00099140 0090:
_build_game_variant_invasion (0000)
000991D0 0090:
_build_game_variant_iron_ctf (0000)
00099260 0090:
_build_game_variant_race (0000)
000992F0 0090:
_build_game_variant_rally (0000)
00099380 0090:
_build_game_variant_team_race (0000)
00099410 0090:
_build_game_variant_team_rally (0000)
000994A0 0030:
_game_engine_override_map_name (0000)
000994D0 0020:
_game_engine_override_game_variant (0000)
000994F0 01a0:
_rasterize_in_game_score_draw_line (0000)
00099690 0060:
_game_engine_hud_draw_messages (0000)
000996F0 0080:
_game_engine_player_has_stealth_weapon (0000)
00099770 0110:
_game_engine_weapon_fired (0000)
00099880 0030:
_test_any_gamepad_button (0000)
000998B0 00c0:
_ticks_to_unicode_time_string (0000)
00099970 0060:
_game_engine_flag_reset (0000)
000999D0 01b0:
_game_engine_variant_cleanup (0000)
00099B80 0010:
_game_engine_allow_pause (0000)
00099B90 0270:
_game_engine_predict_resources (0000)
00099E00 0020:
_game_engine_draw_object_in_motion_sensor (0000)
00099E20 0020:
_game_engine_allow_dynamic_lighting (0000)
00099E40 0020:
_game_engine_allow_integrated_lights (0000)
00099E60 0030:
_game_engine_force_autopickup (0000)
00099E90 0060:
_game_engine_initialize (0000)
00099EF0 0100:
_multiple_teams_alive (0000)
00099FF0 00f0:
_team_has_players (0000)
0009A0E0 0020:
_game_engine_should_end_game (0000)
0009A100 0080:
_adjust_score_for_ranking (0000)
0009A180 0230:
_populate_statistic_buffer (0000)
0009A3B0 0080:
_game_engine_get_player_place (0000)
0009A430 0060:
_postgame_statistic_get_rating (0000)
0009A490 01f0:
_select_players_to_display (0000)
0009A680 01c0:
_find_closest_player_index (0000)
0009A840 0100:
_internal_rasterize_target_name (0000)
0009A940 0920:
_internal_rasterize_score (0000)
0009B260 0080:
_random_item (0000)
0009B2E0 0020:
_game_engine_get_type (0000)
0009B300 00a0:
_match_game_type (0000)
0009B3A0 0150:
_game_engine_update_item_spawn (0000)
0009B4F0 0070:
_game_engine_update_player_no_shield (0000)
0009B560 0060:
_game_engine_update_player_always_invis (0000)
0009B5C0 00e0:
_game_engine_update_non_deterministic (0000)
0009B6A0 0040:
_multiplayer_message_internal (0000)
0009B6E0 0090:
_multiplayer_message (0000)
0009B770 0010:
_game_show_score_one_player (0000)
0009B780 0060:
_game_show_score_team (0000)
0009B7E0 00d0:
_game_show_score_you_ally_enemy (0000)
0009B8B0 0080:
_game_show_score_extended (0000)
0009B930 0020:
_game_show_score (0000)
0009B950 0110:
_find_netgame_flags (0000)
0009BA60 0040:
_find_netgame_flag (0000)
0009BAA0 0130:
_handle_custom_starting_equipment (0000)
0009BBD0 0150:
_game_engine_postspawn_player_update (0000)
0009BD20 00d0:
_game_engine_get_damage_multiplier (0000)
0009BDF0 03e0:
_game_engine_update_teleporter (0000)
0009C1D0 0170:
_game_engine_get_distance_rating_for_spawn (0000)
0009C340 0120:
_game_engine_get_friendly_bonus (0000)
0009C460 00b0:
_default_starting_location_rate_function (0000)
0009C510 0060:
_game_engine_get_starting_location_rating (0000)
0009C570 0220:
_game_engine_get_variant_by_name (0000)
0009C790 0130:
_game_engine_remap_equipment (0000)
0009C8C0 0070:
_game_engine_remap_object_definition (0000)
0009C930 0140:
_game_engine_get_state_message (0000)
0009CA70 00c0:
_game_engine_did_player_win_default (0000)
0009CB30 0030:
_game_engine_did_player_win (0000)
0009CB60 0080:
_game_engine_did_team_win (0000)
0009CBE0 0040:
_netgame_flag_verify_team_exists (0000)
0009CC20 0060:
_netgame_verify_spawn_points (0000)
0009CC80 0070:
_netgame_verify_equipment (0000)
0009CCF0 0280:
_game_engine_verify_current_map (0000)
0009CF70 0010:
_game_engine_playlist_initialize (0000)
0009CF80 0080:
_game_engine_initialize_for_new_map (0000)
0009D000 0140:
_game_engine_player_added (0000)
0009D140 0480:
_game_engine_generate_title_string (0000)
0009D5C0 09e0:
_game_engine_post_rasterize_post_game (0000)
0009DFA0 02f0:
_game_engine_update (0000)
0009E290 0340:
_game_engine_player_killed (0000)
0009E5D0 00a0:
_game_engine_nonplayer_post_rasterize (0000)
0009E670 0350:
_game_engine_rasterize_in_game_score (0000)
0009E9C0 0140:
_game_engine_post_rasterize_in_game (0000)
0009EB00 0060:
_game_engine_post_rasterize (0000)
0025B190 0008:
__real@3ffe666660000000 (0000)
0025B198 0002:
??_C@_11LOCGONAA@?$AA?$AA@ (0000)
0025B19C 0019:
??_C@_0BJ@IAIEOKNM@ui?2multiplayer_game_text?$AA@ (0000)
0025B1B8 001d:
??_C@_0BN@BLHEDFPC@weapon_is_flag?$CIweapon_index?$CJ?$AA@ (0000)
0025B1D8 0022:
??_C@_0CC@HKAICMNO@c?3?2halo?2SOURCE?2game?2game_engine?4@ (0000)
0025B1FC 003c:
??_C@_0DM@INOFLLBD@?$CIitem?9?$DOobject?4scale?5?$DO?$DN?50?45f?$CJ?5?$CG?$CG?5@ (0000)
0025B238 0014:
??_C@_0BE@PEGHDBAP@NULL?5?$CB?$DN?5game_engine?$AA@ (0000)
0025B24C 0014:
??_C@_0BE@CKCLKIJA@variant?5?$CG?$CG?5map_name?$AA@ (0000)
0025B260 001a:
??_C@_0BK@EKPIBKAB@dead_player_index?5?$CB?$DN?5NONE?$AA@ (0000)
0025B27C 000c:
??_C@_0M@CLNODINK@game_engine?$AA@ (0000)
0025B288 0008:
__real@3f53104b57cf969e (0000)
0025B290 0007:
??_C@_06IEOJBDIK@object?$AA@ (0000)
0025B298 0097:
??_C@_0JH@PNHLNBOL@?$CBallow_pick_up?5?$HM?$HM?5?$CBTEST_FLAG?$CIwea@ (0000)
0025B330 001a:
??_C@_0BK@LOIEOAAE@global_goal?$FLindex?$FN?4in_use?$AA@ (0000)
0025B34C 0004:
__real@3f2147ae (0000)
0025B350 0015:
??_C@_0BF@MOJDLNAG@NONE?5?$CB?$DN?5lookup_index?$AA@ (0000)
0025B368 001d:
??_C@_0BN@OIBHHACP@place?4place?5?$DM?5maximum_places?$AA@ (0000)
0025B388 002c:
??_C@_0CM@IEEKPKHB@?$CI?$CBall_tied?5?$HM?$HM?5?$CItied?$CJ?$CJ?5?$HM?$HM?5?$CI1?5?$DN?$DN?5g@ (0000)
0025B3B4 001e:
??_C@_0BO@HPNHAHOG@levels?2test?2carousel?2carousel?$AA@ (0000)
0025B3D4 000c:
??_C@_1M@CDCAHPKB@?$AA?$CF?$AAs?$AA?3?$AA?$CF?$AAs?$AA?$AA@ (0000)
0025B3E0 0008:
??_C@_17PMDFIHDK@?$AA0?$AA?$CF?$AAd?$AA?$AA@ (0000)
0025B3E8 0006:
??_C@_15KNBIKKIN@?$AA?$CF?$AAd?$AA?$AA@ (0000)
0025B3F0 0004:
??_C@_13HOIJIPNN@?$AA?5?$AA?$AA@ (0000)
0025B3F8 0046:
??_C@_0EG@GDPJDEHO@NETGAME?5CODE?5FAILURE?3?5game_engin@ (0000)
0025B440 001b:
??_C@_0BL@FBPHGMEB@player?9?$DOteam_index?5?$CB?$DN?5NONE?$AA@ (0000)
0025B45C 0013:
??_C@_0BD@JDPLED@player_index?$CB?$DNNONE?$AA@ (0000)
0025B470 002b:
??_C@_0CL@DLMKKJM@player_count?5?$DM?5MULTIPLAYER_MAXIM@ (0000)
0025B49C 0022:
??_C@_0CC@FPLNHLNP@place?$DMMULTIPLAYER_MAXIMUM_PLAYER@ (0000)
0025B4C0 0013:
??_C@_0BD@EGHPGJBP@found?5local?5player?$AA@ (0000)
0025B4D4 001d:
??_C@_0BN@LMCPNAFN@player_count?$DN?$CFd?0?5maxcount?$DN?$CFd?$AA@ (0000)
0025B4F8 0008:
__real@3fc0bf25a0000000 (0000)
0025B500 0015:
??_C@_0BF@IHIEPAI@NONE?5?$CB?$DN?5player_index?$AA@ (0000)
0025B518 0016:
??_C@_0BG@OJNPNGFL@failed?5to?5teleport?5?$CFd?$AA@ (0000)
0025B530 0008:
__real@3fe3333340000000 (0000)
0025B538 000a:
??_C@_09DOOCKEDN@team_king?$AA@ (0000)
0025B544 0005:
??_C@_04PJOEONHN@king?$AA@ (0000)
0025B54C 0008:
??_C@_07LIOCHKOH@ironctf?$AA@ (0000)
0025B554 0004:
??_C@_03JHHHHEKD@ctf?$AA@ (0000)
0025B558 0008:
??_C@_07JHGHBFJP@oddball?$AA@ (0000)
0025B560 000d:
??_C@_0N@JBNPINGA@accumulation?$AA@ (0000)
0025B570 000d:
??_C@_0N@CPCFMJOB@team_oddball?$AA@ (0000)
0025B580 0008:
??_C@_07IAHNGGND@stalker?$AA@ (0000)
0025B588 000c:
??_C@_0M@MLMHALFL@elimination?$AA@ (0000)
0025B594 000c:
??_C@_0M@NOCMPHHF@team_slayer?$AA@ (0000)
0025B5A0 0007:
??_C@_06CBFFIGEC@slayer?$AA@ (0000)
0025B5A8 0006:
??_C@_05GCEFBECL@rally?$AA@ (0000)
0025B5B0 000a:
??_C@_09KMEIIIPA@team_race?$AA@ (0000)
0025B5BC 0005:
??_C@_04GLEOMBLA@race?$AA@ (0000)
0025B5C4 0004:
__real@3f0ccccd (0000)
0025B5C8 003b:
??_C@_0DL@MBPNEOKF@NETGAME?5MAP?5FAILURE?3?5failed?5to?5f@ (0000)
0025B604 003b:
??_C@_0DL@FDFHGCGI@NETGAME?5MAP?5FAILURE?3?5failed?5to?5f@ (0000)
0025B640 003e:
??_C@_0DO@GDPJBCBM@NETGAME?5MAP?5FAILURE?3?5failed?5to?5f@ (0000)
0025B680 003d:
??_C@_0DN@GLOHFEFE@NETGAME?5MAP?5FAILURE?3?5failed?5to?5f@ (0000)
0025B6C0 003a:
??_C@_0DK@COLEDOMN@NETGAME?5MAP?5FAILURE?3?5failed?5to?5f@ (0000)
0025B700 0047:
??_C@_0EH@GJGBEMDH@NETGAME?5MAP?5FAILURE?3?5failed?5to?5f@ (0000)
0025B748 0047:
??_C@_0EH@BMGHBGKH@NETGAME?5MAP?5FAILURE?3?5failed?5to?5f@ (0000)
0025B790 004a:
??_C@_0EK@DHDLIGMN@NETGAME?5MAP?5FAILURE?3?5failed?5to?5f@ (0000)
0025B7E0 0049:
??_C@_0EJ@FACIONE@NETGAME?5MAP?5FAILURE?3?5failed?5to?5f@ (0000)
0025B830 004f:
??_C@_0EP@CGHPHLAM@NETGAME?5MAP?5FAILURE?3?5failed?5to?5f@ (0000)
0025B880 004f:
??_C@_0EP@MJLNBADC@NETGAME?5MAP?5FAILURE?3?5failed?5to?5f@ (0000)
0025B8D0 0039:
??_C@_0DJ@MPJKFIIJ@NETGAME?5MAP?5FAILURE?3?5duplicate?5r@ (0000)
0025B90C 0031:
??_C@_0DB@KDFIELID@NETGAME?5MAP?5FAILURE?3?5missing?5rac@ (0000)
0025B940 0034:
??_C@_0DE@KIBANADL@NETGAME?5MAP?5FAILURE?3?5missing?5odd@ (0000)
0025B974 0031:
??_C@_0DB@IKODHNKI@NETGAME?5MAP?5FAILURE?3?5missing?5hil@ (0000)
0025B9A8 0035:
??_C@_0DF@EHBELDKM@NETGAME?5MAP?5FAILURE?3?5ctf?5flag?5ou@ (0000)
0025B9E0 0032:
??_C@_0DC@DCAAPLNK@NETGAME?5MAP?5FAILURE?3?5duplicate?5c@ (0000)
0025BA14 0030:
??_C@_0DA@LKKJMHEH@NETGAME?5MAP?5FAILURE?3?5missing?5ctf@ (0000)
0025BA48 0057:
??_C@_0FH@ODDMDCIB@failed?5to?5initialize?5custome?5gam@ (0000)
0025BAA0 000d:
??_C@_0N@MABFIMPF@title_string?$AA@ (0000)
0025BAB0 001e:
??_C@_1BO@NNCACCCJ@?$AA?5?$AA?7?$AA?5?$AA?7?$AA?5?$AA?7?$AA?5?$AA?7?$AA?5?$AA?7?$AA?5?$AA?7?$AA?$CF?$AAd?$AA?$AA@ (0000)
0025BAD0 001a:
??_C@_1BK@JPAKMPFP@?$AA?5?$AA?7?$AA?5?$AA?7?$AA?5?$AA?7?$AA?5?$AA?7?$AA?5?$AA?7?$AA?$CF?$AAd?$AA?$AA@ (0000)
0025BAEC 0016:
??_C@_1BG@EEDCCJKF@?$AA?5?$AA?7?$AA?5?$AA?7?$AA?5?$AA?7?$AA?5?$AA?7?$AA?$CF?$AAd?$AA?$AA@ (0000)
0025BB04 0012:
??_C@_1BC@DGONEHBJ@?$AA?5?$AA?7?$AA?5?$AA?7?$AA?5?$AA?7?$AA?$CF?$AAs?$AA?$AA@ (0000)
0025BB18 000e:
??_C@_1O@HAEHHN@?$AA?5?$AA?7?$AA?5?$AA?7?$AA?$CF?$AAs?$AA?$AA@ (0000)
0025BB28 000a:
??_C@_19GCIMBEIF@?$AA?5?$AA?7?$AA?$CF?$AAs?$AA?$AA@ (0000)
0025BB34 0026:
??_C@_1CG@MDCDIADO@?$AA?7?$AA?$CF?$AAs?$AA?7?$AA?$CF?$AAs?$AA?7?$AA?$CF?$AAs?$AA?7?$AA?$CF?$AAs?$AA?7?$AA?$CF?$AAs?$AA?7?$AA?$CF?$AAs?$AA?$AA@ (0000)
0025BB5C 0012:
??_C@_0BC@FNEEDLLE@ambient_computers?$AA@ (0000)
0025BB70 0012:
??_C@_0BC@GOFPLFEH@ambient_machinery?$AA@ (0000)
0025BB84 000f:
??_C@_0P@PLBDAHNN@ambient_nature?$AA@ (0000)
0025BB94 0014:
??_C@_1BE@EFJKLKFF@?$AA?7?$AA?$CF?$AAs?$AA?7?$AA?$CF?$AAs?$AA?7?$AA?$CF?$AAs?$AA?$AA@ (0000)
0025BBA8 001b:
??_C@_0BL@NPJONDMM@NONE?5?$CB?$DN?5local_player_index?$AA@ (0000)
002DE3E0 0020:
_debug_player_color (0000)
0043E498 047c:
_global_goal (0000)
_global_variant (0400)
_game_engine (0468)
_global_autogenerate_list (0474)
_global_autogenerate_count (0478)
*/
/* ---------- headers */
#include "cseries.h"
#include "cseries_windows.h"
#include "errors.h"
#include "aim_assist.h"
#include "game_engine.h"
#include "game_engine_list.h"
#include "game_engine_place.h"
#include "bitmaps/bitmap_group.h"
#include "bitmaps/bitmap_group_lookup.h"
#include "effects/player_effects.h"
#include "game_allegiance.h"
#include "game_globals.h"
#include "interface/interface.h"
#include "interface/hud.h"
#include "interface/hud_definitions.h"
#include "interface/hud_messaging.h"
#include "interface/player_ui.h"
#include "interface/terminal.h"
#include "interface/ui_widget.h"
#include "input/input.h"
#include "items/equipment_definitions.h"
#include "items/item_definitions.h"
#include "items/weapon_definitions.h"
#include "items/weapons.h"
#include "main/console.h"
#include "main/main.h"
#include "math/integer_math.h"
#include "networking/network_game_globals.h"
#include "networking/network_server_manager.h"
#include "objects.h"
#include "objects/damage_effect_definitions.h"
#include "physics/collision_features.h"
#include "player_rumble.h"
#include "players.h"
#include "players_runtime.h"
#include "rasterizer/rasterizer.h"
#include "rasterizer/rasterizer_console_vars.h"
#include "render/render.h"
#include "saved games/player_profile.h"
#include "scenario/scenario.h"
#include "scenario/scenario_definitions.h"
#include "sound/sound_classes.h"
#include "text/draw_string.h"
#include "text/font_group.h"
#include "text/text_group.h"
#include "text/unicode.h"
#include "units/bipeds.h"
#include "units/units.h"
/* network_game_globals.c's */
boolean network_game_distributed_client(void);
/* port/linux/game/network_distributed.c's */
void network_distributed_player_killed(long *killing_player_index, long *killing_object_index,
long dead_player_index, boolean *friendly_fire);
/* port/linux/game/network_damage.c's */
boolean network_damage_killer_score(long player_index, long *score);
/* ---------- constants */
enum
{
/* port: the native builds' session limit (halo_port_limits.h) */
MULTIPLAYER_MAXIMUM_PLAYERS = HALO_PORT_MAXIMUM_NETWORK_PLAYERS,
/* ui\multiplayer_game_text only has strings for the first 16 places */
NUMBER_OF_PLACE_STRINGS = 16,
};
/* scenario_starting_equipment.flags (HCEX names) */
enum
{
_netgame_starting_equipment_flag_no_grenades_bit = 0,
_netgame_starting_equipment_flag_plasma_greandes_bit, /* (sic) HCEX spelling */
};
/* game_engine_globals.flags and universal_variant.flags bits used only by this file
(the lower bits are declared with their siblings in game_engine.h) */
enum
{
_game_engine_9_or_more_players_bit = 3,
_game_engine_game_over_sound_disabled_bit,
};
enum
{
_game_variant_generic_starting_equipment_bit = 5,
};
enum
{
_game_engine_all = 12,
_game_engine_all_non_team,
_game_engine_all_normal,
};
enum
{
_multiplayer_sound_game_over = 0x1,
_multiplayer_sound_double_kill = 0xE,
_multiplayer_sound_triple_kill,
_multiplayer_sound_killtacular_kill,
_multiplayer_sound_running_riot,
_multiplayer_sound_killing_spree,
_multiplayer_sound_teleporter_activate = 0x1B,
_multiplayer_sound_countdown_for_respawn = 0x1D,
_multiplayer_sound_respawn = 0x1F,
};
enum game_engine_mode
{
game_engine_mode_active = 0,
game_engine_mode_postgame_delay,
game_engine_mode_postgame_rasterize_delay,
game_engine_mode_postgame_rasterize,
};
enum postgame_statistic
{
_postgame_statistic_ranking = 0,
_postgame_statistic_score,
_postgame_statistic_kills,
_postgame_statistic_assists,
_postgame_statistic_deaths,
NUMBER_OF_POSTGAME_STATISTICS,
};
enum game_engine_weapons
{
_game_engine_weapons_normal = 0,
_game_engine_weapons_pistols,
_game_engine_weapons_assault_rifles,
_game_engine_weapons_plasma_weapons,
_game_engine_weapons_sniping,
_game_engine_weapons_no_sniping,
_game_engine_weapons_rocket_launchers,
_game_engine_weapons_shotguns,
_game_engine_weapons_short_range,
_game_engine_weapons_human,
_game_engine_weapons_no_grenades,
NUMBER_OF_GAME_ENGINE_WEAPON_SETS,
};
enum goal_radar
{
_radar_motion_tracker = 0,
_radar_nav_point,
_radar_none,
};
enum game_engine_vehicles
{
_game_engine_vehicles_default = 0,
_game_engine_vehicles_none,
_game_engine_vehicles_warthog,
_game_engine_vehicles_ghost,
_game_engine_vehicles_tank,
NUMBER_OF_GAME_ENGINE_VEHICLE_SETS,
};
enum
{
_weapon_list_assault_rifle = 0,
_weapon_list_flamethrower,
_weapon_list_gravity_rifle,
_weapon_list_needler,
_weapon_list_pistol,
_weapon_list_plasma_pistol,
_weapon_list_plasma_rifle,
_weapon_list_rocket_launcher,
_weapon_list_shotgun,
_weapon_list_sniper_rifle,
_weapon_list_ball,
_weapon_list_flag,
_weapon_list_frag_grenade,
_weapon_list_plasma_grenade,
};
/* ---------- macros */
#define hud_globals_definition_get(index) \
((struct hud_globals_definition *)tag_get('hudg', (index)))
#define item_collection_definition_get(index) ((struct item_collection_definition *)tag_get(ITEM_COLLECTION_DEFINITION_TAG, index))
/* ---------- structures */
struct netgame_goal
{
real_point3d position;
boolean in_use;
long player_index;
short team_index;
long ignore_player_index;
short nav_index;
};
struct game_engine_globals
{
unsigned long flags;
long next_team_index;
real postgame_timer;
real postgame_progress;
long postgame_state;
real hud_message_timers[MAXIMUM_LOCAL_PLAYERS];
};
struct game_engine_stage
{
char map_name[64];
struct game_variant variant;
};
struct statistic_buffer
{
long player_index;
long score;
long custom;
long kills;
long deaths;
long assists;
long place;
};
typedef char verify_statistic_buffer_size[
sizeof(struct statistic_buffer) == 0x1C ? 1 : -1];
typedef char verify_netgame_goal_size[sizeof(struct netgame_goal) == 0x20 ? 1 : -1];
typedef char verify_game_engine_globals_postgame_timer_offset[
offsetof(struct game_engine_globals, postgame_timer) == 0x8 ? 1 : -1];
typedef char verify_game_engine_globals_next_team_index_offset[
offsetof(struct game_engine_globals, next_team_index) == 0x4 ? 1 : -1];
typedef char verify_game_engine_globals_postgame_progress_offset[
offsetof(struct game_engine_globals, postgame_progress) == 0xC ? 1 : -1];
typedef char verify_game_engine_globals_postgame_state_offset[
offsetof(struct game_engine_globals, postgame_state) == 0x10 ? 1 : -1];
typedef char verify_game_engine_globals_hud_message_timers_offset[
offsetof(struct game_engine_globals, hud_message_timers) == 0x14 ? 1 : -1];
typedef char verify_game_engine_globals_size[
sizeof(struct game_engine_globals) == 0x24 ? 1 : -1];
typedef char verify_game_engine_stage_variant_offset[
offsetof(struct game_engine_stage, variant) == 0x40 ? 1 : -1];
typedef char verify_game_engine_stage_size[
sizeof(struct game_engine_stage) == 0xA8 ? 1 : -1];
/* ---------- prototypes */
void game_engine_playlist_next(
long parameter0,
long parameter1,
long playlist_type);
static void game_engine_build_lighting(
void);
static boolean is_place_tied(
struct statistic_buffer const *entry);
int __cdecl sort_statistic_buffer(
void const *entry0_pointer,
void const *entry1_pointer);
int __cdecl sort_statistic_buffer_ranking(
void const *entry0_pointer,
void const *entry1_pointer);
static void drawline(
wchar_t const *string,
long row_index,
short justification);
static boolean game_engine_infinite_grenades_internal(
void);
static long select_players_to_display(
enum postgame_statistic statistic,
long player_index,
struct statistic_buffer *output,
long maximum_count);
static void netgame_flag_verify_no_team_duplicates(
short flag_type,
char const *error_message);
static void netgame_flag_verify_team_range(
short flag_type,
short minimum_index,
short maximum_index,
char const *error_message);
static void netgame_verify_spawn_points(
short game_type,
short unused_team_index,
short minimum_count,
char const *error_message);
static void netgame_verify_equipment(
short game_type,
char const *error_message);
boolean multiple_teams_alive(
void);
static void game_engine_post_rasterize_in_game(
void);
static void game_engine_rasterize_in_game_score(
long player_index,
real alpha);
static void game_engine_predict_resources(
void);
static void game_engine_verify_current_map(
void);
void game_engine_post_rasterize_post_game(
void);
static boolean internal_rasterize_score(
long player_index,
long message,
long message_data,
wchar_t *buffer,
long buffer_size);
static void game_engine_update_player_no_shield(
long player_index);
static void game_engine_update_teleporter(
long player_index);
static void game_engine_update_weapons(
void);
static void game_engine_update_item_spawn(
void);
boolean team_has_players(
long team_index);
static struct statistic_buffer game_engine_get_player_place(
long player_index);
long postgame_statistic_get_rating(
long player_index,
enum postgame_statistic statistic,
boolean inverse);
long populate_statistic_buffer(
struct statistic_buffer *statistic_buffer,
enum postgame_statistic statistic,
boolean inverse);
static boolean find_closest_player_callback(
long object_index,
void *custom_data);
static long find_closest_player_index(
long player_index);
static void internal_rasterize_target_name(
long player_index);
static long adjust_score_for_ranking(
long score,
long player_index);
/* ---------- globals */
short debug_player_color = NONE;
/* port: slayer's kill-in-order target uses the player's absolute index as
its goal index, so every player needs a goal slot */
struct netgame_goal global_goal[MAX(32, MULTIPLAYER_MAXIMUM_PLAYERS)] = { 0 };
struct game_variant global_variant = { 0 };
struct game_engine *game_engine = NULL;
extern struct game_engine_globals game_engine_globals;
extern struct game_engine_stage global_stage;
extern long timeout_for_endgame_sound;
/* whether a client has had the host's game type state this game (what
changes in the first, from this machine's own start, it only takes: the
game types show what changes in the next) */
static boolean game_engine_network_state_read = FALSE;
/* ---------- public code */
long game_globals_get_weapon(
struct game_globals *game_globals,
long weapon_list_index)
{
struct tag_reference *weapon = TAG_BLOCK_GET_ELEMENT(
&game_globals->weapon_list,
weapon_list_index,
struct tag_reference);
long weapon_definition_index = weapon->index;
return weapon_definition_index;
}
long game_engine_get_team_score(
long team_index)
{
struct data_iterator iterator;
struct player_datum *player;
data_iterator_new(&iterator, player_data);
player = (struct player_datum *)data_iterator_next(&iterator);
while (player)
{
if (player->team_index == team_index)
return game_engine->get_player_score(iterator.datum_index, TRUE);
player = (struct player_datum *)data_iterator_next(&iterator);
}
return 0;
}
real linear_to_non_linear_alpha(
real linear_alpha)
{
real non_linear_alpha = (real)pow((double)linear_alpha, 1.9f);
return non_linear_alpha;
}
static void initialize_player_multiplayer_data(
long player_index)
{
struct player_datum *player = player_get(player_index);
player->state_message = NONE;
player->state_message_player_index = NONE;
player->speed_multiplier = 1.0f;
player->teleporter_index = NONE;
player->player_display_index = NONE;
csmemset(
&player->statistics.multiplayer_statistics,
0,
sizeof(long));
return;
}
/* port: English ordinal for a zero-based place past the string list's 16
("17th", "22nd", "111th"; "tied for 17th" when tied), in a static buffer */
static wchar_t *place_ordinal_string(
long place,
boolean tied)
{
static wchar_t string[32];
long number = place + 1;
wchar_t const *suffix = L"th";
if (number % 100 < 11 || number % 100 > 13)
{
switch (number % 10)
{
case 1:
suffix = L"st";
break;
case 2:
suffix = L"nd";
break;
case 3:
suffix = L"rd";
break;
}
}
usnprintf(
string,
NUMBEROF(string),
tied ? L"tied for %d%s" : L"%d%s",
number,
suffix);
string[NUMBEROF(string) - 1] = 0;
return string;
}
static wchar_t *get_place_string(
struct statistic_buffer *entry)
{
long string_index = PIN(entry->place & 0x7F, 0, 15);
long string_list_index;
/* port: places past the 16th are spelled out instead of clamped (the
caller's format string marks a tie) */
if ((entry->place & 0x7F) >= NUMBER_OF_PLACE_STRINGS)
return place_ordinal_string(entry->place & 0x7F, FALSE);
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
return unicode_string_list_get_string(
string_list_index,
string_index + 36);
return L"";
}
static long game_engine_did_team_win(
long team_index)
{
struct data_iterator iterator;
struct player_datum *player;
long result = FALSE;
data_iterator_new(&iterator, player_data);
player = (struct player_datum *)data_iterator_next(&iterator);
while (player)
{
if (player->team_index == team_index)
{
result = FALSE;
if (game_engine)
{
if (game_engine->did_player_win)
result =
game_engine->did_player_win(iterator.datum_index);
else
result = game_engine_did_player_win_default(
iterator.datum_index);
}
break;
}
player = (struct player_datum *)data_iterator_next(&iterator);
}
return result;
}
static void game_engine_generate_title_string(
wchar_t *title_string,
long player_index)
{
wchar_t *secondary_string;
wchar_t life_string[128];
wchar_t score_string[256];
long string_list_index;
wchar_t *format_string;
player_get(player_index);
secondary_string = L"";
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0x36E,
title_string);
if (global_variant.universal_variant.lives > 0)
{
struct player_datum *player = player_get(player_index);
long remaining_lives =
global_variant.universal_variant.lives - player->statistics.deaths;
switch (remaining_lives)
{
case 0:
string_list_index =
tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
{
secondary_string = unicode_string_list_get_string(
string_list_index,
0x34);
}
else
secondary_string = L"";
break;
case 1:
string_list_index =
tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
{
secondary_string = unicode_string_list_get_string(
string_list_index,
0x35);
}
else
secondary_string = L"";
break;
default:
string_list_index =
tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
{
format_string = unicode_string_list_get_string(
string_list_index,
0x36);
}
else
format_string = L"";
usnprintf(
life_string,
NUMBEROF(life_string),
format_string,
remaining_lives);
life_string[NUMBEROF(life_string) - 1] = 0;
secondary_string = life_string;
break;
}
}
if (game_engine_globals.postgame_state == game_engine_mode_postgame_delay)
{
long did_player_win = game_engine_did_player_win(player_index);
boolean has_teams = game_engine_has_teams();
wchar_t *outcome_string;
switch (did_player_win)
{
case NONE:
string_list_index =
tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
{
outcome_string = unicode_string_list_get_string(
string_list_index,
0x37);
}
else
outcome_string = L"";
ustrncpy(title_string, outcome_string, 80);
break;
case FALSE:
if (has_teams)
{
string_list_index =
tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
{
outcome_string = unicode_string_list_get_string(
string_list_index,
0x38);
}
else
outcome_string = L"";
ustrncpy(title_string, outcome_string, 80);
}
else
{
string_list_index =
tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
{
outcome_string = unicode_string_list_get_string(
string_list_index,
0x39);
}
else
outcome_string = L"";
ustrncpy(title_string, outcome_string, 80);
}
break;
case TRUE:
if (has_teams)
{
string_list_index =
tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
{
outcome_string = unicode_string_list_get_string(
string_list_index,
0x3A);
}
else
outcome_string = L"";
ustrncpy(title_string, outcome_string, 80);
}
else
{
string_list_index =
tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
{
outcome_string = unicode_string_list_get_string(
string_list_index,
0x3B);
}
else
outcome_string = L"";
ustrncpy(title_string, outcome_string, 80);
}
break;
}
}
else if (game_engine_has_teams())
{
wchar_t team0_name[8];
wchar_t team1_name[8];
long team0_score;
long team1_score;
game_engine->format_team_name(
0,
team0_name);
game_engine->format_team_name(
1,
team1_name);
team0_score = game_engine_get_team_score(0);
team1_score = game_engine_get_team_score(1);
if (team0_score > team1_score)
{
string_list_index =
tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
{
format_string =
unicode_string_list_get_string(string_list_index, 0x3C);
}
else
format_string = L"";
usnprintf(
title_string,
80,
format_string,
team0_name,
team1_name,
secondary_string);
}
else if (team0_score < team1_score)
{
string_list_index =
tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
{
format_string =
unicode_string_list_get_string(string_list_index, 0x3D);
}
else
format_string = L"";
usnprintf(
title_string,
80,
format_string,
team1_name,
team0_name,
secondary_string);
}
else
{
string_list_index =
tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
{
format_string =
unicode_string_list_get_string(string_list_index, 0x3E);
}
else
format_string = L"";
usnprintf(
title_string,
80,
format_string,
team1_name,
secondary_string);
}
}
else
{
struct statistic_buffer entry;
entry = game_engine_get_player_place(player_index);
game_engine->format_player_score(player_index, score_string);
if (is_place_tied(&entry))
{
string_list_index =
tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
{
format_string = unicode_string_list_get_string(
string_list_index,
0x3F);
}
else
format_string = L"";
usnprintf(
title_string,
80,
format_string,
get_place_string(&entry),
score_string,
secondary_string);
}
else
{
string_list_index =
tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
{
format_string = unicode_string_list_get_string(
string_list_index,
0x40);
}
else
format_string = L"";
usnprintf(
title_string,
80,
format_string,
get_place_string(&entry),
score_string,
secondary_string);
}
}
title_string[79] = 0;
return;
}
static void rasterize_in_game_score_draw_line(
wchar_t const *string,
boolean brighten,
real_argb_color *color,
long row_index)
{
rectangle2d bounds = render.camera.window_bounds;
short narrow_tab_stops[3];
short wide_tab_stops[3];
short *tab_stops;
boolean splitscreen;
long font_index;
splitscreen = local_player_count() > 1;
font_index = hud_get_font_index();
narrow_tab_stops[0] = 80;
narrow_tab_stops[1] = 125;
narrow_tab_stops[2] = 200;
wide_tab_stops[0] = 130;
wide_tab_stops[1] = 195;
wide_tab_stops[2] = 315;
if (bounds.x1 - bounds.x0 > 320)
tab_stops = wide_tab_stops;
else
tab_stops = narrow_tab_stops;
if (row_index)
draw_string_set_tab_stops(tab_stops, 3);
else
draw_string_set_tab_stops(NULL, 0);
offset_rectangle2d(
&bounds,
-render.camera.viewport_bounds.x0,
-render.camera.viewport_bounds.y0);
if (font_index != NONE)
{
struct font_header *font = font_definition_get(font_index);
long row_offset = 4 * (splitscreen == FALSE) + 4;
long line_height = font->leading_height;
if (!splitscreen)
line_height += font->descending_height;
line_height += font->ascending_height;
if (brighten)
{
color->red += 0.4f;
color->green += 0.4f;
color->blue += 0.4f;
if (color->red > 1.0f)
color->red = 1.0f;
if (color->green > 1.0f)
color->green = 1.0f;
if (color->blue > 1.0f)
color->blue = 1.0f;
}
row_index += row_offset;
bounds.y0 = (short)(row_index * line_height);
bounds.y1 = (short)((row_index + 1) * line_height);
draw_string_set_draw_mode(font_index, NONE, 0, 0, color);
rasterizer_draw_unicode_string(&bounds, NULL, NULL, 0, string);
}
draw_string_set_tab_stops(NULL, 0);
return;
}
long populate_statistic_buffer(
struct statistic_buffer *statistic_buffer,
enum postgame_statistic statistic,
boolean inverse)
{
long player_count = 0;
boolean invert = statistic == _postgame_statistic_deaths ? !inverse : inverse;
struct data_iterator player_iterator;
struct player_datum *player;
long statistic_index;
data_iterator_new(&player_iterator, player_data);
while ((player = (struct player_datum *)data_iterator_next(&player_iterator)) != NULL)
{
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0x2C8,
player_count < MULTIPLAYER_MAXIMUM_PLAYERS);
if (player_count < MULTIPLAYER_MAXIMUM_PLAYERS)
{
statistic_buffer[player_count].player_index = player_iterator.datum_index;
player_count++;
}
}
for (statistic_index = 0; statistic_index < player_count; statistic_index++)
{
long player_index = statistic_buffer[statistic_index].player_index;
player = player_get(player_index);
switch (statistic)
{
case _postgame_statistic_ranking:
statistic_buffer[statistic_index].custom = 0;
if (game_engine->get_player_score)
{
statistic_buffer[statistic_index].custom = adjust_score_for_ranking(
game_engine->get_player_score(player_index, FALSE),
player_index);
}
statistic_buffer[statistic_index].kills = player->statistics.kills[0];
statistic_buffer[statistic_index].assists = player->statistics.assists[0];
statistic_buffer[statistic_index].deaths = player->statistics.deaths;
break;
case _postgame_statistic_score:
statistic_buffer[statistic_index].score = 0;
if (game_engine->get_player_score)
{
statistic_buffer[statistic_index].score = adjust_score_for_ranking(
game_engine->get_player_score(player_index, FALSE),
player_index);
}
break;
case _postgame_statistic_kills:
statistic_buffer[statistic_index].score = player->statistics.kills[0];
break;
case _postgame_statistic_assists:
statistic_buffer[statistic_index].score = player->statistics.assists[0];
break;
case _postgame_statistic_deaths:
statistic_buffer[statistic_index].score = player->statistics.deaths;
break;
default:
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0x2FD,
!"unreachable");
break;
}
if (invert)
statistic_buffer[statistic_index].score = -statistic_buffer[statistic_index].score;
}
if (statistic == _postgame_statistic_ranking)
{
qsort(
statistic_buffer,
player_count,
sizeof(*statistic_buffer),
sort_statistic_buffer_ranking);
}
else
{
qsort(
statistic_buffer,
player_count,
sizeof(*statistic_buffer),
sort_statistic_buffer);
}
for (statistic_index = 0; statistic_index < player_count; statistic_index++)
{
if (statistic_index != 0 &&
sort_statistic_buffer_ranking(
&statistic_buffer[statistic_index - 1],
&statistic_buffer[statistic_index]) == 0)
{
statistic_buffer[statistic_index - 1].place |= 0x80000000;
statistic_buffer[statistic_index].place = statistic_buffer[statistic_index - 1].place;
}
else
{
statistic_buffer[statistic_index].place = statistic_index;
}
}
return player_count;
}
static long select_players_to_display(
enum postgame_statistic statistic,
long player_index,
struct statistic_buffer *output,
long maximum_count)
{
struct statistic_buffer statistic_buffer[MULTIPLAYER_MAXIMUM_PLAYERS];
long player_count = populate_statistic_buffer(statistic_buffer, statistic, FALSE);
boolean debug = rasterizer_debug_options.pad3 == 'E';
long local_player_count = 0;
long statistic_index;
if (debug)
{
terminal_printf(
global_real_argb_white,
"player_count=%d, maxcount=%d",
player_count,
maximum_count);
}
for (statistic_index = 0; statistic_index < player_count; statistic_index++)
{
struct player_datum *player = player_get(statistic_buffer[statistic_index].player_index);
if (player->local_player_index != NONE)
local_player_count++;
}
if (player_count > maximum_count)
{
long outside_range_count = 0;
struct statistic_buffer outside_range[MAXIMUM_LOCAL_PLAYERS];
long outside_range_index;
for (statistic_index = maximum_count; statistic_index < player_count; statistic_index++)
{
struct player_datum *player = player_get(statistic_buffer[statistic_index].player_index);
if (player && player->local_player_index != NONE)
{
if (debug)
{
terminal_printf(
global_real_argb_white,
"found local player");
}
outside_range[outside_range_count] = statistic_buffer[statistic_index];
outside_range_count++;
}
}
for (outside_range_index = 0; outside_range_index < outside_range_count; outside_range_index++)
{
long insertion_index;
for (insertion_index = maximum_count - 1; insertion_index >= 0; insertion_index--)
{
struct player_datum *player = player_get(statistic_buffer[insertion_index].player_index);
if (player->local_player_index == NONE)
{
csmemmove(
&statistic_buffer[insertion_index],
&statistic_buffer[insertion_index + 1],
maximum_count * sizeof(struct statistic_buffer) -
(insertion_index + 1) * sizeof(struct statistic_buffer));
statistic_buffer[maximum_count - 1] = outside_range[outside_range_index];
break;
}
}
}
}
csmemcpy(
output,
statistic_buffer,
MIN(maximum_count, player_count) *
sizeof(struct statistic_buffer));
return MIN(maximum_count, player_count);
}
static void game_engine_rasterize_in_game_score(
long player_index,
real alpha)
{
wchar_t row_string[256];
wchar_t score_string[256];
struct statistic_buffer entries[6];
wchar_t title_string[80];
real_argb_color text_color;
real_argb_color team_colors[2];
real_argb_color color;
boolean has_teams = game_engine_has_teams();
boolean is_current_player;
long entry_count;
long entry_index;
long string_list_index;
wchar_t *column_name;
wchar_t *score_name;
game_engine_generate_title_string(title_string, player_index);
entry_count = select_players_to_display(
_postgame_statistic_ranking,
player_index,
entries,
NUMBEROF(entries));
color.alpha = alpha;
color.red = 0.7f;
color.green = 0.7f;
color.blue = 0.7f;
rasterize_in_game_score_draw_line(title_string, FALSE, &color, 0);
color.red = 0.5f;
color.green = 0.5f;
color.blue = 0.5f;
color.alpha = alpha;
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
column_name = unicode_string_list_get_string(string_list_index, 0x43);
else
column_name = L"";
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
score_name = unicode_string_list_get_string(string_list_index, 0x44);
else
score_name = L"";
game_engine->format_score_name(score_string);
usprintf(row_string, L"\t%s\t%s\t%s", column_name, score_name, score_string);
rasterize_in_game_score_draw_line(row_string, FALSE, &color, 1);
for (entry_index = 0; entry_index < entry_count; entry_index++)
{
long entry_player_index = entries[entry_index].player_index;
struct player_datum *player =
player_try_and_get(entry_player_index);
wchar_t *status_string;
wchar_t *place_string;
real_argb_color *row_color;
is_current_player = player_index == entry_player_index;
if (player)
{
color = *hud_get_text_color(&text_color);
player = player_get(entry_player_index);
team_colors[0].alpha = alpha;
team_colors[0].red = 0.6f;
team_colors[0].green = 0.3f;
team_colors[0].blue = 0.3f;
team_colors[1].alpha = alpha;
team_colors[1].red = 0.3f;
team_colors[1].green = 0.3f;
team_colors[1].blue = 0.6f;
color.alpha = alpha;
game_engine->format_player_score(
entry_player_index,
score_string);
if (game_engine_player_is_out_of_lives(entry_player_index))
{
string_list_index =
tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
status_string =
unicode_string_list_get_string(string_list_index, 0x8A);
else
status_string = L"";
}
else if (player->quit_out_of_game)
{
string_list_index =
tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
status_string =
unicode_string_list_get_string(string_list_index, 0x8B);
else
status_string = L"";
}
else
status_string = score_string;
place_string = get_place_string(&entries[entry_index]);
usprintf(
row_string,
L"\t%s\t%s\t%s",
place_string,
player->name,
status_string);
if (has_teams)
row_color = &team_colors[PIN(player->team_index, 0, 1)];
else
row_color = &color;
rasterize_in_game_score_draw_line(
row_string,
is_current_player,
row_color,
entry_index + 2);
}
}
return;
}
static void drawline(
wchar_t const *string,
long row_index,
short justification)
{
rectangle2d bounds = render.camera.window_bounds;
long line_height = 18;
long line_spacing = 8;
offset_rectangle2d(
&bounds,
-render.camera.viewport_bounds.x0,
-render.camera.viewport_bounds.y0);
bounds.y0 = (short)(row_index * line_height);
bounds.y1 = (short)((row_index + 1) * line_height + line_spacing);
draw_string_set_format(NONE, justification, 0);
rasterizer_draw_unicode_string(&bounds, NULL, NULL, 0, string);
return;
}
void game_engine_post_rasterize_post_game(
void)
{
/* port: sized like every buffer handed to populate_statistic_buffer */
struct statistic_buffer entries[MULTIPLAYER_MAXIMUM_PLAYERS];
wchar_t score_string[256];
wchar_t row_string[256];
short tab_stops[6];
real_argb_color winner_color;
real_argb_color normal_color;
real_argb_color hilite_color;
long font_index;
long entry_count;
long entry_index;
if (!game_engine)
return;
tab_stops[0] = 50;
tab_stops[1] = 125;
tab_stops[2] = 250;
tab_stops[3] = 350;
tab_stops[4] = 410;
tab_stops[5] = 500;
font_index = hud_globals->messaging.single_player_font.index;
get_postgame_hilite_colors(
&winner_color,
&normal_color,
&hilite_color);
draw_string_set_draw_mode(
font_index,
NONE,
2,
8,
&winner_color);
draw_string_set_color(&winner_color);
draw_string_set_format(NONE, 0, 0);
{
struct hud_globals_definition *hud_definition =
hud_globals_definition_get(
interface_get_tag_index(_interface_hud_globals));
rectangle2d bounds;
bounds.x0 = 0;
bounds.y0 = 0;
bounds.x1 = 640;
bounds.y1 = 480;
if (bitmap_group_try_and_get_bitmap(hud_definition->carnage_report_bitmap.index, 0))
{
draw_bitmap_in_rect(
bitmap_group_try_and_get_bitmap(hud_definition->carnage_report_bitmap.index, 0),
&bounds,
&bounds,
NULL,
NONE,
NULL,
TRUE);
}
}
if (global_variant.universal_variant.teams)
{
short team_tab_stops[6] = { 50, 200, 300, 350, 410, 500 };
long team_order[2] = { 0, 1 };
wchar_t const *team_formats[2];
long string_list_index;
long team_row;
long red_team_won;
red_team_won = game_engine_did_team_win(0);
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
team_formats[0] =
string_list_index != NONE ?
unicode_string_list_get_string(string_list_index, 0x41) :
L"";
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
team_formats[1] =
string_list_index != NONE ?
unicode_string_list_get_string(string_list_index, 0x42) :
L"";
if (!red_team_won)
{
team_order[0] = 1;
team_order[1] = 0;
}
draw_string_set_tab_stops(team_tab_stops, NUMBEROF(team_tab_stops));
for (team_row = 0; team_row < 2; team_row++)
{
long team_index = team_order[team_row];
game_engine->format_team_name(
team_index,
score_string);
usnprintf(
row_string,
NUMBEROF(row_string),
team_formats[team_index],
score_string);
row_string[NUMBEROF(row_string) - 1] = 0;
drawline(row_string, team_row + 4, 0);
}
}
{
long string_list_index;
wchar_t const *column_strings[5];
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
column_strings[0] =
string_list_index != NONE ?
unicode_string_list_get_string(string_list_index, 0x43) :
L"";
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
column_strings[1] =
string_list_index != NONE ?
unicode_string_list_get_string(string_list_index, 0x44) :
L"";
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
column_strings[2] =
string_list_index != NONE ?
unicode_string_list_get_string(string_list_index, 0x45) :
L"";
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
column_strings[3] =
string_list_index != NONE ?
unicode_string_list_get_string(string_list_index, 0x46) :
L"";
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
column_strings[4] =
string_list_index != NONE ?
unicode_string_list_get_string(string_list_index, 0x47) :
L"";
game_engine->format_score_name(score_string);
usnprintf(
row_string,
NUMBEROF(row_string),
L"\t%s\t%s\t%s\t%s\t%s\t%s",
column_strings[0],
column_strings[1],
score_string,
column_strings[2],
column_strings[3],
column_strings[4]);
row_string[NUMBEROF(row_string) - 1] = 0;
draw_string_set_tab_stops(tab_stops, NUMBEROF(tab_stops));
drawline(row_string, 7, 0);
}
entry_count = select_players_to_display(_postgame_statistic_ranking, NONE, entries, 12);
for (entry_index = 0; entry_index < entry_count; entry_index++)
{
long player_index = entries[entry_index].player_index;
long draw_row = entry_index + 8;
struct player_datum *player = player_get(player_index);
real_argb_color team_colors[2];
wchar_t const *place_string;
if (player->local_player_index != NONE)
draw_string_set_color(&normal_color);
else
draw_string_set_color(&winner_color);
draw_string_set_tab_stops(tab_stops, NUMBEROF(tab_stops));
place_string = get_place_string(&entries[entry_index]);
usnprintf(row_string, NUMBEROF(row_string), L" \t%s", place_string);
row_string[NUMBEROF(row_string) - 1] = 0;
drawline(row_string, draw_row, 0);
draw_string_set_color(&winner_color);
if (global_variant.universal_variant.teams)
{
long team_index = player->team_index;
team_colors[0].red = 0.8f;
team_colors[0].green = 0.4f;
team_colors[0].blue = 0.4f;
team_colors[0].alpha = 1.0f;
team_colors[1].red = 0.4f;
team_colors[1].green = 0.4f;
team_colors[1].blue = 0.8f;
team_colors[1].alpha = 1.0f;
draw_string_set_color(
&team_colors[PIN(team_index, 0, 1)]);
}
usnprintf(row_string, NUMBEROF(row_string), L" \t \t%s", player->name);
row_string[NUMBEROF(row_string) - 1] = 0;
drawline(row_string, draw_row, 0);
draw_string_set_color(&winner_color);
if (!postgame_statistic_get_rating(player_index, _postgame_statistic_score, FALSE))
draw_string_set_color(&hilite_color);
game_engine->format_player_score(
player_index,
score_string);
usnprintf(row_string, NUMBEROF(row_string), L" \t \t \t%s", score_string);
row_string[NUMBEROF(row_string) - 1] = 0;
drawline(row_string, draw_row, 0);
draw_string_set_color(&winner_color);
if (!postgame_statistic_get_rating(player_index, _postgame_statistic_kills, FALSE))
draw_string_set_color(&hilite_color);
usnprintf(
row_string,
NUMBEROF(row_string),
L" \t \t \t \t%d",
(long)player->statistics.kills[0]);
row_string[NUMBEROF(row_string) - 1] = 0;
drawline(row_string, draw_row, 0);
draw_string_set_color(&winner_color);
if (!postgame_statistic_get_rating(player_index, _postgame_statistic_assists, FALSE))
draw_string_set_color(&hilite_color);
usnprintf(
row_string,
NUMBEROF(row_string),
L" \t \t \t \t \t%d",
(long)player->statistics.assists[0]);
row_string[NUMBEROF(row_string) - 1] = 0;
drawline(row_string, draw_row, 0);
draw_string_set_color(&winner_color);
if (!postgame_statistic_get_rating(player_index, _postgame_statistic_deaths, FALSE))
draw_string_set_color(&hilite_color);
usnprintf(
row_string,
NUMBEROF(row_string),
L" \t \t \t \t \t \t%d",
(long)player->statistics.deaths);
row_string[NUMBEROF(row_string) - 1] = 0;
drawline(row_string, draw_row, 0);
draw_string_set_tab_stops(tab_stops, NUMBEROF(tab_stops));
}
{
real_argb_color prompt_color;
long string_list_index;
wchar_t const *prompt;
struct network_game_server *server;
rectangle2d bounds;
bounds = render.camera.window_bounds;
prompt_color = winner_color;
prompt_color.alpha = game_engine_globals.postgame_progress;
bounds.y0 = 410;
bounds.x0 = 70;
offset_rectangle2d(
&bounds,
-render.camera.viewport_bounds.x0,
-render.camera.viewport_bounds.y0);
draw_string_set_tab_stops(NULL, 0);
draw_string_set_color(&prompt_color);
server = global_network_game_server_get();
if (server)
{
bounds.x0 = 380;
string_list_index =
tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
prompt =
unicode_string_list_get_string(string_list_index, 0x48);
else
prompt = L"";
draw_string_and_hack_in_icons(
&bounds,
NULL,
NULL,
0,
prompt,
FALSE);
return;
}
bounds.x0 = 520;
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
prompt = unicode_string_list_get_string(string_list_index, 0x49);
else
prompt = L"";
draw_string_and_hack_in_icons(
&bounds,
NULL,
NULL,
0,
prompt,
FALSE);
}
return;
}
static long find_closest_player_index(
long player_index)
{
struct player_datum *player = player_get(player_index);
long best_object_index = NONE;
if (player->local_player_index != NONE &&
player_control_get_autoaim_level(player->local_player_index) > 0.0f)
{
best_object_index =
player_control_get_target_object_index(player->local_player_index);
}
if (best_object_index == NONE)
{
long object_indices[32];
real_point3d camera_position;
real_vector3d facing_direction;
long object_count;
long object_index;
unit_get_camera_position(player->unit_index, &camera_position);
player_control_get_facing_direction(
player->local_player_index,
&facing_direction);
object_count = find_objects_from_point_vector(
&camera_position,
&facing_direction,
find_closest_player_callback,
&player_index,
NUMBEROF(object_indices),
object_indices);
for (object_index = 0; object_index < object_count; object_index++)
{
long candidate_object_index = object_indices[object_index];
struct unit_datum *candidate = unit_get(candidate_object_index);
real distance_squared = distance_squared3d(
&camera_position,
&candidate->object.position);
real_point3d target_position;
real_vector3d target_direction;
real target_distance;
real target_angle;
if ((candidate->unit.active_camouflage < 1.0f ||
player->player_display_index == player_index_from_unit_index(candidate_object_index)) &&
autoaim_compute_target(
object_indices[object_index],
&camera_position,
&facing_direction,
player->unit_index,
&target_position,
&target_direction,
&target_distance,
&target_angle) &&
fabs(target_angle) < 0.13083334267139435 &&
distance_squared < 400.0f &&
distance_squared < 900.0f)
{
best_object_index = object_indices[object_index];
}
}
}
if (best_object_index != NONE)
best_object_index = player_index_from_unit_index(best_object_index);
return best_object_index;
}
long game_engine_remap_equipment(
long equipment_definition_index)
{
struct equipment_definition *equipment;
long weapon_list_index;
boolean remap_equipment;
if (equipment_definition_index == NONE)
equipment = NULL;
else
equipment = equipment_definition_get(equipment_definition_index);
weapon_list_index =
weapon_definition_index_to_list_index(equipment_definition_index);
remap_equipment = weapon_list_index == _weapon_list_frag_grenade ||
weapon_list_index == _weapon_list_plasma_grenade;
if (!remap_equipment)
{
if (equipment)
{
if (equipment->equipment.powerup_type == _equipment_powerup_overshield)
{
if (TEST_FLAG(global_variant.universal_variant.flags, _game_variant_no_shields_bit))
return NONE;
}
else if (equipment->equipment.powerup_type == _equipment_powerup_active_camouflage)
{
if (TEST_FLAG(global_variant.universal_variant.flags, _game_variant_always_invisible_bit))
return NONE;
}
}
}
else
{
switch (global_variant.universal_variant.weapon_set)
{
case _game_engine_weapons_plasma_weapons:
weapon_list_index = _weapon_list_plasma_grenade;
break;
case _game_engine_weapons_human:
weapon_list_index = _weapon_list_frag_grenade;
break;
case _game_engine_weapons_no_grenades:
weapon_list_index = NONE;
break;
}
if (!TEST_FLAG(game_engine_globals.flags, _game_engine_5_or_more_players_bit))
{
if (game_engine_infinite_grenades_internal())
{
weapon_list_index = NONE;
}
}
if (TEST_FLAG(game_engine_globals.flags, _game_engine_9_or_more_players_bit))
{
if (real_seed_random(get_global_random_seed_address()) > 0.3f)
weapon_list_index = NONE;
}
else if (TEST_FLAG(game_engine_globals.flags, _game_engine_5_or_more_players_bit))
{
if (real_seed_random(get_global_random_seed_address()) > 0.55f)
weapon_list_index = NONE;
}
}
if (remap_equipment)
return list_index_to_weapon_definition_index(weapon_list_index);
return equipment_definition_index;
}
int __cdecl sort_statistic_buffer(
void const *entry0_pointer,
void const *entry1_pointer)
{
struct statistic_buffer const *entry0 = entry0_pointer;
struct statistic_buffer const *entry1 = entry1_pointer;
long result = 0;
if (entry0->score > entry1->score)
result = -1;
else if (entry1->score > entry0->score)
result = 1;
return result;
}
int __cdecl sort_statistic_buffer_ranking(
void const *entry0_pointer,
void const *entry1_pointer)
{
struct statistic_buffer const *entry0 = entry0_pointer;
struct statistic_buffer const *entry1 = entry1_pointer;
long result = 0;
if (entry0->custom > entry1->custom)
result = -1;
else if (entry1->custom > entry0->custom)
result = 1;
else if (entry0->kills > entry1->kills)
result = -1;
else if (entry1->kills > entry0->kills)
result = 1;
else if (entry0->deaths > entry1->deaths)
result = 1;
else if (entry1->deaths > entry0->deaths)
result = -1;
else if (entry0->assists > entry1->assists)
result = -1;
else if (entry1->assists > entry0->assists)
result = 1;
return result;
}
static boolean is_place_tied(
struct statistic_buffer const *entry)
{
boolean result =
(entry->place & 0x80000000) > 0;
return result;
}
static long place_get_position(
struct statistic_buffer const *entry)
{
return entry->place & ~FLAG(31);
}
static void get_selected_color(
real_argb_color *color)
{
color->red = 0.98f;
color->green = 0.96f;
color->blue = 0.96f;
color->alpha = 1.0f;
return;
}
static boolean can_delete_item(
long weapon_index)
{
boolean result = TRUE;
if (weapon_try_and_get(weapon_index) &&
weapon_is_flag(weapon_index))
{
result = FALSE;
}
return result;
}
static boolean multiplayer_message_internal(
long player_index,
long message,
long message_data,
wchar_t *buffer,
long buffer_size)
{
boolean result = FALSE;
if (game_engine->format_message)
{
result = game_engine->format_message(
player_index,
message,
message_data,
buffer,
buffer_size);
}
if (!result)
{
result = internal_rasterize_score(
player_index,
message,
message_data,
buffer,
buffer_size);
}
return result;
}
static void multiplayer_message(
long player_index,
long message,
long message_data)
{
struct player_datum *player = player_get(player_index);
if (player->local_player_index != NONE)
{
wchar_t buffer[1024];
if (multiplayer_message_internal(
player_index,
message,
message_data,
buffer,
NUMBEROF(buffer)))
{
buffer[NUMBEROF(buffer) - 1] = 0;
hud_print_message(player->local_player_index, buffer);
}
}
return;
}
static void game_show_score_one_player(
long player_index,
long message,
long message_data)
{
if (message != NONE)
multiplayer_message(player_index, message, message_data);
return;
}
void game_show_score_team(
long team_index,
long score)
{
struct data_iterator iterator;
struct player_datum *player;
data_iterator_new(&iterator, player_data);
player = (struct player_datum *)data_iterator_next(&iterator);
while (player)
{
if (player->team_index == team_index)
{
game_show_score_one_player(iterator.datum_index, score, NONE);
}
player = (struct player_datum *)data_iterator_next(&iterator);
}
return;
}
void game_show_score_you_ally_enemy(
long player_index,
long you_score,
long ally_score,
long enemy_score,
long other_player_index)
{
struct player_datum *local_player;
struct data_iterator iterator;
struct player_datum *player;
long score;
local_player = player_get(player_index);
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0xB1A,
NONE != player_index);
data_iterator_new(&iterator, player_data);
player = (struct player_datum *)data_iterator_next(&iterator);
while (player)
{
if (iterator.datum_index == player_index)
{
if (you_score != NONE)
{
game_show_score_one_player(
iterator.datum_index,
you_score,
other_player_index);
}
}
else
{
if (game_team_is_enemy(
(short)local_player->team_index,
(short)player->team_index))
{
score = enemy_score;
}
else
score = ally_score;
if (score != NONE)
{
game_show_score_one_player(
iterator.datum_index,
score,
other_player_index);
}
}
player = (struct player_datum *)data_iterator_next(&iterator);
}
return;
}
void game_show_score_extended(
long player_index,
long score,
long team_index)
{
if (player_index != NONE)
{
game_show_score_one_player(player_index, score, team_index);
}
else
{
struct data_iterator iterator;
data_iterator_new(&iterator, player_data);
while (data_iterator_next(&iterator))
{
game_show_score_one_player(
iterator.datum_index,
score,
team_index);
}
}
return;
}
long players_in_game(
void)
{
struct data_iterator iterator;
long player_count = 0;
data_iterator_new(&iterator, player_data);
while (data_iterator_next(&iterator))
player_count++;
return player_count;
}
static void game_engine_press_start_to_begin(
void)
{
return;
}
static boolean goal_matches_player(
struct player_datum *player,
long player_index,
long goal_index)
{
boolean result = FALSE;
if (game_engine)
{
struct netgame_goal *goal = &global_goal[goal_index];
if (game_engine->player_can_see_goal)
{
if (goal->in_use)
result = game_engine->player_can_see_goal(player_index, goal_index);
}
else if (
goal->in_use &&
(goal->player_index == NONE || player_index == goal->player_index) &&
(goal->team_index == NONE || player->team_index == goal->team_index) &&
(goal->ignore_player_index == NONE || player_index != goal->ignore_player_index))
{
result = TRUE;
}
}
return result;
}
static boolean nearby_vehicle(
long player_index,
struct player_starting_location const *starting_location)
{
struct location location;
long object_indices[16];
short object_count;
short object_index;
player_get(player_index);
scenario_location_from_point(&location, &starting_location->position);
object_count = objects_in_sphere(
0,
0x11F,
&location,
&starting_location->position,
0.1f,
object_indices,
NUMBEROF(object_indices));
for (object_index = 0; object_index < object_count; object_index++)
{
struct object_datum *object = object_get(object_indices[object_index]);
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0xEE9,
object);
if (object->object.type == _object_type_vehicle)
{
struct vehicle_datum *vehicle =
(struct vehicle_datum *)object_get_and_verify_type(
object_indices[object_index],
_object_mask_vehicle);
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0xEEE,
vehicle);
if (vehicle)
return TRUE;
return FALSE;
}
}
return FALSE;
}
static real game_engine_get_friendly_bonus(
long player_index,
real_point3d const *position)
{
struct player_datum *player = player_get(player_index);
struct data_iterator iterator;
struct player_datum *other_player;
real rating = 0.0f;
data_iterator_new(&iterator, player_data);
other_player = (struct player_datum *)data_iterator_next(&iterator);
while (other_player)
{
if (player->team_index == other_player->team_index &&
other_player->unit_index != NONE)
{
real_point3d origin;
real distance;
object_get_origin(other_player->unit_index, &origin);
distance = distance3d(&origin, position);
if (distance >= 1.0f && distance <= 6.0f)
{
rating += (real)pow(
(double)(1.0f - (distance - 1.0f) * 0.2f),
(double)0.6f);
}
}
other_player = (struct player_datum *)data_iterator_next(&iterator);
}
if (rating > 3.0f)
rating = 3.0f;
return rating * 3.0f + 1.0f;
}
static real default_starting_location_rate_function(
long player_index,
struct player_starting_location const *starting_location)
{
struct player_datum *player = player_get(player_index);
real rating = 1.0f;
if (game_engine_running() &&
game_engine_test_flag(0) &&
player->team_index != starting_location->team_index)
{
rating = 0.0f;
}
if (rating > 0.0f)
{
rating *= game_engine_get_distance_rating_for_spawn(
player_index,
&starting_location->position);
}
if (game_engine_running() && rating > 0.0f && game_engine_has_teams())
{
rating *= game_engine_get_friendly_bonus(
player_index,
&starting_location->position);
}
if (game_engine_running() && game_engine->starting_location_rating)
{
rating *= game_engine->starting_location_rating(
player_index,
starting_location);
}
return rating;
}
static boolean test_any_gamepad_button(
long button_index)
{
boolean result = FALSE;
long gamepad_index;
for (gamepad_index = 0; gamepad_index < 4; gamepad_index++)
{
struct gamepad_state const *gamepad_state =
input_get_gamepad_state((short)gamepad_index);
if (gamepad_state && gamepad_state->buttons[button_index])
{
result = TRUE;
break;
}
}
return result;
}
boolean match_game_type(
long game_type,
long count,
short const *game_types)
{
boolean result;
long index;
if (game_engine)
{
result = FALSE;
for (index = 0; index < count; index++)
{
short entry = game_types[index];
result = result | (entry == game_type);
if (entry == _game_engine_all)
{
result = result | TRUE;
}
else if (entry == _game_engine_all_non_team)
{
result = result | (game_type != game_engine_ctf);
}
else if (entry == _game_engine_all_normal)
{
result = result | (game_type != game_engine_ctf && game_type != game_engine_race);
}
}
}
else
{
result = TRUE;
for (index = 0; index < count; index++)
result = result & (game_types[index] == game_engine_none);
}
return result;
}
static boolean game_engine_infinite_grenades_internal(
void)
{
boolean infinite_grenades = FALSE;
if (!TEST_FLAG(game_engine_globals.flags, _game_engine_5_or_more_players_bit))
infinite_grenades = TEST_FLAG(global_variant.universal_variant.flags, _game_variant_infinite_grenades_bit);
return infinite_grenades;
}
static boolean find_closest_player_callback(
long object_index,
void *custom_data)
{
long excluded_player = *(long *)custom_data;
boolean result = FALSE;
struct object_datum *object = object_get(object_index);
if (!TEST_FLAG(object->object.flags, _object_invisible_bit) &&
TEST_FLAG(_object_mask_biped, object->object.type) &&
!TEST_FLAG(object->object.damage_flags, _object_dead_bit) &&
player_index_from_unit_index(object_index) != excluded_player)
{
result = TRUE;
}
return result;
}
static void game_engine_update_purge(
void)
{
long cutoff_time = game_time_get() - 900;
/* (a client of the distributed netcode removes items when the host does,
port/linux/game/network_distributed.c) */
if (!network_game_distributed_client())
{
struct object_iterator item_iterator;
object_iterator_new(&item_iterator, _object_mask_item, 0);
while (object_iterator_next(&item_iterator))
{
struct item_datum *item = item_get(item_iterator.index);
if (item->item.last_owned_time < cutoff_time &&
!TEST_FLAG(item->item.flags, _item_attached_to_unit_bit))
{
long item_index = item_iterator.index;
if (can_delete_item(item_index))
object_delete(item_iterator.index);
}
}
}
{
struct object_iterator biped_iterator;
object_iterator_new(&biped_iterator, _object_mask_biped, 0);
while (object_iterator_next(&biped_iterator))
{
struct object_datum *object;
cutoff_time = 900;
object = object_get(biped_iterator.index);
if (object->object.idle_ticks > (short)cutoff_time &&
TEST_FLAG(object->object.damage_flags, _object_dead_bit))
{
object_delete(biped_iterator.index);
}
}
}
return;
}
void game_engine_flag_reset(
long weapon_index,
real_point3d const *position)
{
if (weapon_index != NONE)
{
struct weapon_datum *weapon = weapon_get(weapon_index);
object_set_position(weapon_index, position, global_forward3d, global_up3d);
object_reset(weapon_index);
SET_FLAG(weapon->weapon.flags, _weapon_runtime_game_engine_active_bit, FALSE);
weapon->item.last_owned_time = game_time_get();
weapon->item.ignore_object_index = NONE;
}
return;
}
void ticks_to_unicode_time_string(
long ticks,
unsigned long character_count,
wchar_t *string)
{
long total_seconds;
long minutes;
long seconds;
wchar_t minute_string[64];
wchar_t second_string[64];
total_seconds = ticks / 30;
minutes = total_seconds / 60;
seconds = total_seconds - minutes * 60;
if (minutes == 0)
usnprintf(minute_string, NUMBEROF(minute_string), L" ");
else
usnprintf(minute_string, NUMBEROF(minute_string), L"%d", minutes);
if (seconds <= 9)
usnprintf(second_string, NUMBEROF(second_string), L"0%d", seconds);
else
usnprintf(second_string, NUMBEROF(second_string), L"%d", seconds);
usnprintf(string, character_count, L"%s:%s", minute_string, second_string);
return;
}
void game_engine_playlist_initialize(
void)
{
game_engine_playlist_next(0, 0, 2);
return;
}
void game_engine_playlist_begin(
void)
{
main_set_multiplayer_map_name(global_stage.map_name);
game_set_game_variant(&global_stage.variant);
if (!network_game_is_active())
main_reset_map();
return;
}
boolean game_engine_get_current_stage(
struct game_variant *variant,
char *map_name)
{
match_assert("c:\\halo\\SOURCE\\game\\game_engine.c", 0x918, variant && map_name);
csmemcpy(variant, &global_stage.variant, sizeof(*variant));
csstrncpy(map_name, global_stage.map_name, sizeof(global_stage.map_name)-1);
map_name[sizeof(global_stage.map_name)-1] = 0;
return TRUE;
}
long list_index_to_weapon_definition_index(
long weapon_list_index)
{
long weapon_definition_index = NONE;
if (weapon_list_index!=NONE)
{
struct game_globals *game_globals = scenario_get_game_globals();
weapon_definition_index = game_globals_get_weapon(game_globals, weapon_list_index);
}
return weapon_definition_index;
}
long weapon_definition_index_to_list_index(
long weapon_definition_index)
{
struct game_globals *game_globals = scenario_get_game_globals();
struct tag_reference *weapons = game_globals->weapon_list.count ?
TAG_BLOCK_GET_ELEMENT(&game_globals->weapon_list, 0, struct tag_reference) :
NULL;
long result = NONE;
long weapon_list_index;
for (weapon_list_index = 0;
weapon_list_index < game_globals->weapon_list.count;
weapon_list_index++)
{
long definition_index = weapons[weapon_list_index].index;
if (weapon_definition_index == definition_index)
{
result = weapon_list_index;
break;
}
}
return result;
}
void game_engine_state_message(
long player_index,
long state_message,
long state_message_player_index)
{
struct player_datum *player = player_get(player_index);
player->state_message = state_message;
player->state_message_player_index = state_message_player_index;
return;
}
void game_engine_player_depower_active_camo(
long player_index)
{
if (player_index!=NONE)
{
struct player_datum *player = player_get(player_index);
if (player->unit_index!=NONE)
{
struct unit_datum *unit = unit_get(player->unit_index);
if (TEST_FLAG(unit->unit.flags, _unit_active_camouflaged_bit))
unit->unit.active_camouflage = 0.5f;
}
}
return;
}
real get_blink_alpha(
void)
{
long phase = system_milliseconds()%2700;
return sin(phase * (3.14159265358979/2700.0));
}
void game_engine_rasterize_message(
wchar_t const *message,
real alpha)
{
rectangle2d bounds;
real_argb_color color;
long font_index;
long terminal_font_index;
if (local_player_count())
font_index = hud_globals->messaging.multi_player_font.index;
else
font_index = hud_globals->messaging.single_player_font.index;
bounds = render.camera.window_bounds;
terminal_font_index = interface_get_tag_index(_interface_font_terminal);
draw_string_set_draw_mode(
terminal_font_index,
NONE,
0,
0,
global_real_argb_white);
color.alpha = alpha;
color.red = 0.45882353f;
color.green = 0.7294118f;
color.blue = 1.0f;
offset_rectangle2d(
&bounds,
-render.camera.viewport_bounds.x0,
-render.camera.viewport_bounds.y0);
bounds.y1 = (short)((5 * bounds.y0 + bounds.y1) / 6 + 9);
bounds.y0 = bounds.y1 - 15;
draw_string_set_draw_mode(font_index, NONE, 2, 8, &color);
draw_string_set_color(&color);
rasterizer_draw_unicode_string(&bounds, NULL, NULL, 0, message);
draw_string_set_format(NONE, 0, 0);
draw_string_set_tab_stops(NULL, 0);
return;
}
static void game_engine_post_rasterize_in_game(
void)
{
long local_player_index;
long player_index;
struct player_datum *player;
struct gamepad_state const *gamepad;
real fade;
local_player_index = render.local_player_index;
player_index = local_player_get_player_index(local_player_index);
player = player_get(player_index);
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0x770,
NONE != local_player_index);
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0x771,
NULL != game_engine);
if (game_engine && player)
internal_rasterize_target_name(player_index);
gamepad = input_get_gamepad_state(local_player_index);
fade = game_engine_globals.hud_message_timers[local_player_index];
if ((!gamepad ||
!gamepad->buttons[_gamepad_binary_button_back]) &&
game_engine_globals.postgame_state != game_engine_mode_postgame_delay)
{
/* a frame is no longer a tick (render_interpolation.c): fade in half
a second, not in 15 frames */
fade -= 0.06666667f * main_get_seconds_elapsed() * TICKS_PER_SECOND;
}
else
{
fade += 0.06666667f * main_get_seconds_elapsed() * TICKS_PER_SECOND;
}
fade = PIN(fade, 0.0f, 1.0f);
if (fade > 0.0f)
{
real alpha = linear_to_non_linear_alpha(fade);
game_engine_rasterize_in_game_score(player_index, alpha);
}
game_engine_globals.hud_message_timers[local_player_index] = fade;
return;
}
long game_engine_player_get_team_index(
long player_index)
{
long team_index = 1;
match_assert("c:\\halo\\SOURCE\\game\\game_engine.c", 0xC11, game_engine);
if (!game_engine->team_index_override)
/* port: 0 or 1 (another machine's player has no local player: -1) */
team_index = PIN(player_get(player_index)->local_player_index % 2, 0, 1);
return team_index;
}
void game_engine_update_player_always_invis(
long player_index)
{
if (game_engine)
{
if ((TEST_FLAG(global_variant.universal_variant.flags, _game_variant_always_invisible_bit) ||
game_engine_test_trait(player_index, 1)) &&
player_get(player_index)->unit_index!=NONE)
{
player_handle_powerup_minor(player_index, 0, 15);
}
}
return;
}
boolean game_engine_player_has_flag(
long player_index)
{
boolean has_flag = FALSE;
if (player_index!=NONE)
{
struct player_datum *player = player_get(player_index);
if (player->unit_index!=NONE)
{
struct unit_datum *unit = unit_get(player->unit_index);
long weapon_index;
for (weapon_index = 0; weapon_index<MAXIMUM_WEAPONS_PER_UNIT; weapon_index++)
{
long weapon_object_index = unit->unit.weapon_object_indices[weapon_index];
if (weapon_object_index!=NONE && weapon_is_flag(weapon_object_index))
{
has_flag = TRUE;
break;
}
}
}
}
return has_flag;
}
void game_show_score(
long player_index,
long score)
{
game_show_score_extended(player_index, score, NONE);
return;
}
void get_postgame_hilite_colors(
real_argb_color *winner_color,
real_argb_color *normal_color,
real_argb_color *hilite_color)
{
winner_color->red = 0.45882353f;
winner_color->green = 0.7294118f;
winner_color->blue = 1.0f;
winner_color->alpha = 1.0f;
normal_color->red = 1.0f;
normal_color->green = 1.0f;
normal_color->blue = 0.0f;
normal_color->alpha = 1.0f;
get_selected_color(hilite_color);
return;
}
boolean game_engine_running(
void)
{
boolean running = game_engine!=NULL;
return running;
}
/* port: whether the game is over and its scores are shown (where the
host's button starts the next, game_engine_update) */
boolean game_engine_showing_postgame(
void)
{
return game_engine != NULL && game_engine_globals.postgame_state == game_engine_mode_postgame_rasterize;
}
boolean game_engine_force_single_screen(
void)
{
boolean force_single_screen = FALSE;
if (game_engine &&
game_engine_globals.postgame_state>=game_engine_mode_postgame_rasterize_delay &&
game_engine_globals.postgame_state<=game_engine_mode_postgame_rasterize)
{
force_single_screen = TRUE;
}
return force_single_screen;
}
void game_engine_dispose(
void)
{
if (game_engine)
{
if (game_engine->dispose)
game_engine->dispose();
game_engine = NULL;
}
return;
}
static void game_engine_update_player_no_shield(
long player_index)
{
struct player_datum *player;
if (game_engine_has_shield(player_index))
return;
player = player_get(player_index);
if (player->unit_index != NONE)
{
struct unit_datum *unit = unit_get(player->unit_index);
unit->object.shield_vitality = 0.0f;
unit->object.maximum_shield_vitality = 0.0f;
}
return;
}
static void game_engine_build_lighting(
void)
{
long player_count = 0;
long object_count = 0;
{
struct data_iterator iterator;
data_iterator_new(&iterator, player_data);
while (data_iterator_next(&iterator))
player_count++;
}
if (global_variant.universal_variant.vehicle_set != _game_engine_vehicles_none)
{
if (global_variant.game_engine_index == game_engine_race)
{
struct scenario *scenario = global_scenario_get();
short flag_index;
for (flag_index = 0;
flag_index < scenario->netgame_flags.count;
flag_index++)
{
struct scenario_netgame_flag *flag = TAG_BLOCK_GET_ELEMENT(
&scenario->netgame_flags,
flag_index,
struct scenario_netgame_flag);
if (flag->type == _netgame_flag_race_vehicle)
object_count++;
}
if (object_count > player_count)
object_count = player_count;
}
else
{
struct object_iterator object_iterator;
object_iterator_new(
&object_iterator,
_object_mask_vehicle,
0);
while (object_iterator_next(&object_iterator))
object_count++;
}
}
if ((player_count > 8 && object_count >= 2) ||
player_count >= 13)
{
SET_FLAG(game_engine_globals.flags, _game_engine_disable_dynamic_light_bit, TRUE);
}
if (player_count > 4 ||
object_count >= 4 ||
TEST_FLAG(game_engine_globals.flags, _game_engine_disable_dynamic_light_bit))
{
SET_FLAG(game_engine_globals.flags, _game_engine_disable_integrated_lights_bit, TRUE);
}
if (player_count >= 5)
SET_FLAG(game_engine_globals.flags, _game_engine_5_or_more_players_bit, TRUE);
if (player_count >= 9)
SET_FLAG(game_engine_globals.flags, _game_engine_9_or_more_players_bit, TRUE);
return;
}
void game_engine_dispose_from_old_map(
void)
{
if (game_engine && game_engine->dispose_from_old_map)
game_engine->dispose_from_old_map();
return;
}
void game_engine_game_ending(
void)
{
if (game_engine && game_engine->game_ending)
game_engine->game_ending();
return;
}
void game_engine_game_starting(
void)
{
if (game_engine)
{
if (game_engine->game_starting)
game_engine->game_starting();
game_engine_build_lighting();
}
return;
}
void game_engine_statistics_append(
long statistic)
{
if (game_engine && game_engine->statistics_append)
game_engine->statistics_append(statistic);
return;
}
void game_engine_handle_client_message(
void *message)
{
if (game_engine && game_engine->handle_client_message)
game_engine->handle_client_message(message);
return;
}
void game_engine_handle_server_message(
void *message)
{
if (game_engine && game_engine->handle_server_message)
game_engine->handle_server_message(message);
return;
}
void game_engine_post_rasterize_objects(
void)
{
if (game_engine && game_engine->post_rasterize_objects)
game_engine->post_rasterize_objects();
return;
}
void game_engine_post_rasterize(
void)
{
if (game_engine)
{
switch (game_engine_globals.postgame_state)
{
case game_engine_mode_active:
case game_engine_mode_postgame_delay:
game_engine_post_rasterize_in_game();
break;
case game_engine_mode_postgame_rasterize_delay:
case game_engine_mode_postgame_rasterize:
game_engine_post_rasterize_post_game();
break;
default:
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0x7B7,
!"unreachable");
break;
}
}
return;
}
void game_engine_nonplayer_post_rasterize(
void)
{
if (game_engine)
{
switch (game_engine_globals.postgame_state)
{
case game_engine_mode_active:
case game_engine_mode_postgame_delay:
game_engine_press_start_to_begin();
break;
case game_engine_mode_postgame_rasterize_delay:
case game_engine_mode_postgame_rasterize:
{
rectangle2d window_bounds;
long local_player_index;
game_engine_post_rasterize_post_game();
window_bounds.x0 = 0;
window_bounds.x1 = 640;
window_bounds.y0 = 0;
window_bounds.y1 = 480;
for (local_player_index = 0;
local_player_index < MAXIMUM_LOCAL_PLAYERS;
local_player_index++)
{
render_ui_widgets_postgame(
(short)local_player_index,
&window_bounds);
rumble_player_clear((short)local_player_index);
}
}
break;
default:
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0xE3B,
!"unreachable");
break;
}
}
return;
}
static void game_engine_update_teleporter(
long player_index)
{
static int blocked_message_delay = 0;
static long fade_function = 0;
static long screen_flash_type = 6;
static real max_intensity = 1.0f;
static real alpha = 0.5f;
static real red = 0.35f;
static real green = 1.0f;
static real blue = 0.35f;
static real duration = 1.0f;
struct scenario *scenario = global_scenario_get();
struct player_datum *player = player_get(player_index);
struct unit_datum *unit;
struct scenario_netgame_flag *source_flag;
struct scenario_netgame_flag *destination_flag;
real_vector3d forward;
long source_flag_index;
long destination_flag_index;
if (player->unit_index == NONE)
return;
unit = unit_get(player->unit_index);
if (player->teleporter_index != NONE)
{
struct scenario_netgame_flag *previous_flag = TAG_BLOCK_GET_ELEMENT(
&scenario->netgame_flags,
player->teleporter_index,
struct scenario_netgame_flag);
if (distance_squared3d(&previous_flag->position, &unit->object.position) > 1.0f)
player->teleporter_index = NONE;
}
source_flag_index = NONE;
find_netgame_flags(
&unit->object.position,
0.5f,
0.0f,
_netgame_flag_teleporter_source,
NONE,
1,
&source_flag_index);
if (source_flag_index == NONE ||
source_flag_index == player->teleporter_index)
{
return;
}
source_flag = TAG_BLOCK_GET_ELEMENT(
&scenario->netgame_flags,
source_flag_index,
struct scenario_netgame_flag);
destination_flag_index = NONE;
find_netgame_flags(
NULL,
0.0f,
0.0f,
_netgame_flag_teleporter_target,
source_flag->team_index,
1,
&destination_flag_index);
if (destination_flag_index != NONE)
{
destination_flag = TAG_BLOCK_GET_ELEMENT(
&scenario->netgame_flags,
destination_flag_index,
struct scenario_netgame_flag);
{
struct collision_feature_list features;
struct player_datum *unit_player;
real_point3d position;
real height;
real radius;
unit = unit_get(player->unit_index);
forward = unit->object.forward;
unit_player = player_get(player_index);
biped_get_physics_pill(
unit_player->unit_index,
&position,
&height,
&radius);
position = destination_flag->position;
{
struct collision_plane point_test_result;
if (collision_get_features_in_sphere(
0x200380,
&position,
height + radius * 2.0f,
height,
radius,
NONE,
&features) &&
collision_features_test_point(
&features,
&position,
&point_test_result))
{
if (point_test_result.object_index != NONE)
{
if (TEST_FLAG(
_object_mask_unit,
object_get(
point_test_result.object_index)
->object.type))
{
struct unit_datum *blocking_unit = unit_get(
point_test_result.object_index);
if (blocking_unit->unit.player_index != NONE)
{
struct player_datum *blocking_player =
player_get(blocking_unit->unit.player_index);
blocking_player->is_blocking_teleporter = TRUE;
blocking_player->telefrag_timeout++;
}
}
}
if (blocked_message_delay > 0)
{
blocked_message_delay--;
return;
}
blocked_message_delay = 120;
{
long string_list_index =
tag_loaded('ustr', "ui\\multiplayer_game_text");
wchar_t const *message;
if (string_list_index != NONE)
message = unicode_string_list_get_string(
string_list_index,
0x65);
else
message = L"";
hud_print_message(
unit_get_local_player_index(unit_player->unit_index),
message);
}
return;
}
}
}
if (player->local_player_index != NONE)
{
game_engine_play_multiplayer_sound(_multiplayer_sound_teleporter_activate);
if (player->local_player_index != NONE)
{
struct screen_flash_definition screen_flash = { 0 };
screen_flash.fade_function = fade_function;
screen_flash.type = screen_flash_type;
screen_flash.duration = duration;
screen_flash.priority = 2;
screen_flash.max_intensity = max_intensity;
screen_flash.zero_scale_factor = 0.0f;
screen_flash.screen_flash_color.alpha = alpha;
screen_flash.screen_flash_color.red = red;
screen_flash.screen_flash_color.green = green;
screen_flash.screen_flash_color.blue = blue;
player_effect_screen_flash(
player_index,
&screen_flash,
1.0f);
}
}
{
real angle =
arctangent(forward.j, forward.i) +
destination_flag->facing -
source_flag->facing;
forward.i = cosine(angle);
forward.j = sine(angle);
normalize3d(&forward);
object_set_position(
player->unit_index,
&destination_flag->position,
&forward,
NULL);
if (player->local_player_index != NONE)
player_control_set_facing(player->local_player_index, &forward);
player->teleporter_index = find_netgame_flag(
&unit->object.position,
1.0f,
0.0f,
_netgame_flag_teleporter_source,
NONE);
}
return;
}
console_printf(
FALSE,
"failed to teleport %d",
source_flag->team_index);
return;
}
void game_engine_update(
void)
{
if (game_engine)
{
game_engine_update_multiplayer_sound();
game_engine_update_purge();
game_engine_update_weapons();
game_engine_update_item_spawn();
{
struct data_iterator player_iterator;
data_iterator_new(&player_iterator, player_data);
while (data_iterator_next(&player_iterator))
{
game_engine_update_player_no_shield(player_iterator.datum_index);
game_engine_update_player_always_invis(player_iterator.datum_index);
game_engine_update_teleporter(player_iterator.datum_index);
/* (on a client of the distributed netcode each game type
skips what the host decides, whose scores, flags, balls and
hills it has: game_engine_read_network_state) */
if (game_engine->player_update_each_tick)
game_engine->player_update_each_tick(player_iterator.datum_index);
}
}
if (game_engine->update)
game_engine->update();
switch (game_engine_globals.postgame_state)
{
case game_engine_mode_active:
/* (a client of the distributed netcode ends the game when the host
has) */
if (
!network_game_distributed_client() &&
game_engine_should_end_game())
{
game_engine_end_game();
}
break;
case game_engine_mode_postgame_delay:
if (game_engine_globals.postgame_timer <= 2.0f &&
!TEST_FLAG(game_engine_globals.flags, _game_engine_game_over_sound_disabled_bit))
{
sound_class_set_gain("", 0.0f, 30);
sound_class_set_gain("ambient_nature", 0.2f, 30);
sound_class_set_gain("ambient_machinery", 0.2f, 30);
sound_class_set_gain("ambient_computers", 0.2f, 30);
SET_FLAG(game_engine_globals.flags, _game_engine_game_over_sound_disabled_bit, TRUE);
}
game_engine_globals.postgame_timer -= 1.0f / TICKS_PER_SECOND;
if (game_engine_globals.postgame_timer <= 0.0f)
{
struct network_game_server *server;
game_engine_globals.postgame_progress = 0.0f;
game_engine_globals.postgame_state = game_engine_mode_postgame_rasterize_delay;
game_engine_globals.postgame_timer = 5.0f;
{
struct data_iterator player_iterator;
struct player_datum *player;
data_iterator_new(&player_iterator, player_data);
player = (struct player_datum *)data_iterator_next(&player_iterator);
while (player)
{
if (player->unit_index != NONE)
unit_kill(player->unit_index);
if (player->local_player_index != NONE)
rumble_player_clear(player->local_player_index);
player = (struct player_datum *)data_iterator_next(&player_iterator);
}
}
{
struct object_iterator object_iterator;
object_iterator_new(
&object_iterator,
_object_mask_vehicle,
0);
while (object_iterator_next(&object_iterator))
{
object_delete(object_iterator.index);
}
}
server = global_network_game_server_get();
if (server)
network_game_server_switch_to_postgame(
global_network_game_server_get());
}
break;
case game_engine_mode_postgame_rasterize_delay:
case game_engine_mode_postgame_rasterize:
break;
default:
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0xA03,
!"unreachable");
break;
}
}
return;
}
enum game_engine_message
{
_game_engine_message_welcome = 0,
_game_engine_message_killed_by_unknown,
_game_engine_message_killed_by_biped,
_game_engine_message_killed_by_vehicle,
_game_engine_message_killed_by_player,
_game_engine_message_killed_by_friendly_fire,
_game_engine_message_killed_by_self,
_game_engine_message_double_kill,
_game_engine_message_killed_enemy,
_game_engine_message_triple_kill,
_game_engine_message_multi_kill,
_game_engine_message_five_kills_in_row,
_game_engine_message_ten_kills_in_a_row,
_game_engine_message_killed_friendly,
_game_engine_message_multi_kill_with_score,
_game_engine_message_triple_kill_with_score,
_game_engine_message_double_kill_with_score,
_game_engine_message_ten_kills_in_a_row_with_score,
_game_engine_message_five_kills_in_row_with_score,
_game_engine_message_killed_enemy_with_score,
_game_engine_message_winner,
_game_engine_message_team_winner,
_game_engine_message_show_score,
_game_engine_message_odd_man_out,
_game_engine_message_out_of_lives,
_game_engine_message_respawn_timer,
_game_engine_message_waiting_for_space_to_clear,
_game_engine_message_player_quit_self,
_game_engine_message_quit,
_game_engine_message_press_back_for_score,
_game_engine_message_time_left,
NUMBER_OF_GAME_ENGINE_MESSAGES,
};
enum
{
_equipment_created_at_rest_bit = 0,
};
void game_engine_player_killed(
long killing_player_index,
long killing_object_index,
long dead_player_index,
boolean friendly_fire)
{
struct player_datum *dead_player = player_get(dead_player_index);
boolean player_kill;
boolean same_player;
boolean valid_players;
long message = NONE;
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0xA31,
dead_player_index != NONE);
if (!game_engine)
return;
/* the distributed netcode: a client's copy of a death has the host's
killer (port/linux/game/network_distributed.c) */
network_distributed_player_killed(&killing_player_index, &killing_object_index, dead_player_index,
&friendly_fire);
/* the host's kill of a player who quit, ahead of this client's clock
(game_update_quit_players has not come to its time yet) */
if (network_game_distributed_client() && dead_player->quit_out_of_game_time != NONE &&
killing_player_index == dead_player_index)
{
dead_player->quit_out_of_game = TRUE;
}
dead_player->death_time = game_time_get();
if (game_engine->player_killed_player)
{
game_engine->player_killed_player(
killing_player_index,
killing_object_index,
dead_player_index,
friendly_fire);
}
same_player = killing_player_index == dead_player_index;
if (killing_player_index != NONE && dead_player_index != NONE)
valid_players = TRUE;
else
valid_players = FALSE;
player_kill = !friendly_fire && valid_players && !same_player;
dead_player->respawn_timer =
dead_player->respawn_penalty + global_variant.universal_variant.respawn_time;
if (global_variant.universal_variant.respawn_time_growth > 0)
{
dead_player->respawn_penalty += global_variant.universal_variant.respawn_time_growth;
dead_player->respawn_penalty =
MIN(
dead_player->respawn_penalty,
global_variant.universal_variant.respawn_time_growth * 5);
if (player_kill && killing_player_index != NONE)
{
struct player_datum *killing_player =
player_get(killing_player_index);
killing_player->respawn_penalty -= global_variant.universal_variant.respawn_time_growth;
killing_player->respawn_penalty =
MAX(killing_player->respawn_penalty, 0);
}
}
if (!player_kill)
dead_player->respawn_timer += global_variant.universal_variant.suicide_penalty;
dead_player->respawn_timer = MAX(dead_player->respawn_timer, 90);
dead_player = player_get(dead_player_index);
if (!dead_player->quit_out_of_game)
{
if (killing_player_index == NONE)
{
if (killing_object_index == NONE)
message = _game_engine_message_killed_by_unknown;
else
{
struct object_datum *object = object_get(killing_object_index);
unit_try_and_get(killing_object_index);
switch (object->object.type)
{
case _object_type_biped:
message = _game_engine_message_killed_by_biped;
break;
case _object_type_vehicle:
message = _game_engine_message_killed_by_vehicle;
break;
default:
message = _game_engine_message_killed_by_unknown;
break;
}
}
}
else if (killing_player_index == dead_player_index)
message = _game_engine_message_killed_by_self;
else
message =
_game_engine_message_killed_by_player + (friendly_fire != FALSE);
game_show_score_extended(
dead_player_index,
message,
killing_player_index);
}
else
{
struct data_iterator iterator;
data_iterator_new(&iterator, player_data);
while (data_iterator_next(&iterator))
{
multiplayer_message(
iterator.datum_index,
_game_engine_message_quit,
dead_player_index);
}
}
if (message == _game_engine_message_killed_by_friendly_fire)
{
if (killing_player_index != NONE)
{
multiplayer_message(
killing_player_index,
_game_engine_message_killed_friendly,
dead_player_index);
}
else
{
struct data_iterator iterator;
data_iterator_new(&iterator, player_data);
while (data_iterator_next(&iterator))
{
multiplayer_message(
iterator.datum_index,
_game_engine_message_killed_friendly,
dead_player_index);
}
}
}
else if (message == _game_engine_message_killed_by_player)
{
struct player_datum *killing_player =
player_get(killing_player_index);
if (killing_player->statistics.multiple_kills >= 4)
{
message = _game_engine_message_multi_kill;
}
else if (killing_player->statistics.multiple_kills == 3)
message = _game_engine_message_triple_kill;
else if (killing_player->statistics.multiple_kills == 2)
message = _game_engine_message_double_kill;
else if (killing_player->statistics.kills_in_a_row == 5)
message = _game_engine_message_five_kills_in_row;
else
{
message = (killing_player->statistics.kills_in_a_row % 5)
? _game_engine_message_killed_enemy
: _game_engine_message_ten_kills_in_a_row;
}
game_show_score_extended(
killing_player_index,
message,
dead_player_index);
}
return;
}
void game_engine_update_non_deterministic(
real delta_seconds)
{
if (game_engine)
{
switch (game_engine_globals.postgame_state)
{
case game_engine_mode_postgame_rasterize_delay:
rumble_clear_all_now();
game_engine_globals.postgame_timer -= delta_seconds;
if (game_engine_globals.postgame_timer <= 0.0f)
game_engine_globals.postgame_state = game_engine_mode_postgame_rasterize;
break;
case game_engine_mode_postgame_rasterize:
rumble_clear_all_now();
game_engine_globals.postgame_progress += delta_seconds;
if (game_engine_globals.postgame_progress > 1.0f)
game_engine_globals.postgame_progress = 1.0f;
if (test_any_gamepad_button(0) || test_any_gamepad_button(12))
{
if (global_network_game_server_get())
network_game_server_reset_to_pregame(
global_network_game_server_get());
}
else if (test_any_gamepad_button(1) || test_any_gamepad_button(13))
{
network_game_abort();
}
break;
}
}
return;
}
boolean game_engine_display_team_indicators(
void)
{
boolean display = FALSE;
if (game_engine)
display = TEST_FLAG(global_variant.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit) && global_variant.universal_variant.teams;
return display;
}
boolean game_engine_can_score(
void)
{
boolean can_score = TRUE;
if (game_engine)
can_score = game_engine_globals.postgame_state==game_engine_mode_active;
return can_score;
}
boolean game_engine_infinite_grenades(
long player_index)
{
boolean infinite_grenades = FALSE;
if (game_engine_running() && player_index!=NONE)
infinite_grenades = game_engine_infinite_grenades_internal();
return infinite_grenades;
}
boolean game_engine_has_shield(
long player_index)
{
boolean has_shield = TRUE;
if (game_engine && player_index!=NONE)
has_shield = !TEST_FLAG(global_variant.universal_variant.flags, _game_variant_no_shields_bit);
return has_shield;
}
boolean game_engine_draw_object_in_motion_sensor(
long unit_index)
{
boolean draw_object = TRUE;
if (game_engine)
draw_object = TEST_FLAG(global_variant.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit);
return draw_object;
}
boolean game_engine_hud_draw_motion_sensor(
long player_index)
{
boolean draw_motion_sensor = TRUE;
if (game_engine)
{
boolean default_draw_motion_sensor;
draw_motion_sensor =
TEST_FLAG(global_variant.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit);
default_draw_motion_sensor = global_variant.universal_variant.goal_radar == _radar_motion_tracker;
if (global_variant.game_engine_index == game_engine_slayer && !global_variant.game_engine_variant.slayer.kill_in_order)
default_draw_motion_sensor = FALSE;
draw_motion_sensor |= default_draw_motion_sensor;
}
return draw_motion_sensor;
}
boolean game_engine_player_has_stealth_weapon(
long player_index)
{
boolean has_stealth_weapon = FALSE;
if (player_index != NONE)
{
struct player_datum *player = player_get(player_index);
if (player->unit_index != NONE)
{
struct unit_datum *unit = unit_get(player->unit_index);
long current_weapon_index = unit->unit.current_weapon_index;
if (current_weapon_index != NONE)
{
long weapon_index =
unit->unit.weapon_object_indices[current_weapon_index];
if (weapon_index != NONE)
{
struct weapon_datum *weapon = weapon_get(weapon_index);
if (weapon->definition_index != NONE)
{
struct weapon_definition *weapon_definition =
weapon_definition_get(weapon->definition_index);
has_stealth_weapon = TEST_FLAG(
weapon_definition->weapon.flags,
_weapon_does_not_depower_active_camo_bit);
}
}
}
}
}
return has_stealth_weapon;
}
void game_engine_weapon_fired(
long player_index)
{
if (game_engine && player_index != NONE)
{
struct player_datum *player = player_get(player_index);
long unit_index = player->unit_index;
if (unit_index != NONE)
{
struct unit_datum *unit = unit_get(unit_index);
long weapon_index = unit_inventory_get_weapon(
unit_index,
unit_get(unit_index)->unit.current_weapon_index);
real active_camouflage_decrease = 0.1f;
if (game_engine_player_has_stealth_weapon(player_index))
{
active_camouflage_decrease = 0.0f;
}
else if (weapon_index != NONE)
{
struct weapon_datum *weapon = weapon_get(weapon_index);
struct weapon_definition *weapon_definition =
weapon_definition_get(weapon->definition_index);
if (0.0f != weapon_definition->weapon.active_camo_ding)
active_camouflage_decrease =
weapon_definition->weapon.active_camo_ding;
}
if (unit->unit.active_camouflage >= 0.05f)
{
unit->unit.active_camouflage -= active_camouflage_decrease;
unit->unit.cause_for_camo_regrowth = 1;
unit->unit.active_camouflage =
MAX(0.05f, unit->unit.active_camouflage);
}
}
}
return;
}
wchar_t *get_place_name(
struct game_engine_place place)
{
long lookup_index;
long string_list_index;
/* port: a session can have more places than the string list names */
match_vassert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0x1316,
place.place < MULTIPLAYER_MAXIMUM_PLAYERS,
"place.place < maximum_places");
if (TEST_FLAG(place.flags, _place_two_groups) && TEST_FLAG(place.flags, _place_tied))
lookup_index = 35;
else if (TEST_FLAG(place.flags, _place_two_groups) && place.place == 0)
lookup_index = 33;
else if (TEST_FLAG(place.flags, _place_two_groups) && place.place == 1)
lookup_index = 34;
else if (TEST_FLAG(place.flags, _place_all_tied))
lookup_index = 32;
/* port: places past the 16th are spelled out; a tie is marked like the
string list's tied places */
else if (place.place >= NUMBER_OF_PLACE_STRINGS)
return place_ordinal_string(place.place, TEST_FLAG(place.flags, _place_tied));
else
{
lookup_index = place.place;
if (TEST_FLAG(place.flags, _place_tied))
lookup_index += 16;
}
match_vassert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0x1331,
lookup_index != NONE,
"NONE != lookup_index");
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
return unicode_string_list_get_string(
string_list_index,
lookup_index + 0x66);
return L"";
}
long find_netgame_flags(
real_point3d const *position,
real radius,
real height,
short type,
short team_index,
long maximum_count,
long *flag_indices)
{
real radius_squared = radius * radius;
long found_count = 0;
short flag_index;
struct scenario *scenario;
scenario = global_scenario_get();
for (flag_index = 0; flag_index < scenario->netgame_flags.count; flag_index++)
{
struct scenario_netgame_flag *flag = TAG_BLOCK_GET_ELEMENT(
&scenario->netgame_flags,
flag_index,
struct scenario_netgame_flag);
if (type != NONE && type != flag->type)
continue;
if (team_index != NONE && team_index != flag->team_index)
continue;
if (position)
{
if (radius >= 0.0f &&
distance_squared3d(&flag->position, position) > radius_squared)
{
continue;
}
if (height > 0.0f &&
fabs(flag->position.z - position->z) > height)
{
continue;
}
}
if (found_count < maximum_count)
flag_indices[found_count++] = flag_index;
}
return found_count;
}
long find_netgame_flag(
real_point3d const *position,
real radius,
real height,
short type,
short team_index)
{
long flag_index = NONE;
find_netgame_flags(
position,
radius,
height,
type,
team_index,
1,
&flag_index);
return flag_index;
}
/* playlist data: in the Aug-15-2001 build the playlist functions were the only users of these two globals;
this build no longer reads them. their definition point here, with the playlist code, is inferred (the
Aug-2001 users and the later builds' layout), not attested */
void *global_autogenerate_list = NULL;
long global_autogenerate_count = 0;
void game_engine_playlist_next(
long parameter0,
long parameter1,
long playlist_type)
{
char *map_name;
struct game_variant variant;
csstrcpy(global_stage.map_name, "levels\\test\\carousel\\carousel");
map_name = main_get_multiplayer_map_name();
if (map_name && map_name[0])
{
csstrncpy(global_stage.map_name, map_name, sizeof(global_stage.map_name) - 1);
global_stage.map_name[sizeof(global_stage.map_name) - 1] = 0;
}
if (player_ui_game_variant_specified(&variant))
csmemcpy(&global_stage.variant, &variant, sizeof(global_stage.variant));
return;
}
boolean game_engine_should_end_game(
void)
{
boolean should_end_game = FALSE;
if (game_engine && !multiple_teams_alive())
should_end_game = TRUE;
return should_end_game;
}
void game_engine_clear_goal_position(
short goal_index)
{
/* port: a goal of the table only */
if (!VALID_INDEX(goal_index, NUMBEROF(global_goal)))
return;
csmemset(&global_goal[goal_index], 0, sizeof(struct netgame_goal));
return;
}
long get_flag_definition_index(
void)
{
struct game_globals *game_globals;
struct game_globals_multiplayer_information *multiplayer_information;
global_scenario_get();
game_globals = scenario_get_game_globals();
multiplayer_information = TAG_BLOCK_GET_ELEMENT(
&game_globals->multiplayer_information,
0,
struct game_globals_multiplayer_information);
return multiplayer_information->flag.index;
}
long get_ball_definition_index(
void)
{
struct game_globals *game_globals;
struct game_globals_multiplayer_information *multiplayer_information;
global_scenario_get();
game_globals = scenario_get_game_globals();
multiplayer_information = TAG_BLOCK_GET_ELEMENT(
&game_globals->multiplayer_information,
0,
struct game_globals_multiplayer_information);
return multiplayer_information->ball.index;
}
void game_engine_override_map_name(
char const *map_name)
{
if (map_name && map_name[0])
csstrncpy(global_stage.map_name, map_name, sizeof(global_stage.map_name)-1);
return;
}
void game_engine_override_game_variant(
struct game_variant const *variant)
{
if (variant)
csmemcpy(&global_stage.variant, variant, sizeof(global_stage.variant));
return;
}
void game_engine_switch_to_postgame(
void)
{
if (game_engine_globals.postgame_state==game_engine_mode_active)
{
if (global_network_game_server_get())
{
game_engine_globals.postgame_state = game_engine_mode_postgame_delay;
game_engine_globals.postgame_timer = 7.0f;
}
else
{
game_engine_globals.postgame_state = game_engine_mode_postgame_rasterize;
}
}
return;
}
void game_engine_load_stage(
char const *map_name)
{
if (!map_name || csstrcmp(global_stage.map_name, map_name))
main_set_multiplayer_map_name(global_stage.map_name);
game_set_game_variant(&global_stage.variant);
if (!network_game_is_active())
main_reset_map();
return;
}
void game_engine_end_game(
void)
{
if (game_engine_globals.postgame_state==game_engine_mode_active)
{
game_engine_globals.postgame_state = game_engine_mode_postgame_delay;
game_engine_globals.postgame_timer = 7.0f;
game_engine_play_multiplayer_sound(_multiplayer_sound_game_over);
ui_widgets_close_all();
}
return;
}
void game_engine_player_damaged_player(
long damaging_player_index,
long dead_player_index,
boolean damage_type)
{
match_assert("c:\\halo\\SOURCE\\game\\game_engine.c", 0xA20, dead_player_index != NONE);
/* (a client of the distributed netcode replaying the host's damage has
the host's game type state, game_engine_read_network_state) */
if (network_game_distributed_client())
return;
if (game_engine && game_engine->player_damaged_player)
game_engine->player_damaged_player(damaging_player_index, dead_player_index, damage_type);
return;
}
static boolean game_engine_player_is_odd_man_out(
long player_index)
{
struct player_datum *player = player_get(player_index);
boolean result = FALSE;
if (global_variant.universal_variant.odd_man_out && player->unit_index==NONE)
{
struct data_iterator iterator;
struct player_datum *other_player;
result = TRUE;
data_iterator_new(&iterator, player_data);
other_player = (struct player_datum *)data_iterator_next(&iterator);
while (other_player)
{
if (other_player->unit_index==NONE &&
other_player!=player &&
(other_player->death_time>player->death_time ||
(other_player->death_time==player->death_time &&
DATUM_INDEX_TO_ABSOLUTE_INDEX(player_index)<
DATUM_INDEX_TO_ABSOLUTE_INDEX(iterator.datum_index))))
{
result = FALSE;
}
other_player = (struct player_datum *)data_iterator_next(&iterator);
}
}
return result;
}
boolean game_engine_player_is_out_of_lives(
long player_index)
{
boolean out_of_lives = FALSE;
if (global_variant.universal_variant.lives>0)
{
struct player_datum *player = player_get(player_index);
if (player->unit_index==NONE && player->statistics.deaths>=global_variant.universal_variant.lives)
out_of_lives = TRUE;
}
return out_of_lives;
}
short game_engine_player_get_custom_motion_sensor_positions(
long player_index,
real_point2d *positions,
byte *goal_indices,
short maximum_count)
{
short count = 0;
if (game_engine && global_variant.universal_variant.goal_radar == _radar_motion_tracker && player_index != NONE)
{
struct player_datum *player = player_get(player_index);
long goal_index;
/* port: every goal, one per player in the native builds' sessions */
for (goal_index = 0; goal_index < (long)NUMBEROF(global_goal); goal_index++)
{
struct netgame_goal *goal = &global_goal[goal_index];
if (goal_matches_player(player, player_index, goal_index) && count < maximum_count)
{
goal_indices[count] = goal_index;
positions[count].x = goal->position.x;
positions[count].y = goal->position.y;
count++;
}
}
}
return count;
}
void game_engine_render_nav_points(
short local_player_index)
{
if (game_engine &&
global_variant.universal_variant.goal_radar == _radar_nav_point &&
local_player_index != NONE)
{
long player_index = local_player_get_player_index(local_player_index);
if (player_index != NONE)
{
struct player_datum *player = player_get(player_index);
long goal_index;
if (player->unit_index != NONE)
{
real_point3d head_position;
unit_get_head_position(player->unit_index, &head_position);
/* port: every goal, one per player in the native builds' sessions */
for (goal_index = 0; goal_index < (long)NUMBEROF(global_goal); goal_index++)
{
if (goal_matches_player(player, player_index, goal_index))
{
short render_type = hud_get_nav_point_render_type(
local_player_index,
&head_position,
&global_goal[goal_index].position,
NONE);
custom_render_nav_point(
local_player_index,
&global_goal[goal_index].position,
global_goal[goal_index].nav_index,
render_type);
}
}
}
}
}
return;
}
boolean game_engine_hud_draw_messages(
long player_index)
{
boolean draw_messages = TRUE;
if (game_engine && player_index!=NONE)
{
struct player_datum *player = player_get(player_index);
if (player->local_player_index!=NONE &&
game_engine_globals.hud_message_timers[player->local_player_index]>0.0f)
{
draw_messages = FALSE;
}
}
return draw_messages;
}
boolean game_engine_force_autopickup(
long unit_index,
long weapon_index)
{
boolean force_autopickup = FALSE;
if (game_engine && global_variant.game_engine_index==game_engine_ctf && weapon_is_flag(weapon_index))
force_autopickup = TRUE;
return force_autopickup;
}
boolean game_engine_allow_pick_up(
long unit_index,
long weapon_index)
{
boolean allow_pick_up = TRUE;
if (game_engine && game_engine->allow_pick_up)
allow_pick_up = game_engine->allow_pick_up(unit_index, weapon_index);
return allow_pick_up;
}
boolean game_engine_picking_up(
long unit_index,
long weapon_index)
{
boolean allow_pick_up = TRUE;
if (game_engine)
{
struct weapon_datum *weapon = weapon_try_and_get(weapon_index);
if (weapon && weapon_is_flag(weapon_index))
{
if (TEST_FLAG(weapon->weapon.flags, _weapon_runtime_game_engine_active_bit))
{
SET_FLAG(weapon->weapon.flags, _weapon_runtime_game_engine_active_bit, FALSE);
if (game_engine->weapon_dropped)
game_engine->weapon_dropped(weapon_index);
}
SET_FLAG(weapon->weapon.flags, _weapon_runtime_game_engine_active_bit, TRUE);
if (game_engine->picking_up)
{
long player_index = player_index_from_unit_index(unit_index);
allow_pick_up = game_engine->picking_up(
weapon_index,
player_index);
}
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0xF58,
!allow_pick_up ||
!TEST_FLAG(weapon->weapon.flags, _weapon_must_be_readied_bit) ||
!unit_has_weapon_with_flag(unit_index, _weapon_must_be_readied_bit));
}
}
return allow_pick_up;
}
boolean game_engine_test_flag(
long flag)
{
boolean result = FALSE;
if (game_engine && game_engine->test_flag)
result = game_engine->test_flag(flag);
return result;
}
boolean game_engine_test_trait(
long trait,
long value)
{
boolean result = FALSE;
if (game_engine && game_engine->test_trait)
result = game_engine->test_trait(trait, value);
return result;
}
void game_engine_prespawn_player_update(
long player_index)
{
if (game_engine)
{
if (game_engine->prespawn_player_update)
game_engine->prespawn_player_update(player_index);
else
{
struct player_datum *player = player_get(player_index);
/* port: 0 or 1 (another machine's player has no local player: -1) */
player->team_index = PIN(player->local_player_index % 2, 0, 1);
}
}
return;
}
static struct statistic_buffer game_engine_get_player_place(
long player_index)
{
struct statistic_buffer statistic_buffer[MULTIPLAYER_MAXIMUM_PLAYERS];
long place = 0;
populate_statistic_buffer(statistic_buffer, _postgame_statistic_ranking, FALSE);
while (TRUE)
{
if (statistic_buffer[place].player_index == player_index)
break;
place++;
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0x362,
place<MULTIPLAYER_MAXIMUM_PLAYERS);
}
return statistic_buffer[place];
}
struct game_variant *build_game_variant_king(
struct game_variant *variant)
{
struct game_variant result = { 0 };
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, FALSE);
result.universal_variant.goal_radar = _radar_nav_point;
result.universal_variant.respawn_time = 150;
result.universal_variant.score_to_win = 2;
result.flags = 1;
result.universal_variant.suicide_penalty = 150;
result.universal_variant.vehicle_set = _game_engine_vehicles_warthog;
result.game_engine_index = game_engine_king;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.teams = FALSE;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
result.game_engine_variant.king.moving_hill = FALSE;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_crazy_king(
struct game_variant *variant)
{
struct game_variant result = { 0 };
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, FALSE);
result.universal_variant.goal_radar = _radar_nav_point;
result.universal_variant.score_to_win = 2;
result.game_engine_variant.king.moving_hill = TRUE;
result.universal_variant.vehicle_set = _game_engine_vehicles_warthog;
result.flags = 1;
result.game_engine_index = game_engine_king;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time = 0;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.suicide_penalty = 150;
result.universal_variant.teams = FALSE;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_slayer(
struct game_variant *variant)
{
struct game_variant result = { 0 };
result.game_engine_index = game_engine_slayer;
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, FALSE);
result.universal_variant.vehicle_set = _game_engine_vehicles_warthog;
result.universal_variant.goal_radar = _radar_motion_tracker;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time = 0;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.score_to_win = 15;
result.universal_variant.suicide_penalty = 300;
result.universal_variant.teams = FALSE;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
result.game_engine_variant.slayer.no_death_bonus = FALSE;
result.game_engine_variant.slayer.no_kill_penalty = FALSE;
result.game_engine_variant.slayer.kill_in_order = FALSE;
result.flags = 1;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_team_slayer(
struct game_variant *variant)
{
struct game_variant result = { 0 };
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, FALSE);
result.universal_variant.respawn_time = 300;
result.universal_variant.suicide_penalty = 300;
result.game_engine_index = game_engine_slayer;
result.universal_variant.teams = TRUE;
result.universal_variant.vehicle_set = _game_engine_vehicles_warthog;
result.flags = 1;
result.universal_variant.goal_radar = _radar_motion_tracker;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.score_to_win = 50;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
result.game_engine_variant.slayer.no_death_bonus = FALSE;
result.game_engine_variant.slayer.no_kill_penalty = FALSE;
result.game_engine_variant.slayer.kill_in_order = FALSE;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_elimination(
struct game_variant *variant)
{
struct game_variant result = { 0 };
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, FALSE);
result.game_engine_index = game_engine_slayer;
result.universal_variant.lives = 1;
result.universal_variant.vehicle_set = _game_engine_vehicles_warthog;
result.flags = 1;
result.universal_variant.goal_radar = _radar_motion_tracker;
result.universal_variant.health = 1.0f;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time = 0;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.score_to_win = 25;
result.universal_variant.suicide_penalty = 300;
result.universal_variant.teams = FALSE;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
result.game_engine_variant.slayer.no_death_bonus = FALSE;
result.game_engine_variant.slayer.no_kill_penalty = FALSE;
result.game_engine_variant.slayer.kill_in_order = FALSE;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_phantoms(
struct game_variant *variant)
{
struct game_variant result = { 0 };
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, FALSE);
result.game_engine_index = game_engine_slayer;
result.universal_variant.respawn_time = 150;
result.universal_variant.goal_radar = _radar_nav_point;
result.universal_variant.vehicle_set = _game_engine_vehicles_warthog;
result.universal_variant.suicide_penalty = 150;
result.game_engine_variant.slayer.no_death_bonus = TRUE;
result.game_engine_variant.slayer.no_kill_penalty = TRUE;
result.game_engine_variant.slayer.kill_in_order = TRUE;
result.flags = 1;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.score_to_win = 10;
result.universal_variant.teams = FALSE;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_endurance(
struct game_variant *variant)
{
struct game_variant result = { 0 };
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, FALSE);
result.game_engine_index = game_engine_slayer;
result.universal_variant.odd_man_out = TRUE;
result.universal_variant.respawn_time_growth = 300;
result.universal_variant.vehicle_set = _game_engine_vehicles_warthog;
result.flags = 1;
result.universal_variant.suicide_penalty = 300;
result.universal_variant.goal_radar = _radar_motion_tracker;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 5;
result.universal_variant.respawn_time = 0;
result.universal_variant.score_to_win = 10;
result.universal_variant.teams = FALSE;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
result.game_engine_variant.slayer.no_death_bonus = FALSE;
result.game_engine_variant.slayer.no_kill_penalty = FALSE;
result.game_engine_variant.slayer.kill_in_order = FALSE;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_rockets(
struct game_variant *variant)
{
struct game_variant result = { 0 };
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, TRUE);
result.game_engine_index = game_engine_slayer;
result.universal_variant.goal_radar = _radar_nav_point;
result.universal_variant.vehicle_set = _game_engine_vehicles_warthog;
result.flags = 1;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time = 0;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.score_to_win = 25;
result.universal_variant.suicide_penalty = 300;
result.universal_variant.teams = FALSE;
result.universal_variant.weapon_set = _game_engine_weapons_rocket_launchers;
result.game_engine_variant.slayer.no_death_bonus = FALSE;
result.game_engine_variant.slayer.no_kill_penalty = FALSE;
result.game_engine_variant.slayer.kill_in_order = FALSE;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_snipers(
struct game_variant *variant)
{
struct game_variant result = { 0 };
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, TRUE);
result.game_engine_index = game_engine_slayer;
result.universal_variant.goal_radar = _radar_nav_point;
result.universal_variant.vehicle_set = _game_engine_vehicles_warthog;
result.flags = 1;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time = 0;
result.universal_variant.respawn_time_growth = 150;
result.universal_variant.score_to_win = 15;
result.universal_variant.suicide_penalty = 300;
result.universal_variant.teams = FALSE;
result.universal_variant.weapon_set = _game_engine_weapons_sniping;
result.game_engine_variant.slayer.no_death_bonus = FALSE;
result.game_engine_variant.slayer.no_kill_penalty = FALSE;
result.game_engine_variant.slayer.kill_in_order = FALSE;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_oddball(
struct game_variant *variant)
{
struct game_variant result = { 0 };
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, FALSE);
result.universal_variant.respawn_time = 150;
result.universal_variant.goal_radar = _radar_nav_point;
result.universal_variant.suicide_penalty = 150;
result.universal_variant.vehicle_set = _game_engine_vehicles_none;
result.game_engine_variant.oddball.ball_spawn_count = 1;
result.game_engine_variant.oddball.ball_spawn_delay = TRUE;
result.flags = 1;
result.game_engine_index = game_engine_oddball;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.score_to_win = 2;
result.universal_variant.teams = FALSE;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
result.game_engine_variant.oddball.random_start = FALSE;
result.game_engine_variant.oddball.oddball_ball_type = 0;
result.game_engine_variant.oddball.trait_with_ball = 0;
result.game_engine_variant.oddball.trait_without_ball = 0;
result.game_engine_variant.oddball.speed_with_ball = 0;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_team_oddball(
struct game_variant *variant)
{
struct game_variant result;
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, TRUE);
result.universal_variant.goal_radar = _radar_nav_point;
result.universal_variant.lives = 0;
result.universal_variant.teams = TRUE;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.vehicle_set = _game_engine_vehicles_none;
result.universal_variant.respawn_time_growth = 0;
result.game_engine_variant.oddball.ball_spawn_count = 1;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
result.flags = 1;
result.game_engine_variant.oddball.ball_spawn_delay = FALSE;
result.game_engine_variant.oddball.random_start = FALSE;
result.game_engine_variant.oddball.oddball_ball_type = 0;
result.game_engine_variant.oddball.trait_with_ball = 0;
result.game_engine_variant.oddball.trait_without_ball = 0;
result.game_engine_variant.oddball.speed_with_ball = 0;
result.game_engine_index = game_engine_oddball;
result.universal_variant.health = 1.0f;
result.universal_variant.respawn_time = 300;
result.universal_variant.score_to_win = 2;
result.universal_variant.suicide_penalty = 150;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_reverse_tag(
struct game_variant *variant)
{
struct game_variant result = { 0 };
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, FALSE);
result.universal_variant.respawn_time = 150;
result.universal_variant.goal_radar = _radar_nav_point;
result.universal_variant.suicide_penalty = 150;
result.universal_variant.vehicle_set = _game_engine_vehicles_none;
result.game_engine_variant.oddball.ball_spawn_count = 1;
result.game_engine_variant.oddball.ball_spawn_delay = TRUE;
result.game_engine_variant.oddball.oddball_ball_type = 1;
result.flags = 1;
result.game_engine_index = game_engine_oddball;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.score_to_win = 2;
result.universal_variant.teams = FALSE;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
result.game_engine_variant.oddball.random_start = FALSE;
result.game_engine_variant.oddball.trait_with_ball = 0;
result.game_engine_variant.oddball.trait_without_ball = 0;
result.game_engine_variant.oddball.speed_with_ball = 0;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_accumulation(
struct game_variant *variant)
{
struct game_variant result = { 0 };
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, FALSE);
result.universal_variant.respawn_time = 150;
result.universal_variant.suicide_penalty = 150;
result.universal_variant.vehicle_set = _game_engine_vehicles_none;
result.game_engine_variant.oddball.oddball_ball_type = 1;
result.flags = 1;
result.game_engine_index = game_engine_oddball;
result.universal_variant.goal_radar = _radar_none;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.score_to_win = 5;
result.universal_variant.teams = FALSE;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
result.game_engine_variant.oddball.ball_spawn_count = 16;
result.game_engine_variant.oddball.ball_spawn_delay = FALSE;
result.game_engine_variant.oddball.random_start = FALSE;
result.game_engine_variant.oddball.trait_with_ball = 0;
result.game_engine_variant.oddball.trait_without_ball = 0;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_juggernaut(
struct game_variant *variant)
{
struct game_variant result = { 0 };
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, FALSE);
result.universal_variant.respawn_time = 150;
result.universal_variant.suicide_penalty = 150;
result.universal_variant.goal_radar = _radar_nav_point;
result.universal_variant.vehicle_set = _game_engine_vehicles_warthog;
result.game_engine_variant.oddball.ball_spawn_count = 1;
result.game_engine_variant.oddball.trait_with_ball = 2;
result.flags = 1;
result.game_engine_variant.oddball.oddball_ball_type = 2;
result.game_engine_index = game_engine_oddball;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.score_to_win = 10;
result.universal_variant.teams = FALSE;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
result.game_engine_variant.oddball.ball_spawn_delay = FALSE;
result.game_engine_variant.oddball.random_start = FALSE;
result.game_engine_variant.oddball.trait_without_ball = 0;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_stalker(
struct game_variant *variant)
{
struct game_variant result = { 0 };
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, FALSE);
result.universal_variant.respawn_time = 150;
result.universal_variant.suicide_penalty = 150;
result.game_engine_variant.oddball.ball_spawn_count = 1;
result.game_engine_index = game_engine_oddball;
result.game_engine_variant.oddball.trait_with_ball = 1;
result.game_engine_variant.oddball.trait_without_ball = 3;
result.flags = 1;
result.universal_variant.vehicle_set = _game_engine_vehicles_warthog;
result.game_engine_variant.oddball.oddball_ball_type = 2;
result.game_engine_variant.oddball.speed_with_ball = 2;
result.universal_variant.goal_radar = _radar_motion_tracker;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.score_to_win = 10;
result.universal_variant.teams = FALSE;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
result.game_engine_variant.oddball.ball_spawn_delay = FALSE;
result.game_engine_variant.oddball.random_start = FALSE;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_king_pro(
struct game_variant *variant)
{
struct game_variant result = { 0 };
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, TRUE);
result.universal_variant.goal_radar = _radar_nav_point;
result.universal_variant.score_to_win = 2;
result.flags = 1;
result.universal_variant.vehicle_set = _game_engine_vehicles_warthog;
result.game_engine_index = game_engine_king;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time = 300;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.suicide_penalty = 450;
result.universal_variant.teams = FALSE;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
result.game_engine_variant.king.moving_hill = FALSE;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_team_king(
struct game_variant *variant)
{
struct game_variant result = { 0 };
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, FALSE);
result.universal_variant.score_to_win = 2;
result.universal_variant.goal_radar = _radar_nav_point;
result.universal_variant.vehicle_set = _game_engine_vehicles_warthog;
result.universal_variant.teams = TRUE;
result.game_engine_variant.king.moving_hill = TRUE;
result.flags = 1;
result.game_engine_index = game_engine_king;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time = 300;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.suicide_penalty = 150;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_slayer_pro(
struct game_variant *variant)
{
struct game_variant result = { 0 };
result.game_engine_index = game_engine_slayer;
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, TRUE);
result.universal_variant.vehicle_set = _game_engine_vehicles_warthog;
result.game_engine_variant.slayer.no_death_bonus = TRUE;
result.game_engine_variant.slayer.no_kill_penalty = TRUE;
result.flags = 1;
result.universal_variant.goal_radar = _radar_motion_tracker;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time = 0;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.score_to_win = 25;
result.universal_variant.suicide_penalty = 450;
result.universal_variant.teams = FALSE;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
result.game_engine_variant.slayer.kill_in_order = FALSE;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_ctf(
struct game_variant *variant)
{
struct game_variant result = { 0 };
result.game_engine_index = game_engine_ctf;
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, FALSE);
result.universal_variant.goal_radar = _radar_nav_point;
result.universal_variant.teams = TRUE;
result.flags = 1;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time = 300;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.score_to_win = 3;
result.universal_variant.suicide_penalty = 150;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
result.universal_variant.vehicle_set = _game_engine_vehicles_warthog;
result.game_engine_variant.ctf.assault = FALSE;
result.game_engine_variant.ctf.flag_at_home_to_score = FALSE;
result.game_engine_variant.ctf.flag_must_reset = FALSE;
result.game_engine_variant.ctf.reset_on_capture = FALSE;
result.game_engine_variant.ctf.single_flag_time = 0;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_ctf_pro(
struct game_variant *variant)
{
struct game_variant result = { 0 };
result.game_engine_index = game_engine_ctf;
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, TRUE);
result.universal_variant.goal_radar = _radar_nav_point;
result.universal_variant.teams = TRUE;
result.game_engine_variant.ctf.flag_at_home_to_score = TRUE;
result.flags = 1;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time = 300;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.score_to_win = 3;
result.universal_variant.suicide_penalty = 450;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
result.universal_variant.vehicle_set = _game_engine_vehicles_warthog;
result.game_engine_variant.ctf.assault = FALSE;
result.game_engine_variant.ctf.flag_must_reset = FALSE;
result.game_engine_variant.ctf.reset_on_capture = FALSE;
result.game_engine_variant.ctf.single_flag_time = 0;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_invasion(
struct game_variant *variant)
{
struct game_variant result = { 0 };
result.game_engine_index = game_engine_ctf;
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, FALSE);
result.universal_variant.goal_radar = _radar_nav_point;
result.universal_variant.teams = TRUE;
result.game_engine_variant.ctf.assault = TRUE;
result.flags = 1;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 5;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time = 0;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.score_to_win = 3;
result.universal_variant.suicide_penalty = 150;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
result.universal_variant.vehicle_set = _game_engine_vehicles_warthog;
result.game_engine_variant.ctf.flag_at_home_to_score = FALSE;
result.game_engine_variant.ctf.flag_must_reset = FALSE;
result.game_engine_variant.ctf.reset_on_capture = FALSE;
result.game_engine_variant.ctf.single_flag_time = 0;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_iron_ctf(
struct game_variant *variant)
{
struct game_variant result = { 0 };
result.game_engine_index = game_engine_ctf;
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, FALSE);
result.universal_variant.goal_radar = _radar_nav_point;
result.universal_variant.teams = TRUE;
result.game_engine_variant.ctf.flag_must_reset = TRUE;
result.flags = 1;
result.universal_variant.health = 2.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time = 450;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.score_to_win = 3;
result.universal_variant.suicide_penalty = 150;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
result.universal_variant.vehicle_set = _game_engine_vehicles_tank;
result.game_engine_variant.ctf.assault = FALSE;
result.game_engine_variant.ctf.flag_at_home_to_score = FALSE;
result.game_engine_variant.ctf.reset_on_capture = FALSE;
result.game_engine_variant.ctf.single_flag_time = 0;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_race(
struct game_variant *variant)
{
struct game_variant result = { 0 };
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, FALSE);
result.universal_variant.goal_radar = _radar_nav_point;
result.flags = 1;
result.game_engine_index = game_engine_race;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time = 0;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.score_to_win = 3;
result.universal_variant.suicide_penalty = 300;
result.universal_variant.teams = FALSE;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
result.universal_variant.vehicle_set = _game_engine_vehicles_warthog;
result.game_engine_variant.race.race_type = 0;
result.game_engine_variant.race.team_scoring = 0;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_rally(
struct game_variant *variant)
{
struct game_variant result = { 0 };
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, FALSE);
result.universal_variant.goal_radar = _radar_nav_point;
result.universal_variant.vehicle_set = _game_engine_vehicles_warthog;
result.game_engine_variant.race.race_type = 2;
result.flags = 1;
result.game_engine_index = game_engine_race;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time = 0;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.score_to_win = 15;
result.universal_variant.suicide_penalty = 300;
result.universal_variant.teams = FALSE;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
result.game_engine_variant.race.team_scoring = 0;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_team_race(
struct game_variant *variant)
{
struct game_variant result = { 0 };
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, FALSE);
result.universal_variant.goal_radar = _radar_nav_point;
result.universal_variant.teams = TRUE;
result.flags = 1;
result.game_engine_index = game_engine_race;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time = 0;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.score_to_win = 3;
result.universal_variant.suicide_penalty = 300;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
result.universal_variant.vehicle_set = _game_engine_vehicles_warthog;
result.game_engine_variant.race.race_type = 0;
result.game_engine_variant.race.team_scoring = 0;
*variant = result;
return variant;
}
struct game_variant *build_game_variant_team_rally(
struct game_variant *variant)
{
struct game_variant result = { 0 };
result.game_engine_index = game_engine_race;
SET_FLAG(result.universal_variant.flags, _game_variant_draw_object_in_motion_sensor_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_allow_friendly_navpoints_bit, TRUE);
SET_FLAG(result.universal_variant.flags, _game_variant_infinite_grenades_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_no_shields_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_always_invisible_bit, FALSE);
SET_FLAG(result.universal_variant.flags, _game_variant_generic_starting_equipment_bit, FALSE);
result.universal_variant.goal_radar = _radar_nav_point;
result.universal_variant.score_to_win = 5;
result.universal_variant.teams = TRUE;
result.universal_variant.vehicle_set = _game_engine_vehicles_warthog;
result.flags = 1;
result.game_engine_variant.race.race_type = 2;
result.universal_variant.health = 1.0f;
result.universal_variant.lives = 0;
result.universal_variant.odd_man_out = FALSE;
result.universal_variant.respawn_time = 0;
result.universal_variant.respawn_time_growth = 0;
result.universal_variant.suicide_penalty = 300;
result.universal_variant.weapon_set = _game_engine_weapons_normal;
result.game_engine_variant.race.team_scoring = 0;
*variant = result;
return variant;
}
long postgame_statistic_get_rating(
long player_index,
enum postgame_statistic statistic,
boolean inverse)
{
struct statistic_buffer statistic_buffer[MULTIPLAYER_MAXIMUM_PLAYERS];
long player_count = 0;
long rating;
long statistic_index;
player_count = populate_statistic_buffer(statistic_buffer, statistic, inverse);
rating = 0;
if (statistic_buffer[0].player_index != player_index)
{
for (statistic_index = 1; statistic_index < player_count; statistic_index++)
{
if (statistic_buffer[statistic_index - 1].score != statistic_buffer[statistic_index].score)
rating++;
if (statistic_buffer[statistic_index].player_index == player_index)
break;
}
}
return rating;
}
long game_engine_did_player_win(
long player_index)
{
long result = 0;
if (game_engine)
{
if (game_engine->did_player_win)
result = game_engine->did_player_win(player_index);
else
result = game_engine_did_player_win_default(player_index);
}
return result;
}
boolean multiple_teams_alive(
void)
{
boolean result = FALSE;
if (players_in_game() <= 1)
return TRUE;
else
{
struct data_iterator iterator;
struct player_datum *player;
long team_index = NONE;
data_iterator_new(&iterator, player_data);
player = (struct player_datum *)data_iterator_next(&iterator);
while (player)
{
if (!player->quit_out_of_game &&
(player->unit_index != NONE ||
(!game_engine_player_is_odd_man_out(iterator.datum_index) &&
!game_engine_player_is_out_of_lives(
iterator.datum_index))))
{
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0x1BE,
player->team_index != NONE);
if (player->team_index != team_index)
{
if (team_index != NONE)
{
result = TRUE;
break;
}
team_index = player->team_index;
}
}
player = (struct player_datum *)data_iterator_next(&iterator);
}
}
return result;
}
boolean team_has_players(
long team_index)
{
boolean result = FALSE;
if (players_in_game() <= 1)
{
result = TRUE;
goto done;
}
else
{
struct data_iterator iterator;
struct player_datum *player;
data_iterator_new(&iterator, player_data);
player = (struct player_datum *)data_iterator_next(&iterator);
while (player)
{
if (!player->quit_out_of_game &&
(player->unit_index != NONE ||
(!game_engine_player_is_odd_man_out(iterator.datum_index) &&
!game_engine_player_is_out_of_lives(
iterator.datum_index))))
{
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0x1F7,
player->team_index != NONE);
/* Preserve the retail first-eligible-player behavior. */
if (player->team_index == team_index)
result = TRUE;
break;
}
player = (struct player_datum *)data_iterator_next(&iterator);
}
}
done:
return result;
}
long game_engine_did_player_win_default(
long player_index)
{
long result = 0;
if (global_variant.universal_variant.teams)
{
long team0_score = game_engine_get_team_score(0);
long team1_score = game_engine_get_team_score(1);
long winning_team_index;
struct player_datum *player = player_get(player_index);
if (multiple_teams_alive())
winning_team_index = team0_score == team1_score ? NONE : (team0_score > team1_score ? 0 : 1);
else
winning_team_index = team_has_players(0) ? 0 : 1;
if (winning_team_index == NONE)
result = NONE;
else if (player->team_index == winning_team_index)
result = TRUE;
else
result = FALSE;
}
else
{
struct statistic_buffer entry;
entry = game_engine_get_player_place(player_index);
if (is_place_tied(&entry) &&
!place_get_position(&entry))
result = NONE;
else if (!place_get_position(&entry))
result = TRUE;
else
result = FALSE;
}
return result;
}
static long game_engine_get_type(
void)
{
long game_engine_type = NONE;
if (game_engine)
game_engine_type = game_engine->type;
return game_engine_type;
}
struct game_variant *game_engine_get_variant(
void)
{
return &global_variant;
}
struct game_variant *game_engine_get_variant_by_name(
struct game_variant *variant,
char const *name)
{
struct game_variant temporary;
struct game_variant result;
csmemset(&result, 0, sizeof(result));
if (csstrcmp(name, "race") == 0)
result = *build_game_variant_race(&temporary);
else if (csstrcmp(name, "team_race") == 0)
result = *build_game_variant_team_race(&temporary);
else if (csstrcmp(name, "rally") == 0)
result = *build_game_variant_rally(&temporary);
else if (csstrcmp(name, "slayer") == 0)
result = *build_game_variant_slayer(&temporary);
else if (csstrcmp(name, "team_slayer") == 0)
result = *build_game_variant_team_slayer(&temporary);
else if (csstrcmp(name, "elimination") == 0)
result = *build_game_variant_elimination(&temporary);
else if (csstrcmp(name, "stalker") == 0)
result = *build_game_variant_stalker(&temporary);
else if (csstrcmp(name, "team_oddball") == 0)
result = *build_game_variant_team_oddball(&temporary);
else if (csstrcmp(name, "accumulation") == 0)
result = *build_game_variant_accumulation(&temporary);
else if (csstrcmp(name, "oddball") == 0)
result = *build_game_variant_oddball(&temporary);
else if (csstrcmp(name, "ctf") == 0)
result = *build_game_variant_ctf(&temporary);
else if (csstrcmp(name, "ironctf") == 0)
result = *build_game_variant_iron_ctf(&temporary);
else if (csstrcmp(name, "king") == 0)
result = *build_game_variant_king(&temporary);
else if (csstrcmp(name, "team_king") == 0)
result = *build_game_variant_team_king(&temporary);
*variant = result;
return variant;
}
boolean game_engine_get_goal_in_use(
short goal_index)
{
return global_goal[goal_index].in_use;
}
real_point3d *game_engine_get_goal_position(
real_point3d *position,
short index)
{
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0xFE2,
global_goal[index].in_use);
*position = global_goal[index].position;
return position;
}
void game_engine_set_goal_position(
short goal_index,
real_point3d const *position,
real height,
char const *name,
long player_index,
short team_index,
long ignore_player_index)
{
/* port: a goal of the table only */
if (!VALID_INDEX(goal_index, NUMBEROF(global_goal)))
return;
global_goal[goal_index].ignore_player_index = ignore_player_index;
global_goal[goal_index].nav_index = find_nav_point(name);
global_goal[goal_index].in_use = TRUE;
global_goal[goal_index].position = *position;
global_goal[goal_index].team_index = team_index;
global_goal[goal_index].position.z += height + 0.63f;
global_goal[goal_index].player_index = player_index;
return;
}
boolean game_engine_man_out(
long player_index)
{
struct player_datum *player = player_get(player_index);
boolean man_out = player->quit_out_of_game ||
game_engine_player_is_out_of_lives(player_index) ||
game_engine_player_is_odd_man_out(player_index);
return man_out;
}
real_rgb_color *game_engine_player_get_change_color(
real_rgb_color *change_color,
long player_index)
{
struct player_datum *player = player_get(player_index);
real_rgb_color result;
if (global_variant.universal_variant.teams)
{
if (player->team_index == 0)
result = *global_real_rgb_red;
else
result = *global_real_rgb_blue;
}
else
{
long color_index = player->network_player_data.primary_color_index;
if (debug_player_color != NONE)
color_index = debug_player_color;
result = player_profile_get_rgb_color(color_index);
}
*change_color = result;
return change_color;
}
boolean game_engine_has_teams(
void)
{
boolean has_teams = FALSE;
if (game_engine)
has_teams = global_variant.universal_variant.teams;
return has_teams;
}
boolean game_engine_allow_pause(
void)
{
return game_engine_globals.postgame_state==game_engine_mode_active;
}
boolean game_engine_allow_dynamic_lighting(
void)
{
boolean allow_dynamic_lighting = TRUE;
if (game_engine)
allow_dynamic_lighting = !TEST_FLAG(game_engine_globals.flags, _game_engine_disable_dynamic_light_bit);
return allow_dynamic_lighting;
}
boolean game_engine_allow_integrated_lights(
long object_index)
{
boolean allow_integrated_lights = TRUE;
if (game_engine)
allow_integrated_lights = !TEST_FLAG(game_engine_globals.flags, _game_engine_disable_integrated_lights_bit);
return allow_integrated_lights;
}
void game_engine_variant_cleanup(
struct game_variant *variant)
{
struct game_variant original = *variant;
variant->human_readable_game_description[NUMBEROF(variant->human_readable_game_description) - 1] = 0;
variant->game_engine_index = PIN(variant->game_engine_index, 1, 5);
variant->universal_variant.teams = !!variant->universal_variant.teams;
variant->universal_variant.odd_man_out = !!variant->universal_variant.odd_man_out;
variant->universal_variant.respawn_time_growth = MAX(variant->universal_variant.respawn_time_growth, 0);
variant->universal_variant.respawn_time = MAX(variant->universal_variant.respawn_time, 0);
variant->universal_variant.suicide_penalty = MAX(variant->universal_variant.suicide_penalty, 0);
variant->universal_variant.lives = MAX(variant->universal_variant.lives, 0);
variant->universal_variant.health = PIN(variant->universal_variant.health, 0.25f, 4.0f);
variant->universal_variant.weapon_set = PIN(variant->universal_variant.weapon_set, 0, NUMBER_OF_GAME_ENGINE_WEAPON_SETS - 1);
variant->universal_variant.vehicle_set = PIN(variant->universal_variant.vehicle_set, 0, NUMBER_OF_GAME_ENGINE_VEHICLE_SETS - 1);
switch (variant->game_engine_index)
{
case game_engine_ctf:
variant->game_engine_variant.ctf.assault = !!variant->game_engine_variant.ctf.assault;
variant->game_engine_variant.ctf.reset_on_capture = !!variant->game_engine_variant.ctf.reset_on_capture;
variant->game_engine_variant.ctf.flag_must_reset = !!variant->game_engine_variant.ctf.flag_must_reset;
variant->universal_variant.teams = TRUE;
variant->game_engine_variant.ctf.flag_at_home_to_score = !!variant->game_engine_variant.ctf.flag_at_home_to_score;
variant->game_engine_variant.ctf.single_flag_time = FLOOR(variant->game_engine_variant.ctf.single_flag_time, 0);
break;
case game_engine_slayer:
variant->game_engine_variant.slayer.no_death_bonus = !!variant->game_engine_variant.slayer.no_death_bonus;
variant->game_engine_variant.slayer.no_kill_penalty = !!variant->game_engine_variant.slayer.no_kill_penalty;
variant->game_engine_variant.slayer.kill_in_order = !!variant->game_engine_variant.slayer.kill_in_order;
break;
case game_engine_oddball:
/* port: the balls' arrays and goals hold no more */
variant->game_engine_variant.oddball.ball_spawn_count =
PIN(variant->game_engine_variant.oddball.ball_spawn_count, 0, MAXIMUM_ODDBALLS);
break;
}
if (csmemcmp(&original, variant, sizeof(original)) != 0)
{
struct game_variant cleaned;
csmemcpy(&cleaned, &original, sizeof(cleaned));
csmemcpy(&cleaned, variant, sizeof(cleaned));
error(
_error_silent,
"NETGAME CODE FAILURE: game_engine_variant_cleanup changed the variant");
}
return;
}
static void game_engine_predict_resources(
void)
{
struct game_globals *game_globals;
struct game_globals_multiplayer_information *multiplayer_information;
struct game_globals_vehicle *vehicle;
long weapon_indices[10];
long weapon_index;
game_globals = scenario_get_game_globals();
multiplayer_information = TAG_BLOCK_GET_ELEMENT(
&game_globals->multiplayer_information,
0,
struct game_globals_multiplayer_information);
switch (global_variant.universal_variant.vehicle_set)
{
case _game_engine_vehicles_warthog:
vehicle = TAG_BLOCK_GET_ELEMENT(
&multiplayer_information->vehicles,
0,
struct game_globals_vehicle);
object_definition_predict(vehicle->vehicle.index);
break;
case _game_engine_vehicles_ghost:
vehicle = TAG_BLOCK_GET_ELEMENT(
&multiplayer_information->vehicles,
1,
struct game_globals_vehicle);
object_definition_predict(vehicle->vehicle.index);
break;
case _game_engine_vehicles_tank:
vehicle = TAG_BLOCK_GET_ELEMENT(
&multiplayer_information->vehicles,
2,
struct game_globals_vehicle);
object_definition_predict(vehicle->vehicle.index);
break;
default:
{
struct tag_block *vehicles = &multiplayer_information->vehicles;
vehicle = TAG_BLOCK_GET_ELEMENT(
vehicles,
0,
struct game_globals_vehicle);
object_definition_predict(vehicle->vehicle.index);
vehicle = TAG_BLOCK_GET_ELEMENT(
vehicles,
1,
struct game_globals_vehicle);
object_definition_predict(vehicle->vehicle.index);
vehicle = TAG_BLOCK_GET_ELEMENT(
vehicles,
2,
struct game_globals_vehicle);
object_definition_predict(vehicle->vehicle.index);
break;
}
}
object_definition_predict(list_index_to_weapon_definition_index(_weapon_list_frag_grenade));
object_definition_predict(list_index_to_weapon_definition_index(_weapon_list_plasma_grenade));
if (global_variant.game_engine_index == game_engine_oddball)
object_definition_predict(list_index_to_weapon_definition_index(_weapon_list_ball));
if (global_variant.game_engine_index == game_engine_ctf)
object_definition_predict(list_index_to_weapon_definition_index(_weapon_list_flag));
weapon_indices[0] = list_index_to_weapon_definition_index(0);
weapon_indices[1] = list_index_to_weapon_definition_index(1);
weapon_indices[2] = list_index_to_weapon_definition_index(2);
weapon_indices[3] = list_index_to_weapon_definition_index(3);
weapon_indices[4] = list_index_to_weapon_definition_index(4);
weapon_indices[5] = list_index_to_weapon_definition_index(5);
weapon_indices[6] = list_index_to_weapon_definition_index(6);
weapon_indices[7] = list_index_to_weapon_definition_index(7);
weapon_indices[8] = list_index_to_weapon_definition_index(8);
weapon_indices[9] = list_index_to_weapon_definition_index(9);
for (weapon_index = 0; weapon_index < 10; weapon_index++)
{
object_definition_predict(
game_engine_remap_weapon(weapon_indices[weapon_index]));
}
return;
}
void game_engine_initialize(
struct game_variant *variant)
{
csmemset(&game_engine_globals, 0, sizeof(game_engine_globals));
game_engine_globals.postgame_state = game_engine_mode_active;
if (variant && variant->game_engine_index)
{
global_variant = *variant;
game_engine_variant_cleanup(&global_variant);
/* port: the cleaned variant's (the one given may be any number) */
game_engine = game_engines[global_variant.game_engine_index];
}
return;
}
void game_engine_initialize_for_new_map(
void)
{
if (game_engine)
{
game_engine_verify_current_map();
game_engine_intialize_queued_sounds();
csmemset(global_goal, 0, sizeof(global_goal));
game_engine_globals.next_team_index = 0;
timeout_for_endgame_sound = 0;
game_engine_network_state_read = FALSE;
if (game_engine->initialize_for_new_map &&
!game_engine->initialize_for_new_map())
{
error(
_error_silent,
"failed to initialize custome game engine for new map, reverting to default game engine");
if (game_engine)
{
if (game_engine->dispose)
game_engine->dispose();
game_engine = NULL;
}
}
game_engine_predict_resources();
}
return;
}
void game_engine_player_added(
long player_index)
{
initialize_player_multiplayer_data(player_index);
if (game_engine)
{
struct player_datum *player = player_get(player_index);
long *next_team_index = &game_engine_globals.next_team_index;
if (global_variant.universal_variant.teams)
{
if (global_network_game_client_get())
{
player->team_index =
PIN((signed char)player->network_player_data.team_index % 2, 0, 1);
}
else
{
player->network_player_data.team_index =
(char)*next_team_index;
player->team_index =
(signed char)*next_team_index;
*next_team_index = (*next_team_index + 1) % 2;
}
}
else
{
/* port: a free-for-all team is the player's own slot, which stays
below the player limit and is the same on every machine */
long team_index = DATUM_INDEX_TO_ABSOLUTE_INDEX(player_index);
player->network_player_data.team_index =
(char)team_index;
player->team_index =
(signed char)team_index;
}
if (player_index != NONE)
{
multiplayer_message(player_index, 0, NONE);
}
else
{
struct data_iterator iterator;
data_iterator_new(&iterator, player_data);
while (data_iterator_next(&iterator))
multiplayer_message(iterator.datum_index, 0, NONE);
}
if (game_engine->player_added)
game_engine->player_added(player_index);
}
return;
}
real game_engine_get_distance_rating_for_spawn(
long player_index,
real_point3d const *position)
{
boolean has_teams = game_engine ? global_variant.universal_variant.teams : FALSE;
struct player_datum *player;
struct data_iterator iterator;
struct player_datum *other_player;
real rating;
player = player_get(player_index);
rating = 1.0f;
data_iterator_new(&iterator, player_data);
other_player = (struct player_datum *)data_iterator_next(&iterator);
while (other_player)
{
if (other_player->unit_index!=NONE)
{
real_point3d origin;
real distance;
object_get_origin(other_player->unit_index, &origin);
distance = distance3d(&origin, position);
if (!has_teams ||
other_player->team_index!=player->team_index ||
!(distance>0.25f))
{
if (distance<0.25f)
rating = 0.0f;
else if (distance<1.0f)
rating *= 0.1f;
if (other_player->team_index!=player->team_index)
{
if (distance<2.0f)
rating = 0.0f;
else if (!(distance>5.0f))
rating = (distance-2.0f)*rating*0.33333334f;
}
}
}
other_player = (struct player_datum *)data_iterator_next(&iterator);
}
return rating;
}
real game_engine_get_starting_location_rating(
long player_index,
struct player_starting_location const *starting_location)
{
if (!match_game_type(game_engine_get_type(), 4, starting_location->game_types))
return 0.0f;
if (nearby_vehicle(player_index, starting_location))
return 0.0f;
return default_starting_location_rate_function(player_index, starting_location);
}
real game_engine_get_damage_multiplier(
long damaging_player_index,
long damaged_player_index)
{
real result = 1.0f;
if (game_engine)
result /= PIN(global_variant.universal_variant.health, 0.25f, 4.0f);
if (damaging_player_index != NONE &&
damaged_player_index != NONE)
{
if (game_engine_test_trait(damaging_player_index, 2))
{
result *= 1.5f;
}
if (game_engine_test_trait(damaged_player_index, 3))
{
result *= 0.5f;
}
}
return result;
}
long game_engine_remap_vehicle(
long vehicle_definition_index)
{
long result = vehicle_definition_index;
if (game_engine)
{
struct game_globals *game_globals;
struct game_globals_multiplayer_information *multiplayer_information;
struct tag_block *vehicles;
struct game_globals_vehicle *vehicle0;
struct game_globals_vehicle *vehicle1;
struct game_globals_vehicle *vehicle2;
struct game_globals_vehicle *vehicle;
game_globals = scenario_get_game_globals();
multiplayer_information = TAG_BLOCK_GET_ELEMENT(
&game_globals->multiplayer_information,
0,
struct game_globals_multiplayer_information);
vehicle0 = TAG_BLOCK_GET_ELEMENT(
&multiplayer_information->vehicles,
0,
struct game_globals_vehicle);
vehicles = &multiplayer_information->vehicles;
vehicle1 = TAG_BLOCK_GET_ELEMENT(vehicles, 1, struct game_globals_vehicle);
vehicle2 = TAG_BLOCK_GET_ELEMENT(vehicles, 2, struct game_globals_vehicle);
if (result != vehicle0->vehicle.index &&
result != vehicle1->vehicle.index &&
result != vehicle2->vehicle.index)
{
result = NONE;
}
switch (global_variant.universal_variant.vehicle_set)
{
case _game_engine_vehicles_none:
result = NONE;
break;
case _game_engine_vehicles_warthog:
vehicle = TAG_BLOCK_GET_ELEMENT(
vehicles,
0,
struct game_globals_vehicle);
if (vehicle->vehicle.index != result)
result = NONE;
break;
case _game_engine_vehicles_ghost:
vehicle = TAG_BLOCK_GET_ELEMENT(
vehicles,
1,
struct game_globals_vehicle);
if (vehicle->vehicle.index != result)
result = NONE;
break;
case _game_engine_vehicles_tank:
vehicle = TAG_BLOCK_GET_ELEMENT(
vehicles,
2,
struct game_globals_vehicle);
if (vehicle->vehicle.index != result)
result = NONE;
break;
}
}
return result;
}
long game_engine_remap_weapon(
long weapon_definition_index)
{
long weapon_list_index =
weapon_definition_index_to_list_index(weapon_definition_index);
if (weapon_list_index == _weapon_list_ball ||
weapon_list_index == _weapon_list_flag ||
weapon_list_index == NONE)
{
return weapon_definition_index;
}
if (weapon_list_index == _weapon_list_flamethrower)
weapon_list_index = _weapon_list_rocket_launcher;
switch (global_variant.universal_variant.weapon_set)
{
case _game_engine_weapons_pistols:
switch (weapon_list_index)
{
case _weapon_list_needler:
case _weapon_list_pistol:
case _weapon_list_plasma_rifle:
case _weapon_list_rocket_launcher:
weapon_list_index = _weapon_list_plasma_pistol;
break;
case _weapon_list_plasma_pistol:
default:
weapon_list_index = _weapon_list_pistol;
break;
}
break;
case _game_engine_weapons_assault_rifles:
switch (weapon_list_index)
{
case _weapon_list_needler:
case _weapon_list_pistol:
case _weapon_list_plasma_rifle:
case _weapon_list_rocket_launcher:
weapon_list_index = _weapon_list_plasma_rifle;
break;
case _weapon_list_plasma_pistol:
default:
weapon_list_index = _weapon_list_assault_rifle;
break;
}
break;
case _game_engine_weapons_plasma_weapons:
if (weapon_list_index >= _weapon_list_needler && weapon_list_index <= _weapon_list_plasma_pistol)
weapon_list_index = _weapon_list_plasma_pistol;
else
weapon_list_index = _weapon_list_plasma_rifle;
break;
case _game_engine_weapons_sniping:
if (weapon_list_index != _weapon_list_pistol && weapon_list_index != _weapon_list_sniper_rifle)
weapon_list_index = _weapon_list_sniper_rifle;
break;
case _game_engine_weapons_no_sniping:
switch (weapon_list_index)
{
case _weapon_list_pistol:
weapon_list_index = _weapon_list_assault_rifle;
break;
case _weapon_list_sniper_rifle:
weapon_list_index = _weapon_list_shotgun;
break;
}
break;
case _game_engine_weapons_rocket_launchers:
weapon_list_index = _weapon_list_rocket_launcher;
break;
case _game_engine_weapons_shotguns:
weapon_list_index = _weapon_list_shotgun;
break;
case _game_engine_weapons_short_range:
switch (weapon_list_index)
{
case _weapon_list_assault_rifle:
case _weapon_list_needler:
case _weapon_list_pistol:
case _weapon_list_sniper_rifle:
weapon_list_index = _weapon_list_shotgun;
break;
}
break;
case _game_engine_weapons_human:
switch (weapon_list_index)
{
case _weapon_list_needler:
case _weapon_list_plasma_rifle:
weapon_list_index = _weapon_list_assault_rifle;
break;
case _weapon_list_plasma_pistol:
weapon_list_index = _weapon_list_pistol;
break;
}
break;
}
return list_index_to_weapon_definition_index(weapon_list_index);
}
long game_engine_remap_object_definition(
long definition_index)
{
short object_type;
if (!game_engine_running() || definition_index==NONE)
{
return definition_index;
}
object_type = object_definition_get(definition_index)->object.type;
if (object_type==_object_type_vehicle)
{
return game_engine_remap_vehicle(definition_index);
}
if (object_type==_object_type_weapon)
{
return game_engine_remap_weapon(definition_index);
}
if (object_type==_object_type_equipment)
{
return game_engine_remap_equipment(definition_index);
}
return definition_index;
}
/* ---------- private code */
static void netgame_flag_verify_no_team_duplicates(
short flag_type,
char const *error_message)
{
struct scenario *scenario = global_scenario_get();
short flag_index;
for (flag_index = 0;
flag_index < scenario->netgame_flags.count;
flag_index++)
{
struct scenario_netgame_flag *flag = TAG_BLOCK_GET_ELEMENT(
&scenario->netgame_flags,
flag_index,
struct scenario_netgame_flag);
short duplicate_index;
if (flag_type != flag->type)
continue;
for (duplicate_index = flag_index + 1;
duplicate_index < scenario->netgame_flags.count;
duplicate_index++)
{
struct scenario_netgame_flag *duplicate = TAG_BLOCK_GET_ELEMENT(
&scenario->netgame_flags,
duplicate_index,
struct scenario_netgame_flag);
if (flag_type == duplicate->type &&
duplicate->team_index == flag->team_index)
{
error(
_error_silent,
error_message,
duplicate->team_index);
}
}
}
return;
}
static void update_weapon_inventory(
long weapon_index)
{
struct weapon_datum *weapon;
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0x80A,
weapon_index != NONE);
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0x80B,
weapon_is_flag(weapon_index));
weapon = weapon_get(weapon_index);
if (weapon->object.parent_object_index == NONE &&
!TEST_FLAG(weapon->item.flags, _item_attached_to_unit_bit) &&
TEST_FLAG(
weapon->weapon.flags,
_weapon_runtime_game_engine_active_bit))
{
weapon->weapon.flags &=
~FLAG(_weapon_runtime_game_engine_active_bit);
if (game_engine->weapon_dropped)
game_engine->weapon_dropped(weapon_index);
}
return;
}
static void game_engine_update_weapons(
void)
{
struct object_iterator iterator;
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0x828,
NULL != game_engine);
object_iterator_new(
&iterator,
_object_mask_item,
0);
while (object_iterator_next(&iterator))
{
struct item_datum *item = item_get(iterator.index);
if (TEST_FLAG(item->item.flags, _item_attached_to_unit_bit))
{
item->object.scale = 1.f;
}
else
{
struct item_definition *definition =
item_definition_get(item->definition_index);
item->object.scale =
definition->item.scale != 0.f
? definition->item.scale
: 1.f;
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0x83E,
(item->object.scale >= 0.5f) &&
(item->object.scale <= 3.f));
}
/*
* Slot 0x38 is populated by the CTF and oddball engines. It receives
* each objective weapon during the per-tick item scan.
*/
if (game_engine->objective_weapon_update)
{
struct weapon_datum *weapon = weapon_try_and_get(iterator.index);
if (weapon && weapon_is_flag(iterator.index))
{
update_weapon_inventory(iterator.index);
game_engine->objective_weapon_update(
iterator.index,
weapon);
}
}
}
return;
}
static void netgame_flag_verify_team_range(
short flag_type,
short minimum_index,
short maximum_index,
char const *error_message)
{
struct scenario *scenario = global_scenario_get();
short flag_index;
for (flag_index = 0;
flag_index < scenario->netgame_flags.count;
flag_index++)
{
struct scenario_netgame_flag *flag = TAG_BLOCK_GET_ELEMENT(
&scenario->netgame_flags,
flag_index,
struct scenario_netgame_flag);
if (flag_type == flag->type &&
(flag->team_index < minimum_index ||
flag->team_index > maximum_index))
{
error(
_error_silent,
error_message,
flag->team_index);
}
}
return;
}
static void netgame_verify_equipment(
short game_type,
char const *error_message)
{
long matching_count = 0;
struct scenario *scenario = global_scenario_get();
short equipment_index;
for (equipment_index = 0;
equipment_index < scenario->netgame_equipment.count;
equipment_index++)
{
struct scenario_netgame_equipment *equipment =
TAG_BLOCK_GET_ELEMENT(
&scenario->netgame_equipment,
equipment_index,
struct scenario_netgame_equipment);
if (match_game_type(
game_type,
4,
equipment->game_type))
{
matching_count++;
}
}
if (matching_count == 0)
error(_error_silent, error_message);
return;
}
static void netgame_flag_verify_team_exists(
short flag_type,
short flag_index,
char const *error_message)
{
if (find_netgame_flag(
NULL,
0.f,
0.f,
flag_type,
flag_index) == NONE)
{
error(
_error_silent,
error_message,
flag_index);
}
return;
}
static void game_engine_verify_current_map(
void)
{
netgame_flag_verify_team_exists(
_netgame_flag_ctf_flag,
0,
"NETGAME MAP FAILURE: missing ctf flag [team %d]");
netgame_flag_verify_team_exists(
_netgame_flag_ctf_flag,
1,
"NETGAME MAP FAILURE: missing ctf flag [team %d]");
netgame_flag_verify_no_team_duplicates(
_netgame_flag_ctf_flag,
"NETGAME MAP FAILURE: duplicate ctf flag [team %d]");
netgame_flag_verify_team_range(
_netgame_flag_ctf_flag,
0,
1,
"NETGAME MAP FAILURE: ctf flag out of range [team %d]");
netgame_flag_verify_team_exists(
_netgame_flag_hill,
0,
"NETGAME MAP FAILURE: missing hill flag [team %d]");
netgame_flag_verify_team_exists(
_netgame_flag_hill,
1,
"NETGAME MAP FAILURE: missing hill flag [team %d]");
netgame_flag_verify_team_exists(
_netgame_flag_oddball_ball_spawn,
0,
"NETGAME MAP FAILURE: missing oddball flag [team %d]");
netgame_flag_verify_team_exists(
_netgame_flag_oddball_ball_spawn,
1,
"NETGAME MAP FAILURE: missing oddball flag [team %d]");
netgame_flag_verify_team_exists(
_netgame_flag_race_track,
0,
"NETGAME MAP FAILURE: missing race flag [team %d]");
netgame_flag_verify_team_exists(
_netgame_flag_race_track,
1,
"NETGAME MAP FAILURE: missing race flag [team %d]");
netgame_flag_verify_no_team_duplicates(
_netgame_flag_race_track,
"NETGAME MAP FAILURE: duplicate race track flag [team %d]");
/* BUG (preserved for exact matching): January passes team index zero for
* both CTF checks, and netgame_verify_spawn_points never reads that
* formal parameter.
* A corrected build should filter starting locations by an authoritatively
* recovered team-index field before reporting per-team counts.
*/
netgame_verify_spawn_points(
game_engine_ctf,
0,
4,
"NETGAME MAP FAILURE: failed to find enough spawn points for ctf team 0 (%d/%d)");
netgame_verify_spawn_points(
game_engine_ctf,
0,
4,
"NETGAME MAP FAILURE: failed to find enough spawn points for ctf team 1 (%d/%d)");
netgame_verify_spawn_points(
game_engine_slayer,
0,
4,
"NETGAME MAP FAILURE: failed to find enough spawn points for slayer %d/%d");
netgame_verify_spawn_points(
game_engine_oddball,
0,
4,
"NETGAME MAP FAILURE: failed to find enough spawn points for oddball %d/%d");
netgame_verify_spawn_points(
game_engine_king,
0,
4,
"NETGAME MAP FAILURE: failed to find enough spawn points for king %d/%d");
netgame_verify_spawn_points(
game_engine_race,
0,
4,
"NETGAME MAP FAILURE: failed to find enough spawn points for race %d/%d");
netgame_verify_equipment(
game_engine_ctf,
"NETGAME MAP FAILURE: failed to find any equipment for ctf");
netgame_verify_equipment(
game_engine_slayer,
"NETGAME MAP FAILURE: failed to find any equipment for slayer");
netgame_verify_equipment(
game_engine_oddball,
"NETGAME MAP FAILURE: failed to find any equipment for oddball");
netgame_verify_equipment(
game_engine_king,
"NETGAME MAP FAILURE: failed to find any equipment for king");
netgame_verify_equipment(
game_engine_race,
"NETGAME MAP FAILURE: failed to find any equipment for race");
return;
}
static void internal_rasterize_target_name(
long player_index)
{
struct player_datum *player;
long target_player_index;
player = player_get(player_index);
target_player_index = NONE;
if (player->local_player_index != NONE && player->unit_index != NONE)
{
target_player_index = find_closest_player_index(player_index);
if (target_player_index == player_index)
target_player_index = NONE;
}
/* This is drawn once a frame, several frames per tick
(render_interpolation.c): the hold time counts ticks, as it did on the
Xbox. */
{
static long last_game_times[MAXIMUM_NUMBER_OF_LOCAL_PLAYERS];
long *last_game_time = NULL;
if (player->local_player_index >= 0 &&
player->local_player_index < MAXIMUM_NUMBER_OF_LOCAL_PLAYERS)
{
last_game_time = &last_game_times[player->local_player_index];
}
if (!last_game_time || *last_game_time != game_time_get())
{
if (last_game_time)
*last_game_time = game_time_get();
if (player->player_display_index != target_player_index)
{
if (player->player_display_count > 0)
player->player_display_count--;
if (player->player_display_count == 0)
player->player_display_index = target_player_index;
}
else if (player->player_display_count < 15)
{
player->player_display_count++;
}
}
}
if (player->player_display_index != NONE)
{
struct player_datum *target_player = player_get(player->player_display_index);
wchar_t target_name[12] = { 0 };
long hold_time = player->player_display_count;
real alpha;
if (hold_time >= 10)
hold_time = 10;
ustrncpy(target_name, target_player->name, NUMBEROF(target_name) - 1);
target_name[NUMBEROF(target_name) - 1] = 0;
alpha = linear_to_non_linear_alpha(hold_time * 0.1f) * 0.5f;
game_engine_rasterize_message(target_name, alpha);
}
return;
}
static boolean internal_rasterize_score(
long player_index,
long message,
long message_data,
wchar_t *buffer,
long buffer_size)
{
struct player_datum *player;
struct player_datum *other_player;
long score;
long string_list_index;
wchar_t const *format;
boolean result;
result = TRUE;
player = player_get(player_index);
score = 0;
if (game_engine_test_flag(1))
{
switch (message)
{
case _game_engine_message_multi_kill:
message = _game_engine_message_multi_kill_with_score;
break;
case _game_engine_message_triple_kill:
message = _game_engine_message_triple_kill_with_score;
break;
case _game_engine_message_double_kill:
message = _game_engine_message_double_kill_with_score;
break;
case _game_engine_message_ten_kills_in_a_row:
message = _game_engine_message_ten_kills_in_a_row_with_score;
break;
case _game_engine_message_five_kills_in_row:
message = _game_engine_message_five_kills_in_row_with_score;
break;
case _game_engine_message_killed_enemy:
message = _game_engine_message_killed_enemy_with_score;
break;
default:
break;
}
if (message >= _game_engine_message_multi_kill_with_score &&
message <= _game_engine_message_killed_enemy_with_score)
{
/* port: a client of the distributed netcode replaying the host's
killing blow: the score the host's game type gave its killer
(its own has it only once the game type's state comes) */
if (!network_damage_killer_score(player_index, &score))
score = game_engine->get_player_score(player_index, TRUE);
}
}
switch (message)
{
case _game_engine_message_welcome:
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x4A);
else
format = L"";
usnprintf(
buffer,
buffer_size,
format,
player->name);
break;
case _game_engine_message_killed_by_unknown:
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x4B);
else
format = L"";
usnprintf(
buffer,
buffer_size,
format,
player->name);
break;
case _game_engine_message_killed_by_biped:
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x4C);
else
format = L"";
usnprintf(
buffer,
buffer_size,
format,
player->name);
break;
case _game_engine_message_killed_by_vehicle:
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x4D);
else
format = L"";
usnprintf(
buffer,
buffer_size,
format,
player->name);
break;
case _game_engine_message_killed_by_player:
other_player = player_get(message_data);
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x4E);
else
format = L"";
usnprintf(
buffer,
buffer_size,
format,
player->name,
other_player->name);
break;
case _game_engine_message_killed_by_friendly_fire:
other_player = player_get(message_data);
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x4F);
else
format = L"";
usnprintf(
buffer,
buffer_size,
format,
player->name,
other_player->name);
break;
case _game_engine_message_quit:
other_player = player_get(message_data);
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x50);
else
format = L"";
usnprintf(
buffer,
buffer_size,
format,
other_player->name);
break;
case _game_engine_message_killed_by_self:
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x51);
else
format = L"";
usnprintf(
buffer,
buffer_size,
format,
player->name);
break;
case _game_engine_message_killed_friendly:
other_player = player_get(message_data);
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x52);
else
format = L"";
usnprintf(
buffer,
buffer_size,
format,
other_player->name);
break;
case _game_engine_message_multi_kill:
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x53);
else
format = L"";
ustrncpy(
buffer,
format,
buffer_size);
game_engine_play_multiplayer_sound(_multiplayer_sound_killtacular_kill);
break;
case _game_engine_message_triple_kill:
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x54);
else
format = L"";
ustrncpy(
buffer,
format,
buffer_size);
game_engine_play_multiplayer_sound(_multiplayer_sound_triple_kill);
break;
case _game_engine_message_double_kill:
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x55);
else
format = L"";
ustrncpy(
buffer,
format,
buffer_size);
game_engine_play_multiplayer_sound(_multiplayer_sound_double_kill);
break;
case _game_engine_message_ten_kills_in_a_row:
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x56);
else
format = L"";
ustrncpy(
buffer,
format,
buffer_size);
game_engine_play_multiplayer_sound(_multiplayer_sound_running_riot);
break;
case _game_engine_message_five_kills_in_row:
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x57);
else
format = L"";
ustrncpy(
buffer,
format,
buffer_size);
game_engine_play_multiplayer_sound(_multiplayer_sound_killing_spree);
break;
case _game_engine_message_killed_enemy:
other_player = player_get(message_data);
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x58);
else
format = L"";
usnprintf(
buffer,
buffer_size,
format,
other_player->name);
break;
case _game_engine_message_multi_kill_with_score:
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x59);
else
format = L"";
usnprintf(
buffer,
buffer_size,
format,
score);
game_engine_play_multiplayer_sound(_multiplayer_sound_killtacular_kill);
break;
case _game_engine_message_triple_kill_with_score:
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x5A);
else
format = L"";
usnprintf(
buffer,
buffer_size,
format,
score);
game_engine_play_multiplayer_sound(_multiplayer_sound_triple_kill);
break;
case _game_engine_message_double_kill_with_score:
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x5B);
else
format = L"";
usnprintf(
buffer,
buffer_size,
format,
score);
game_engine_play_multiplayer_sound(_multiplayer_sound_double_kill);
break;
case _game_engine_message_ten_kills_in_a_row_with_score:
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x5C);
else
format = L"";
usnprintf(
buffer,
buffer_size,
format,
score);
game_engine_play_multiplayer_sound(_multiplayer_sound_running_riot);
break;
case _game_engine_message_five_kills_in_row_with_score:
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x5D);
else
format = L"";
usnprintf(
buffer,
buffer_size,
format,
score);
game_engine_play_multiplayer_sound(_multiplayer_sound_killing_spree);
break;
case _game_engine_message_killed_enemy_with_score:
other_player = player_get(message_data);
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x5E);
else
format = L"";
usnprintf(
buffer,
buffer_size,
format,
other_player->name,
score);
break;
case _game_engine_message_odd_man_out:
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x5F);
else
format = L"";
ustrncpy(
buffer,
format,
buffer_size);
break;
case _game_engine_message_out_of_lives:
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x60);
else
format = L"";
ustrncpy(
buffer,
format,
buffer_size);
break;
case _game_engine_message_respawn_timer:
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x61);
else
format = L"";
usnprintf(
buffer,
buffer_size,
format,
message_data);
break;
case _game_engine_message_waiting_for_space_to_clear:
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x62);
else
format = L"";
ustrncpy(
buffer,
format,
buffer_size);
break;
case _game_engine_message_player_quit_self:
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x63);
else
format = L"";
ustrncpy(
buffer,
format,
buffer_size);
break;
case _game_engine_message_press_back_for_score:
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
format = unicode_string_list_get_string(string_list_index, 0x64);
else
format = L"";
ustrncpy(
buffer,
format,
buffer_size);
break;
default:
result = FALSE;
break;
}
buffer[buffer_size - 1] = 0;
return result;
}
static long adjust_score_for_ranking(
long score,
long player_index)
{
struct player_datum *player;
long result = 0;
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0x29D,
player_index!=NONE);
player = player_get(player_index);
if (score < -1000)
score = -1000;
score += 1000;
if (player->statistics.deaths <
global_variant.universal_variant.lives)
{
result = 0x40000000;
}
if (!player->quit_out_of_game)
result |= 0x20000000;
return result | score;
}
static long item_collection_get_total(
struct tag_block const *permutations)
{
struct item_permutation_definition const *permutation =
(struct item_permutation_definition const *)permutations->address;
long permutation_count = permutations->count;
long result = 0;
long permutation_index;
for (permutation_index = 0;
permutation_index < permutation_count;
permutation_index++)
{
result = (long)(
(real)result + permutation[permutation_index].weight);
}
return result;
}
static long random_item(
long item_collection_index)
{
struct item_collection_definition *definition =
item_collection_definition_get(item_collection_index);
struct tag_block *permutations = &definition->permutations;
long permutation_count = permutations->count;
long remaining_weight = seed_random_range(
get_global_random_seed_address(),
0,
(short)item_collection_get_total(permutations));
struct item_permutation_definition const *permutation =
permutations->address;
long permutation_index = 0;
while (permutation_index < permutation_count)
{
remaining_weight =
(long)((real)remaining_weight -
permutation[permutation_index].weight);
if (remaining_weight < 0)
return permutation[permutation_index].item.index;
permutation_index++;
}
return NONE;
}
static void game_engine_update_item_spawn(
void)
{
struct scenario *scenario = global_scenario_get();
short equipment_index;
/* a client of the distributed netcode has the host's items
(port/linux/game/network_distributed.c) */
if (network_game_distributed_client())
return;
for (equipment_index = 0;
equipment_index < scenario->netgame_equipment.count;
equipment_index++)
{
struct scenario_netgame_equipment *equipment =
TAG_BLOCK_GET_ELEMENT(
&scenario->netgame_equipment,
equipment_index,
struct scenario_netgame_equipment);
if (match_game_type(
game_engine_get_type(),
NUMBEROF(equipment->game_type),
equipment->game_type))
{
long respawn_period = 30 * TICKS_PER_SECOND;
short respawn_time = equipment->spawn_time;
if (respawn_time == 0)
{
if (equipment->item_collection.index != NONE)
{
struct item_collection_definition *item_collection =
item_collection_definition_get(
equipment->item_collection.index);
respawn_time = item_collection->spawn_time;
if (respawn_time != 0)
respawn_period = respawn_time * TICKS_PER_SECOND;
}
}
else
{
respawn_period = respawn_time * TICKS_PER_SECOND;
}
if (game_time_get() % respawn_period == 0)
{
long definition_index =
random_item(equipment->item_collection.index);
struct object_placement_data placement_data;
long object_index;
object_placement_data_new(
&placement_data,
definition_index,
NONE);
placement_data.position = equipment->position;
object_index = object_new(&placement_data);
if (object_index != NONE)
{
struct item_datum *item = item_get(object_index);
object_set_garbage(object_index, FALSE);
if (TEST_FLAG(
equipment->flags,
_equipment_created_at_rest_bit))
{
SET_FLAG(item->object.flags, _object_at_rest_bit, TRUE);
}
item->item.last_owned_time +=
respawn_period - 30 * TICKS_PER_SECOND;
}
}
}
}
return;
}
static void handle_custom_starting_equipment(
long unit_index,
long *fragmentation_grenade_count,
long *plasma_grenade_count)
{
struct scenario *scenario = global_scenario_get();
long starting_equipment_index;
for (starting_equipment_index = 0;
starting_equipment_index < scenario->scenario_starting_equipment.count;
starting_equipment_index++)
{
struct scenario_starting_equipment *starting_equipment = TAG_BLOCK_GET_ELEMENT(
&scenario->scenario_starting_equipment,
starting_equipment_index,
struct scenario_starting_equipment);
if (match_game_type(
game_engine_get_type(),
4,
starting_equipment->game_type))
{
boolean first_weapon = TRUE;
long item_collection_index;
/* January visits the first five of the six item collections */
for (item_collection_index = 0;
item_collection_index < 5;
item_collection_index++)
{
if (starting_equipment->item_collection[item_collection_index].index != NONE)
{
long definition_index = random_item(
starting_equipment->item_collection[item_collection_index].index);
long weapon_index;
struct object_placement_data placement_data;
object_placement_data_new(
&placement_data,
definition_index,
NONE);
weapon_index = object_new(&placement_data);
if (weapon_index != NONE)
{
struct object_datum *weapon = object_get_and_verify_type(
weapon_index,
_object_mask_item);
if (!first_weapon &&
unit_has_weapon_definition_index(
unit_index,
weapon->definition_index))
{
object_delete(weapon_index);
}
else
{
unit_add_weapon_to_inventory(
unit_index,
weapon_index,
first_weapon ? 2 : 0);
first_weapon = FALSE;
}
}
}
}
if (TEST_FLAG(starting_equipment->flags, _netgame_starting_equipment_flag_no_grenades_bit))
{
*fragmentation_grenade_count = 0;
*plasma_grenade_count = 0;
}
if (TEST_FLAG(starting_equipment->flags, _netgame_starting_equipment_flag_plasma_greandes_bit))
{
*plasma_grenade_count += *fragmentation_grenade_count;
*fragmentation_grenade_count = 0;
}
break;
}
}
return;
}
void game_engine_postspawn_player_update(
long player_index)
{
struct player_datum *player;
long unit_index;
struct game_globals_grenade *fragmentation_grenade;
struct game_globals_grenade *plasma_grenade;
long fragmentation_grenade_count;
long plasma_grenade_count;
if (!game_engine)
return;
if (game_engine->player_update)
{
game_engine->player_update(player_index);
return;
}
player = player_get(player_index);
unit_index = player->unit_index;
fragmentation_grenade = TAG_BLOCK_GET_ELEMENT(
&scenario_get_game_globals()->grenades,
_unit_grenade_human_fragmentation,
struct game_globals_grenade);
plasma_grenade = TAG_BLOCK_GET_ELEMENT(
&scenario_get_game_globals()->grenades,
_unit_grenade_covenant_plasma,
struct game_globals_grenade);
plasma_grenade_count = plasma_grenade->maximum_count;
fragmentation_grenade_count = fragmentation_grenade->maximum_count;
if (TEST_FLAG(game_engine_globals.flags, _game_engine_9_or_more_players_bit))
{
fragmentation_grenade_count = 1;
plasma_grenade_count = 1;
}
else if (TEST_FLAG(game_engine_globals.flags, _game_engine_5_or_more_players_bit))
{
fragmentation_grenade_count = 2;
plasma_grenade_count = 2;
}
{
long starting_fragmentation_grenade_count =
fragmentation_grenade_count;
long starting_plasma_grenade_count = 0;
if (!TEST_FLAG(global_variant.universal_variant.flags, _game_variant_generic_starting_equipment_bit))
{
handle_custom_starting_equipment(
unit_index,
&starting_fragmentation_grenade_count,
&starting_plasma_grenade_count);
}
if (game_engine_infinite_grenades_internal())
{
starting_plasma_grenade_count =
plasma_grenade_count;
starting_fragmentation_grenade_count =
fragmentation_grenade_count;
}
if (unit_index != NONE)
{
struct unit_datum *unit = object_get_and_verify_type(
unit_index,
_object_mask_unit);
switch (global_variant.universal_variant.weapon_set)
{
case _game_engine_weapons_plasma_weapons:
starting_plasma_grenade_count +=
starting_fragmentation_grenade_count;
starting_fragmentation_grenade_count = 0;
break;
case _game_engine_weapons_human:
starting_fragmentation_grenade_count +=
starting_plasma_grenade_count;
starting_plasma_grenade_count = 0;
break;
case _game_engine_weapons_no_grenades:
if (!game_engine_infinite_grenades_internal())
{
starting_fragmentation_grenade_count = 0;
starting_plasma_grenade_count = 0;
}
break;
}
starting_fragmentation_grenade_count = MIN(
starting_fragmentation_grenade_count,
fragmentation_grenade_count);
starting_plasma_grenade_count = MIN(
starting_plasma_grenade_count,
plasma_grenade_count);
unit->unit.grenade_counts[
_unit_grenade_human_fragmentation] =
(char)starting_fragmentation_grenade_count;
unit->unit.grenade_counts[
_unit_grenade_covenant_plasma] =
(char)starting_plasma_grenade_count;
}
}
return;
}
boolean game_engine_get_state_message(
long player_index,
wchar_t *message,
long message_character_count)
{
struct player_datum *player;
long state_message_parameter;
long state_message;
long respawn_timer;
boolean result = FALSE;
if (game_engine)
{
player = player_get(player_index);
if (player->state_message >= _game_engine_message_odd_man_out &&
player->state_message <=
_game_engine_message_waiting_for_space_to_clear)
{
player->state_message = NONE;
}
if (player->unit_index == NONE)
{
state_message_parameter = 0;
if (player->quit_out_of_game == TRUE)
state_message = _game_engine_message_player_quit_self;
else if (game_engine_player_is_out_of_lives(player_index))
state_message = _game_engine_message_out_of_lives;
else if (game_engine_player_is_odd_man_out(player_index))
state_message = _game_engine_message_odd_man_out;
else
{
respawn_timer = player->respawn_timer;
if (respawn_timer > 0)
{
state_message = _game_engine_message_respawn_timer;
state_message_parameter = respawn_timer / TICKS_PER_SECOND;
}
else
state_message =
_game_engine_message_waiting_for_space_to_clear;
}
result = multiplayer_message_internal(
player_index,
state_message,
state_message_parameter,
message,
message_character_count);
}
else if (game_time_get() < 15 * TICKS_PER_SECOND)
{
result = multiplayer_message_internal(
player_index,
_game_engine_message_press_back_for_score,
NONE,
message,
message_character_count);
}
else if (player->state_message != NONE)
{
result = multiplayer_message_internal(
player_index,
player->state_message,
player->state_message_player_index,
message,
message_character_count);
}
}
return result;
}
/* port: a distributed client's players spawn when the host spawns them
(network_player_attach_unit), but their respawn countdown runs here as it
does on the host (game_engine_should_spawn_player), for the hud's count and
its sounds: it stops a tick short, where the host's unit ends it */
void game_engine_client_respawn_countdown(
long player_index)
{
struct player_datum *player;
if (!game_engine)
return;
player = player_get(player_index);
if (player->quit_out_of_game == TRUE ||
player->statistics.deaths == 0 ||
player->respawn_timer <= 1 ||
game_engine_player_is_out_of_lives(player_index) ||
game_engine_player_is_odd_man_out(player_index) ||
game_engine_globals.postgame_state == game_engine_mode_postgame_rasterize ||
game_engine_globals.postgame_state == game_engine_mode_postgame_rasterize_delay)
{
return;
}
if (player->local_player_index != NONE &&
(player->respawn_timer == 90 || player->respawn_timer == 60 || player->respawn_timer == 30))
{
game_engine_play_multiplayer_sound(_multiplayer_sound_countdown_for_respawn);
}
player->respawn_timer--;
if (player->local_player_index != NONE && player->respawn_timer == 1)
game_engine_play_multiplayer_sound(_multiplayer_sound_respawn);
return;
}
boolean game_engine_should_spawn_player(
long player_index)
{
boolean should_spawn = FALSE;
if (game_engine)
{
struct player_datum *player = player_get(player_index);
if (player->quit_out_of_game == TRUE)
{
should_spawn = FALSE;
}
else if (player->statistics.deaths == 0)
{
should_spawn = TRUE;
}
else if (game_engine_player_is_out_of_lives(player_index))
{
should_spawn = FALSE;
}
else if (game_engine_player_is_odd_man_out(player_index))
{
should_spawn = FALSE;
}
else if (game_engine_globals.postgame_state ==
game_engine_mode_postgame_rasterize ||
game_engine_globals.postgame_state ==
game_engine_mode_postgame_rasterize_delay)
{
should_spawn = FALSE;
}
else
{
long respawn_timer = player->respawn_timer;
if (respawn_timer > 0)
{
if (player->local_player_index != NONE)
{
if (respawn_timer == 90)
{
game_engine_play_multiplayer_sound(
_multiplayer_sound_countdown_for_respawn);
}
else if (respawn_timer == 60)
{
game_engine_play_multiplayer_sound(
_multiplayer_sound_countdown_for_respawn);
}
else if (respawn_timer == 30)
{
game_engine_play_multiplayer_sound(
_multiplayer_sound_countdown_for_respawn);
}
else if (respawn_timer == 1)
{
game_engine_play_multiplayer_sound(
_multiplayer_sound_respawn);
}
}
player->respawn_timer--;
should_spawn = player->respawn_timer == 0;
}
else
{
should_spawn = TRUE;
}
}
if (should_spawn &&
game_time_get() > 3 &&
game_time_get() % 32 !=
DATUM_INDEX_TO_ABSOLUTE_INDEX(player_index) % 32)
{
should_spawn = FALSE;
}
}
return should_spawn;
}
struct game_engine_place game_engine_get_place(
long player_index,
enum get_score_type score_type)
{
struct player_datum *player;
long group_count;
boolean tied;
boolean all_tied;
struct game_engine_place result;
player = player_get(player_index);
all_tied = TRUE;
tied = FALSE;
group_count = 1;
result.place = 0;
if (game_engine->get_player_score)
{
struct data_iterator iterator;
struct player_datum *other_player;
/* port: free-for-all team indices run up to the player limit */
unsigned long team_mask[BIT_VECTOR_SIZE_IN_LONGS(MULTIPLAYER_MAXIMUM_PLAYERS)] = { 0 };
long score = game_engine->get_player_score(player_index, score_type);
data_iterator_new(&iterator, player_data);
other_player = (struct player_datum *)data_iterator_next(&iterator);
while (other_player)
{
boolean different_player;
if (score_type == _get_score_team)
{
different_player =
other_player->team_index != player->team_index;
}
else
different_player = iterator.datum_index != player_index;
if (different_player &&
score_type == _get_score_team)
{
/* a team outside the mask (none yet) counts on its own */
if (VALID_INDEX(other_player->team_index, MULTIPLAYER_MAXIMUM_PLAYERS))
{
if (BIT_VECTOR_TEST_FLAG(team_mask, other_player->team_index))
different_player = FALSE;
else
BIT_VECTOR_SET_FLAG(team_mask, other_player->team_index, TRUE);
}
}
if (different_player)
{
long other_score = game_engine->get_player_score(
iterator.datum_index,
score_type);
group_count++;
if (other_score != score)
all_tied = FALSE;
if (other_score > score)
result.place++;
else if (other_score == score)
tied = TRUE;
}
other_player =
(struct player_datum *)data_iterator_next(&iterator);
}
match_vassert(
"c:\\halo\\SOURCE\\game\\game_engine.c",
0x1377,
!all_tied || tied || group_count == 1,
"(!all_tied || (tied)) || (1 == group_count)");
}
all_tied &= tied;
result.flags = score_type != _get_score_team
? 0
: FLAG(_place_team);
SET_FLAG(result.flags, _place_tied, tied);
SET_FLAG(
result.flags,
_place_all_tied,
all_tied);
SET_FLAG(
result.flags,
_place_two_groups,
group_count == 2);
return result;
}
static void netgame_verify_spawn_points(
short game_type,
short unused_team_index,
short minimum_count,
char const *error_message)
{
short starting_location_count;
long matching_count;
short starting_location_index;
starting_location_count = player_get_starting_location_count();
matching_count = 0;
for (starting_location_index = 0;
starting_location_index < starting_location_count;
starting_location_index++)
{
struct player_starting_location *starting_location =
player_get_starting_location(starting_location_index);
if (match_game_type(
game_type,
4,
starting_location->game_types))
{
matching_count++;
}
}
if (matching_count < minimum_count)
{
error(
_error_silent,
error_message,
matching_count,
minimum_count);
}
return;
}
long game_engine_slayer_write_network_state(byte *buffer, long size);
boolean game_engine_slayer_read_network_state(byte const *buffer, long size, boolean first);
long game_engine_ctf_write_network_state(byte *buffer, long size);
boolean game_engine_ctf_read_network_state(byte const *buffer, long size, boolean first);
long game_engine_oddball_write_network_state(byte *buffer, long size);
boolean game_engine_oddball_read_network_state(byte const *buffer, long size, boolean first);
long game_engine_king_write_network_state(byte *buffer, long size);
boolean game_engine_king_read_network_state(byte const *buffer, long size, boolean first);
long game_engine_race_write_network_state(byte *buffer, long size);
boolean game_engine_race_read_network_state(byte const *buffer, long size, boolean first);
/* the distributed netcode (port/linux/game/network_damage.c): a player's
score as the game type has it (with its killing blows' messages), 0 for
none */
long game_engine_network_player_score(
long player_index)
{
if (!game_engine || !game_engine->get_player_score)
return 0;
return game_engine->get_player_score(player_index, TRUE);
}
/* the distributed netcode (port/linux/game/network_distributed.c): the
current game type's state (scores, and what else every machine must agree
on), which the host sends its clients; the size written, 0 for none */
long game_engine_write_network_state(
byte *buffer,
long size)
{
long postgame_state;
long written;
if (!game_engine || size < (long)sizeof(postgame_state))
return 0;
/* whether the game is over, then the game type's */
postgame_state = game_engine_globals.postgame_state;
csmemcpy(buffer, &postgame_state, sizeof(postgame_state));
buffer += sizeof(postgame_state);
size -= sizeof(postgame_state);
switch (game_engine_get_type())
{
case game_engine_ctf: written = game_engine_ctf_write_network_state(buffer, size); break;
case game_engine_slayer: written = game_engine_slayer_write_network_state(buffer, size); break;
case game_engine_oddball: written = game_engine_oddball_write_network_state(buffer, size); break;
case game_engine_king: written = game_engine_king_write_network_state(buffer, size); break;
case game_engine_race: written = game_engine_race_write_network_state(buffer, size); break;
default: written = 0; break;
}
return sizeof(postgame_state) + written;
}
/* a client: the host's */
void game_engine_read_network_state(
byte const *buffer,
long size)
{
long postgame_state;
boolean first;
boolean read;
if (!game_engine || size < (long)sizeof(postgame_state))
return;
csmemcpy(&postgame_state, buffer, sizeof(postgame_state));
buffer += sizeof(postgame_state);
size -= sizeof(postgame_state);
first = !game_engine_network_state_read;
switch (game_engine_get_type())
{
case game_engine_ctf: read = game_engine_ctf_read_network_state(buffer, size, first); break;
case game_engine_slayer: read = game_engine_slayer_read_network_state(buffer, size, first); break;
case game_engine_oddball: read = game_engine_oddball_read_network_state(buffer, size, first); break;
case game_engine_king: read = game_engine_king_read_network_state(buffer, size, first); break;
case game_engine_race: read = game_engine_race_read_network_state(buffer, size, first); break;
default: read = TRUE; break;
}
/* (a state the game type refused is not had: the first it takes is,
whose events it only takes) */
if (!read)
return;
game_engine_network_state_read = TRUE;
/* the game ended on the host (after what ended it is shown, as the host
shows it) */
if (postgame_state != 0 && game_engine_globals.postgame_state == 0)
game_engine_end_game();
}