Files
Cesarus85--mjolnir-vr/source/game/game_engine_king.c
T

1029 lines
25 KiB
C

/*
GAME_ENGINE_KING.C
symbols in this file:
000A0030 0010:
_king_engine_dispose (0000)
000A0040 0020:
_hill_points_to_2d (0000)
000A0060 0350:
_find_hill (0000)
000A03B0 0010:
_king_engine_dispose_from_old_map (0000)
000A03C0 0020:
_king_engine_player_added (0000)
000A03E0 0010:
_king_engine_game_ending (0000)
000A03F0 0020:
_king_engine_game_starting (0000)
000A0410 0010:
_king_engine_statistics_append (0000)
000A0420 0010:
_king_engine_handle_client_message (0000)
000A0430 0010:
_king_engine_handle_server_message (0000)
000A0440 0010:
_king_engine_pregame_post_rasterize (0000)
000A0450 0090:
_player_inside_hill (0000)
000A04E0 0160:
_king_engine_player_update (0000)
000A0640 01c0:
_king_calculate_hill_state (0000)
000A0800 0010:
_king_engine_player_damaged_player (0000)
000A0810 0010:
_king_engine_player_killed_player (0000)
000A0820 0190:
_king_engine_display_score (0000)
000A09B0 0010:
_king_engine_prespawn_player_update (0000)
000A09C0 0040:
_king_get_score (0000)
000A0A00 0090:
_render_dynamic_quad_initialize (0000)
000A0A90 02b0:
_render_dynamic_quad (0000)
000A0D40 0040:
_king_get_score_string (0000)
000A0D80 0060:
_king_get_score_header_string (0000)
000A0DE0 0030:
_king_get_team_score_string (0000)
000A0E10 0020:
_king_engine_goal_matches_player (0000)
000A0E30 0070:
_find_next_hill (0000)
000A0EA0 0110:
_king_engine_initialize_for_new_map (0000)
000A0FB0 03a0:
_king_engine_post_rasterize (0000)
000A1350 0110:
_king_engine_update (0000)
0025BDC0 000d:
??_C@_0N@DGPCNCJC@NULL?5?$CB?$DN?5flag?$AA@ (0000)
0025BDD0 0027:
??_C@_0CH@IHPMMFJJ@c?3?2halo?2SOURCE?2game?2game_engine_@ (0000)
0025BDF8 0023:
??_C@_0CD@DHKICDEA@king_globals?4hill_point_count?5?$CB?$DN@ (0000)
0025BE1C 0014:
??_C@_0BE@EEOONBNI@FAILED?5TO?5FIND?5HILL?$AA@ (0000)
0025BE30 000b:
??_C@_0L@HEFOOJCG@crown_blue?$AA@ (0000)
0025BE3C 0038:
??_C@_0DI@GPEOKAOO@failed?5to?5find?5hill?5?$CD?$CFd?5most?5lik@ (0000)
002DE488 0088:
_king_engine (0000)
0043E948 0230:
_king_globals (0000)
*/
/* ---------- headers */
#include "cseries/cseries.h"
#include "cseries/errors.h"
#include "game/game_engine_king.h"
#include "game/game_engine_place.h"
#include "game/players.h"
#include "main/console.h"
#include "math/geometry.h"
#include "rasterizer/rasterizer.h"
#include "rasterizer/rasterizer_geometry.h"
#include "render/render.h"
#include "scenario/scenario.h"
#include "scenario/scenario_definitions.h"
#include "shaders/shader_definitions.h"
#include "shaders/shaders.h"
#include "tag_files/tag_groups.h"
#include "text/text_group.h"
#include "text/unicode.h"
#include "units/units.h"
/* ---------- constants */
enum
{
MAXIMUM_KING_SCORE_SLOTS = 16,
MAXIMUM_HILL_POINTS = 12,
MAXIMUM_HILLS = 64,
NUMBER_OF_DEFAULT_ANIMATION_VALUES = 4,
HILL_MOVE_TIME = TICKS_PER_MINUTE,
HILL_CONTROL_TIME = 10*TICKS_PER_SECOND,
HILL_SCORE_SOUND_INTERVAL = 5*TICKS_PER_SECOND,
HILL_30_SECOND_WARNING = 30*TICKS_PER_SECOND,
HILL_60_SECOND_WARNING = TICKS_PER_MINUTE,
};
enum
{
_multiplayer_sound_60_seconds = 0x2,
_multiplayer_sound_30_seconds,
_multiplayer_sound_red_60_seconds,
_multiplayer_sound_red_30_seconds,
_multiplayer_sound_blue_60_seconds,
_multiplayer_sound_blue_30_seconds,
_multiplayer_sound_hill_move = 0x1E,
_multiplayer_sound_team_king = 0x20,
_multiplayer_sound_king = 0x24,
_multiplayer_sound_hill_contested = 0x27,
_multiplayer_sound_hill_controlled,
_multiplayer_sound_countdown_timer_end = 0x2A,
};
enum
{
_string_place_score_seconds = 0x9B,
_string_ally_name_is_on_the_hill_score_seconds,
_string_enemy_name_is_on_the_hill_score_seconds,
_string_time,
_rasterizer_lock_dynamic_quad = 9,
};
/* ---------- macros */
/* ---------- structures */
/* Target-proven vertex layouts used by this translation unit's quad helper. */
struct model_vertex_uncompressed
{
real_point3d position;
real_vector3d normal;
real_vector3d binormal;
real_vector3d tangent;
real_point2d texcoord;
short nodes[2];
real node_weights[2];
};
struct model_vertex_compressed
{
real_point3d position;
unsigned long normal;
unsigned long binormal;
unsigned long tangent;
point2d texcoord;
byte nodes[2];
short node_weight;
};
typedef char verify_model_vertex_uncompressed_size[
sizeof(struct model_vertex_uncompressed) == 0x44 ? 1 : -1];
typedef char verify_model_vertex_compressed_size[
sizeof(struct model_vertex_compressed) == 0x20 ? 1 : -1];
/* January-local render packet layouts used by render_dynamic_quad. */
struct rasterizer_model_skinning
{
real_matrix4x3 const *node_matrices;
short node_matrix_count;
word pad;
};
struct render_model_effect
{
short type;
word pad;
real intensity;
byte reserved[0x20];
};
struct rasterizer_model_begin_parameters
{
unsigned long geometry_flags;
long unique_identifier;
struct rasterizer_model_skinning skinning;
struct render_lighting lighting;
struct render_animation animation;
struct render_model_effect effect;
real_point3d centroid;
real radius;
real_vector2d base_map_scale;
};
typedef char verify_rasterizer_model_begin_parameters_size[
sizeof(struct rasterizer_model_begin_parameters) == 0xCC ? 1 : -1];
/* January scenario flag layout consumed by the King map scan. */
struct scenario_netgame_flag
{
real_point3d position;
real facing;
short type;
short team_index;
byte unused[0x80];
};
typedef char verify_scenario_netgame_flag_size[
sizeof(struct scenario_netgame_flag) == 0x94 ? 1 : -1];
typedef char verify_scenario_netgame_flags_offset[
offsetof(struct scenario, netgame_flags) == 0x378 ? 1 : -1];
/* ---------- prototypes */
static void hill_points_to_2d(
real_point3d const *points,
real_point2d *points2d,
long point_count);
static void find_hill(
void);
static long find_next_hill(
long hill_id);
static boolean player_inside_hill(
long player_index);
static void king_calculate_hill_state(
void);
/* ---------- globals */
/* Shared rasterizer defaults, named by the January image. */
extern real_rgb_color global_default_animation_colors[4];
extern real global_default_animation_values[4];
struct king_globals king_globals = { 0 };
static short king_engine_hill_count = 0;
static short king_engine_hills[MAXIMUM_HILLS] = { 0 };
/* ---------- public code */
void king_engine_dispose(
void)
{
return;
}
void king_engine_dispose_from_old_map(
void)
{
return;
}
void king_engine_game_ending(
void)
{
return;
}
void king_engine_statistics_append(
long statistic)
{
return;
}
void king_engine_handle_client_message(
void *message)
{
return;
}
void king_engine_handle_server_message(
void *message)
{
return;
}
void king_engine_pregame_post_rasterize(
void)
{
return;
}
void king_engine_player_damaged_player(
long damaging_player_index,
long dead_player_index,
boolean damage_type)
{
return;
}
void king_engine_player_killed_player(
long killing_player_index,
long killing_object_index,
long dead_player_index,
boolean friendly_fire)
{
return;
}
void king_engine_prespawn_player_update(
long player_index)
{
return;
}
void king_engine_player_added(
long player_index)
{
player_get(player_index);
return;
}
void king_engine_game_starting(
void)
{
game_engine_play_multiplayer_sound(
game_engine_has_teams() ?
_multiplayer_sound_team_king :
_multiplayer_sound_king);
return;
}
wchar_t *king_get_score_string(
long player_index,
wchar_t *buffer)
{
struct player_datum *player = player_get(player_index);
ticks_to_unicode_time_string(
player->statistics.multiplayer_statistics.king_statistics.time_on_hill,
256,
buffer);
return buffer;
}
wchar_t *king_get_team_score_string(
long team_index,
wchar_t *buffer)
{
ticks_to_unicode_time_string(
king_globals.score[team_index],
256,
buffer);
return buffer;
}
boolean king_engine_initialize_for_new_map(
void)
{
struct scenario *scenario = global_scenario_get();
short flag_index;
csmemset(&king_globals, 0, sizeof(king_globals));
king_engine_hill_count = 0;
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_hill)
{
boolean found = FALSE;
short hill_index;
for (hill_index = 0; hill_index < king_engine_hill_count; hill_index++)
{
if (king_engine_hills[hill_index] == flag->team_index)
{
found = TRUE;
break;
}
}
if (!found)
king_engine_hills[king_engine_hill_count++] = flag->team_index;
}
}
king_globals.hill_id = 0;
king_globals.hill_timer = HILL_MOVE_TIME;
king_globals.hill_previous_controller = NONE;
king_globals.hill_state = king_hill_uncontrolled;
find_hill();
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine_king.c",
0x154,
king_globals.hill_point_count != 0);
render_dynamic_quad_initialize();
return TRUE;
}
void king_engine_player_update(
long player_index)
{
struct player_datum *player = player_get(player_index);
game_engine_state_message(player_index, NONE, NONE);
king_globals.on_the_hill[DATUM_INDEX_TO_ABSOLUTE_INDEX(player_index)] = FALSE;
if (player->unit_index != NONE)
{
struct unit_datum *unit = unit_get(player->unit_index);
if (game_engine_can_score() && player_inside_hill(player_index))
{
king_globals.on_the_hill[DATUM_INDEX_TO_ABSOLUTE_INDEX(player_index)] = TRUE;
player->statistics.multiplayer_statistics.king_statistics.time_on_hill++;
if (king_globals.score_tick[player->team_index] < game_time_get())
{
long score_to_win;
long score;
king_globals.score[player->team_index]++;
king_globals.score_tick[player->team_index] = game_time_get();
score_to_win = game_engine_get_variant()->unknown40*TICKS_PER_MINUTE;
score = king_globals.score[player->team_index];
if (score_to_win - score == HILL_30_SECOND_WARNING)
{
if (game_engine_has_teams())
{
game_engine_play_multiplayer_sound(
player->team_index ?
_multiplayer_sound_blue_30_seconds :
_multiplayer_sound_red_30_seconds);
}
else
{
game_engine_play_multiplayer_sound(_multiplayer_sound_30_seconds);
}
}
if (score_to_win - score == HILL_60_SECOND_WARNING)
{
if (game_engine_has_teams())
{
game_engine_play_multiplayer_sound(
player->team_index ?
_multiplayer_sound_blue_60_seconds :
_multiplayer_sound_red_60_seconds);
}
else
{
game_engine_play_multiplayer_sound(_multiplayer_sound_60_seconds);
}
}
if (king_globals.score[player->team_index] > 0 &&
king_globals.score[player->team_index] % HILL_SCORE_SOUND_INTERVAL == 0 &&
king_globals.score[player->team_index] < score_to_win)
{
game_engine_play_multiplayer_sound(_multiplayer_sound_countdown_timer_end);
}
if (score >= score_to_win)
game_engine_end_game();
}
game_engine_state_message(player_index, king_message_you_are_on_the_hill, player_index);
}
}
return;
}
boolean king_engine_display_score(
long player_index,
long message,
long message_player_index,
wchar_t *buffer,
long buffer_size)
{
struct player_datum *player = player_get(player_index);
boolean result = TRUE;
long string_list_index;
wchar_t *string;
switch (message)
{
case king_message_enemy_on_the_hill:
case king_message_ally_on_the_hill:
case king_message_you_are_on_the_hill:
{
struct player_datum *other_player = player_get(message_player_index);
long score = king_globals.score[other_player->team_index]/TICKS_PER_SECOND;
if (message == king_message_you_are_on_the_hill)
{
wchar_t *place_name = get_place_name(
game_engine_get_place(player_index, _get_score_team));
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
{
string = unicode_string_list_get_string(
string_list_index,
_string_place_score_seconds);
}
else
string = L"";
usnprintf(buffer, buffer_size, string, place_name, score);
}
else if (message == king_message_ally_on_the_hill)
{
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
{
string = unicode_string_list_get_string(
string_list_index,
_string_ally_name_is_on_the_hill_score_seconds);
}
else
string = L"";
usnprintf(buffer, buffer_size, string, other_player->name, score);
}
else if (message == king_message_enemy_on_the_hill)
{
string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
if (string_list_index != NONE)
{
string = unicode_string_list_get_string(
string_list_index,
_string_enemy_name_is_on_the_hill_score_seconds);
}
else
string = L"";
usnprintf(buffer, buffer_size, string, other_player->name, score);
}
else
{
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine_king.c",
0x3A2,
!"unreachable");
}
}
break;
default:
result = FALSE;
break;
}
return result;
}
long king_get_score(
long player_index,
enum get_score_type score_type)
{
struct player_datum *player = player_get(player_index);
if (score_type == _get_score_individual)
return player->statistics.multiplayer_statistics.king_statistics.time_on_hill;
return king_globals.score[player->team_index];
}
void render_dynamic_quad_initialize(
void)
{
short i;
global_default_animation_colors[0] = *global_real_rgb_white;
global_default_animation_colors[1] = *global_real_rgb_white;
global_default_animation_colors[2] = *global_real_rgb_white;
global_default_animation_colors[3] = *global_real_rgb_white;
for (i = 0; i < NUMBER_OF_DEFAULT_ANIMATION_VALUES; i++)
global_default_animation_values[i] = 0.0f;
return;
}
void render_dynamic_quad(
struct model_vertex_uncompressed *verts,
long shader_index,
struct render_lighting const *lighting,
struct render_animation const *animation,
real u_scale,
real v_scale)
{
long triangle_buffer_index;
long vertex_buffer_index;
rasterizer_globals.current_lock_operation = _rasterizer_lock_dynamic_quad;
triangle_buffer_index = rasterizer_dynamic_triangles_new(2);
vertex_buffer_index = rasterizer_dynamic_vertices_new(_rasterizer_vertex_type_model_compressed, 4);
if (triangle_buffer_index != NONE && vertex_buffer_index != NONE)
{
void *vertices = rasterizer_dynamic_vertices_lock(vertex_buffer_index);
short *triangles = rasterizer_dynamic_triangles_lock(triangle_buffer_index);
struct rasterizer_model_begin_parameters parameters;
real_point3d centroid;
struct shader *shader;
rasterizer_geometry_compress_vertices(
_rasterizer_vertex_type_model_uncompressed,
4,
vertices,
4*sizeof(struct model_vertex_compressed),
verts,
4*sizeof(struct model_vertex_uncompressed));
triangles[0] = 0;
triangles[1] = 1;
triangles[2] = 2;
triangles[3] = 2;
triangles[4] = 3;
triangles[5] = 0;
rasterizer_dynamic_triangles_unlock(triangle_buffer_index);
rasterizer_dynamic_vertices_unlock(vertex_buffer_index);
shader = shader_definition_get(shader_index);
centroid.x = (verts[0].position.x + verts[1].position.x + verts[2].position.x + verts[3].position.x)*0.25f;
centroid.y = (verts[0].position.y + verts[1].position.y + verts[2].position.y + verts[3].position.y)*0.25f;
centroid.z = (verts[0].position.z + verts[1].position.z + verts[2].position.z + verts[3].position.z)*0.25f;
csmemset(&parameters, 0, sizeof(parameters));
parameters.unique_identifier = 1;
parameters.skinning.node_matrices = global_identity4x3;
parameters.skinning.node_matrix_count = 1;
if (lighting)
{
parameters.lighting = *lighting;
}
else
{
parameters.lighting.ambient_color = *global_real_rgb_white;
parameters.lighting.distant_light_count = 0;
parameters.lighting.point_light_count = 0;
parameters.lighting.reflection_tint_color = *global_real_argb_white;
parameters.lighting.shadow_vector.i = 0.0f;
parameters.lighting.shadow_vector.j = 1.0f;
parameters.lighting.shadow_vector.k = 0.0f;
parameters.lighting.shadow_color = *global_real_rgb_black;
}
if (animation)
{
parameters.animation = *animation;
}
else
{
parameters.animation.colors = global_default_animation_colors;
parameters.animation.values = global_default_animation_values;
}
parameters.centroid = centroid;
parameters.base_map_scale.i = u_scale;
parameters.base_map_scale.j = v_scale;
rasterizer_profile_enable(FALSE);
rasterizer_models_begin(FALSE);
rasterizer_model_begin(&parameters, TRUE);
if (shader_type_is_transparent(shader->base.type))
{
rasterizer_model_transparent_geometry_submit(
shader,
0,
NULL,
triangle_buffer_index,
2,
NULL,
vertex_buffer_index,
&centroid,
NULL);
}
else
{
rasterizer_model_draw(
shader,
0,
NULL,
triangle_buffer_index,
2,
NULL,
vertex_buffer_index);
}
rasterizer_model_end();
rasterizer_models_end();
rasterizer_profile_enable(TRUE);
rasterizer_dynamic_triangles_delete(triangle_buffer_index);
rasterizer_dynamic_vertices_delete(vertex_buffer_index);
}
rasterizer_globals.current_lock_operation = _rasterizer_lock_unlocked;
return;
}
wchar_t *king_get_score_header_string(
wchar_t *buffer)
{
long string_list_index = tag_loaded('ustr', "ui\\multiplayer_game_text");
wchar_t const *string;
if (string_list_index != NONE)
{
string = unicode_string_list_get_string(
string_list_index,
_string_time);
}
else
{
string = L"";
}
ustrcpy(buffer, string);
return buffer;
}
boolean king_engine_goal_matches_player(
long player_index,
long goal_index)
{
boolean matches = !king_globals.on_the_hill[DATUM_INDEX_TO_ABSOLUTE_INDEX(player_index)];
return matches;
}
void king_engine_update(
void)
{
if (game_engine_can_score() &&
game_engine_get_variant()->unknown4C.byte0 &&
--king_globals.hill_timer == 0)
{
king_globals.hill_timer = HILL_MOVE_TIME;
king_globals.hill_id = find_next_hill(king_globals.hill_id);
find_hill();
game_engine_play_multiplayer_sound(_multiplayer_sound_hill_move);
while (king_globals.hill_point_count == 0)
{
error(2, "failed to find hill #%d most likely bad point placement", king_globals.hill_id);
if (king_globals.hill_id == 0)
break;
king_globals.hill_id = find_next_hill(king_globals.hill_id);
find_hill();
game_engine_play_multiplayer_sound(_multiplayer_sound_hill_move);
}
}
if (king_globals.hill_point_count > 0)
{
real_point3d position = king_globals.hill_center;
game_engine_set_goal_position(0, &position, 0.0f, "crown_blue", NONE, NONE, NONE);
}
else
{
console_printf(FALSE, "FAILED TO FIND HILL");
}
king_calculate_hill_state();
return;
}
/* ---------- private code */
static void hill_points_to_2d(
real_point3d const *points,
real_point2d *points2d,
long point_count)
{
long i;
for (i = 0; i < point_count; i++)
{
points2d[i].x = points[i].x;
points2d[i].y = points[i].y;
}
return;
}
static void find_hill(
void)
{
struct scenario *scenario = global_scenario_get();
long flag_indices[MAXIMUM_HILL_POINTS];
real_point3d points[MAXIMUM_HILL_POINTS];
real_point2d points2d[MAXIMUM_HILL_POINTS];
short hull_indices[MAXIMUM_HILL_POINTS];
real_point3d minimum, maximum;
long point_count;
short hull_point_count;
long i;
point_count = find_netgame_flags(
NULL,
0.0f,
0.0f,
_netgame_flag_hill,
(short)king_globals.hill_id,
MAXIMUM_HILL_POINTS,
flag_indices);
king_globals.hill_point_count = point_count;
if (point_count)
{
for (i = 0; i < point_count; i++)
{
struct scenario_netgame_flag *flag = TAG_BLOCK_GET_ELEMENT(
&scenario->netgame_flags,
flag_indices[i],
struct scenario_netgame_flag);
match_assert(
"c:\\halo\\SOURCE\\game\\game_engine_king.c",
0xDE,
NULL != flag);
points[i] = flag->position;
}
if (point_count == 1)
{
points[1] = points[0];
points[2] = points[0];
points[3] = points[0];
points[0].x -= 1.0f;
points[0].y -= 1.0f;
points[1].x += 1.0f;
points[1].y -= 1.0f;
points[2].x -= 1.0f;
points[2].y += 1.0f;
points[3].x += 1.0f;
points[3].y += 1.0f;
point_count = 4;
}
hill_points_to_2d(points, points2d, point_count);
hull_point_count = convex_hull2d(point_count, points2d, hull_indices);
for (i = 0; i < hull_point_count; i++)
{
king_globals.hill_points[i] = points[hull_indices[i]];
king_globals.convex_hull[i] = points2d[hull_indices[i]];
}
king_globals.hill_point_count = hull_point_count;
minimum = king_globals.hill_points[0];
maximum = king_globals.hill_points[0];
for (i = 0; i < hull_point_count; i++)
{
real_point3d *point = &king_globals.hill_points[i];
minimum.x = MIN(minimum.x, point->x);
minimum.y = MIN(minimum.y, point->y);
minimum.z = MIN(minimum.z, point->z);
maximum.x = MAX(maximum.x, point->x);
maximum.y = MAX(maximum.y, point->y);
maximum.z = MAX(maximum.z, point->z);
}
king_globals.hill_bottom = minimum.z - 0.1f;
king_globals.hill_top = maximum.z + 0.8f;
king_globals.hill_center.x = (maximum.x + minimum.x)*0.5f;
king_globals.hill_center.y = (maximum.y + minimum.y)*0.5f;
king_globals.hill_center.z = (maximum.z + minimum.z)*0.5f;
}
return;
}
static boolean player_inside_hill(
long player_index)
{
boolean inside = 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);
real_point3d const *position = &unit->object.bounding_sphere_center;
if (position->z >= king_globals.hill_bottom && position->z <= king_globals.hill_top)
{
real_point2d point;
point.x = position->x;
point.y = position->y;
inside = convex_hull2d_test_point(
king_globals.hill_point_count,
king_globals.convex_hull,
&point,
0.0f);
}
}
}
return inside;
}
static void king_calculate_hill_state(
void)
{
struct data_iterator iterator;
struct player_datum *player;
long player_count = 0;
if (game_engine_has_teams())
{
long enemy_count = 0;
data_iterator_new(&iterator, player_data);
player = (struct player_datum *)data_iterator_next(&iterator);
while (player)
{
if (king_globals.on_the_hill[DATUM_INDEX_TO_ABSOLUTE_INDEX(iterator.datum_index)])
{
if (player->team_index)
enemy_count++;
else
player_count++;
}
player = (struct player_datum *)data_iterator_next(&iterator);
}
if (enemy_count)
{
if (player_count)
{
king_globals.hill_state = king_hill_contested;
if (king_globals.hill_controlled_count > HILL_CONTROL_TIME)
game_engine_play_multiplayer_sound(_multiplayer_sound_hill_contested);
king_globals.hill_controlled_count = 0;
}
else
{
if (king_globals.hill_state == king_hill_controlled_blue)
king_globals.hill_controlled_count++;
else
king_globals.hill_controlled_count = 0;
king_globals.hill_state = king_hill_controlled_blue;
if (king_globals.hill_controlled_count == HILL_CONTROL_TIME)
game_engine_play_multiplayer_sound(_multiplayer_sound_hill_controlled);
}
}
else if (player_count)
{
if (king_globals.hill_state == king_hill_controlled_red)
king_globals.hill_controlled_count++;
else
king_globals.hill_controlled_count = 0;
king_globals.hill_state = king_hill_controlled_red;
if (king_globals.hill_controlled_count == HILL_CONTROL_TIME)
game_engine_play_multiplayer_sound(_multiplayer_sound_hill_controlled);
}
else
{
king_globals.hill_state = king_hill_uncontrolled;
king_globals.hill_controlled_count = 0;
}
}
else
{
long controller;
data_iterator_new(&iterator, player_data);
player = (struct player_datum *)data_iterator_next(&iterator);
while (player)
{
if (king_globals.on_the_hill[DATUM_INDEX_TO_ABSOLUTE_INDEX(iterator.datum_index)])
{
controller = iterator.datum_index;
player_count++;
}
player = (struct player_datum *)data_iterator_next(&iterator);
}
if (player_count > 1)
{
king_globals.hill_state = king_hill_contested;
if (king_globals.hill_controlled_count > HILL_CONTROL_TIME)
game_engine_play_multiplayer_sound(_multiplayer_sound_hill_contested);
king_globals.hill_controlled_count = 0;
king_globals.hill_previous_controller = NONE;
}
else if (player_count)
{
if (king_globals.hill_state == king_hill_controlled &&
controller == king_globals.hill_previous_controller)
{
king_globals.hill_controlled_count++;
}
else
{
king_globals.hill_controlled_count = 0;
king_globals.hill_previous_controller = controller;
}
king_globals.hill_state = king_hill_controlled;
if (king_globals.hill_controlled_count == HILL_CONTROL_TIME)
game_engine_play_multiplayer_sound(_multiplayer_sound_hill_controlled);
}
else
{
king_globals.hill_state = king_hill_uncontrolled;
king_globals.hill_controlled_count = 0;
king_globals.hill_previous_controller = NONE;
}
}
return;
}
static long find_next_hill(
long hill_id)
{
long next_hill_id;
short start_index = random_range(0, king_engine_hill_count);
short i;
for (i = 0; i < king_engine_hill_count; i++)
{
short hill_index = (start_index + i)%king_engine_hill_count;
if (hill_id != king_engine_hills[hill_index])
return king_engine_hills[hill_index];
}
/* January and the later Xbox build both leave the no-candidate result
* undefined. The caller expects maps to provide at least two hill ids. */
return next_hill_id;
}