/* * Copyright (C) 2002-2007 The Warp Rogue Team * Part of the Warp Rogue Project * * This software is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License. * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY. * * See the license.txt file for more details. */ /* * Module Name: Round * Description: - */ #define Uses_Event #define Uses_Util #define Uses_Ai #define Uses_Command #define Uses_Area #define Uses_Equipment #define Uses_Character #define Uses_Stats #define Uses_Perception #define Uses_Death #include "mheader.h" #include "round.h" /* * number of phases in a round */ #define N_PHASES 10 /* * maximal number of actions a character can perform in a single * round - equal to N_PHASES */ #define MAX_ACTIONS N_PHASES /* * calculates the number of actions a character has per round */ #define n_actions_per_round(c) divide_and_round_up((c)->stat[S_IN].current, 10) /* * checks whether a phase is an active phase for a character or not */ #define is_active_phase(p, c) PhaseTable[n_actions_per_round(c) - 1][p] static void character_actions(void); static void hand_out_actions(void); static CHARACTER * next_character_to_act(void); /* * current phase of the game round */ static PHASE CurrentPhase = 0; /* * a phase jump happens when the game jumps right * into a phase by calling the set_phase() function * * a phase jump requires some special behaviour which * is activated by this switch * */ static bool PhaseJump = false; /* * this table tells us in which phases a character * is active / inactive. This depends on the number of * actions a character can perform per round. * * Usage example: * Is a character with X actions active in phase P? * if (PhaseTable[X - 1][P]) HE IS ACTIVE */ static const int PhaseTable[MAX_ACTIONS][N_PHASES] = { {0,0,0,0,0,1,0,0,0,0}, {0,0,1,0,0,1,0,0,0,0}, {0,0,1,0,0,1,0,1,0,0}, {0,1,0,1,0,1,0,1,0,0}, {1,0,1,0,1,0,1,0,1,0}, {1,1,0,1,0,1,0,1,0,1}, {1,1,0,1,1,0,1,1,1,0}, {1,1,1,0,1,1,1,0,1,1}, {1,1,1,1,1,0,1,1,1,1}, {1,1,1,1,1,1,1,1,1,1} }; /* * the currently active character */ static CHARACTER * ActiveCharacter = NULL; /* * sets the current phase */ void set_phase(PHASE phase) { CurrentPhase = phase; PhaseJump = true; } /* * returns the current phase */ PHASE get_phase(void) { return CurrentPhase; } /* * executes a game round */ void game_round(void) { while (CurrentPhase < N_PHASES) { if (PhaseJump) { PhaseJump = false; } else { handle_events(); hand_out_actions(); } character_actions(); ++CurrentPhase; } CurrentPhase = 0; } /* * returns the currently active character */ CHARACTER * active_character(void) { return ActiveCharacter; } /* * returns true if a character can act in the current phase or false * if he can't */ bool character_can_act(const CHARACTER *character) { if (is_active_phase(CurrentPhase, character) && !character_has_flag(character, CF_BUSY) && !character_has_flag(character, CF_STUNNED)) { return true; } return false; } /* * calculates how much time (time unit = phases) it will take a character to execute a * certain number of actions */ PHASE_TIME actions_to_time(const CHARACTER *character, N_ACTIONS n_actions) { PHASE_TIME phase_time; PHASE phase; phase_time = 0; phase = CurrentPhase; while (true) { ++phase_time; if (is_active_phase(phase, character)) { --n_actions; } if (n_actions == 0) { break; } ++phase; if (phase == N_PHASES) { phase = 0; } } return phase_time; } /* * lets the characters act */ static void character_actions(void) { while ((ActiveCharacter = next_character_to_act()) != NULL) { update_perception_data(ActiveCharacter); if (ActiveCharacter->controller == CC_PLAYER) { player_control(ActiveCharacter); } /* switch character hack - do not merge these if statements! */ if (ActiveCharacter->controller == CC_AI) { ai_control(ActiveCharacter); } if (character_killed(ActiveCharacter)) { character_destroy(ActiveCharacter); } } } /* * hands out actions to those characters who can act * in the current phase */ static void hand_out_actions(void) { CHARACTER *character; LIST_NODE *node; for (node = area_character_list()->head; node != NULL; node = node->next) { character = (CHARACTER *)node->data; if (character_can_act(character)) { character->action_spent = false; } } } /* * returns the next character to act in the current phase */ static CHARACTER * next_character_to_act(void) { CHARACTER *character_to_act; CHARACTER *character; LIST_NODE *node; character_to_act = NULL; for (node = area_character_list()->head; node != NULL; node = node->next) { character = (CHARACTER *)node->data; if (character->action_spent) continue; if (!character_can_act(character)) continue; if (character_to_act == NULL) { character_to_act = character; continue; } if (character->stat[S_IN].current > character_to_act->stat[S_IN].current) { character_to_act = character; } } return character_to_act; }