| 1 |
<?php |
<?php |
| 2 |
// $Id: game.module,v 1.52.2.17 2008/11/25 16:00:45 morbus Exp $ |
// $Id: game.module,v 1.52.2.18 2008/11/29 03:30:39 morbus Exp $ |
| 3 |
|
|
| 4 |
/** |
/** |
| 5 |
* @file |
* @file |
| 15 |
* @todo add missing/null/unowned bid checking to game_battle_process_form(); |
* @todo add missing/null/unowned bid checking to game_battle_process_form(); |
| 16 |
* @todo run an EXPLAIN on game_log_recent (8 seconds? wtf.) |
* @todo run an EXPLAIN on game_log_recent (8 seconds? wtf.) |
| 17 |
* @todo error if there are no mobs available (modules, etc.). |
* @todo error if there are no mobs available (modules, etc.). |
|
* @todo add in "get random AI" code, or some alternative means? |
|
| 18 |
* @todo game_battle_play() needs to complain about missing params. |
* @todo game_battle_play() needs to complain about missing params. |
|
* @todo modify game_menu() to check for valid $bids before hitting callback. |
|
| 19 |
* @todo go through and fine-tooth game_battle_play(). |
* @todo go through and fine-tooth game_battle_play(). |
| 20 |
* @todo move the dynamic 'hp' values into $state? |
* @todo move the dynamic 'hp' values into $state? |
| 21 |
* @todo add in uname to the variables (and other missing values). |
* @todo add in uname to the variables (and other missing values). |
| 23 |
* using it inside array indexes. and, we use it so much that it makes it a |
* using it inside array indexes. and, we use it so much that it makes it a |
| 24 |
* bit prohibitive to add in a hook to it (but, do we NEED to is the question). |
* bit prohibitive to add in a hook to it (but, do we NEED to is the question). |
| 25 |
* @todo print out the state and see if you're happy with all the variables. |
* @todo print out the state and see if you're happy with all the variables. |
|
* @todo work on the "shared battle" database stuff; similar to shared logs. |
|
| 26 |
* @todo start breaking up game_battle_play() into smaller chunks. |
* @todo start breaking up game_battle_play() into smaller chunks. |
| 27 |
* @todo how should we maintain battle win/loss records and/or other stats? |
* @todo how should we maintain battle win/loss records and/or other stats? |
|
* @todo if only one battle in the state at a time, do we need to pass bid? |
|
|
* @todo should be add current_bid with the ID? would save on passing. state. |
|
|
* @todo worry about this with shared battles in; handle on state_load. |
|
| 28 |
* @todo we're forcing 's as a plural for mob names, without any good logic. |
* @todo we're forcing 's as a plural for mob names, without any good logic. |
| 29 |
* @todo storing $state['battles']['current'] is nicer than the $bid. |
* @todo battle_load needs to check against the passed user as owner. |
| 30 |
* @todo if we load only one battle at a time, why not just ['battle']? |
* @todo if another module calls game_state_load() after ours, will they |
| 31 |
|
* be unable to get the latest information (if we haven't saved recently?). |
| 32 |
|
* @todo we need a hook_user to handle user deletions and so forth. |
| 33 |
|
* @todo store win/loss into game state; how to handle 2p game state? race? |
| 34 |
*/ |
*/ |
| 35 |
|
|
| 36 |
/** |
/** |
| 43 |
'page arguments' => array('game_battle_init_form'), |
'page arguments' => array('game_battle_init_form'), |
| 44 |
'title' => 'Game battle', |
'title' => 'Game battle', |
| 45 |
); |
); |
| 46 |
$items['game/battle/%'] = array( |
$items['game/battle/%game_battle'] = array( |
| 47 |
'access arguments' => array('play game'), |
'access arguments' => array('play game'), |
| 48 |
'page callback' => 'drupal_get_form', |
'page callback' => 'drupal_get_form', |
| 49 |
'page arguments' => array('game_battle_process_form', 2), |
'page arguments' => array('game_battle_process_form', 2), |
| 77 |
// @todo create a much nicer interface for selecting mobs and attack order. |
// @todo create a much nicer interface for selecting mobs and attack order. |
| 78 |
foreach (array($user->uid, 'AI-01') as $uid) { |
foreach (array($user->uid, 'AI-01') as $uid) { |
| 79 |
for ($mob_num = 1; $mob_num <= 2; $mob_num++) { |
for ($mob_num = 1; $mob_num <= 2; $mob_num++) { |
| 80 |
$form['game']['parties'][$uid][$mob_num] = array( |
$form['game']['battle']['parties'][$uid][$mob_num] = array( |
| 81 |
'#options' => $options, |
'#options' => $options, |
| 82 |
'#required' => $mob_num == 1 ? TRUE : FALSE, |
'#required' => $mob_num == 1 ? TRUE : FALSE, |
| 83 |
'#type' => 'radios', |
'#type' => 'radios', |
| 101 |
global $user; |
global $user; |
| 102 |
$mobs = module_invoke_all('game_mobs'); |
$mobs = module_invoke_all('game_mobs'); |
| 103 |
$state = game_state_load(); |
$state = game_state_load(); |
|
$bid = game_random_id(); |
|
| 104 |
|
|
| 105 |
// turn the mob selections into parties for a new battle. |
// turn the mob selections into parties for a new battle. |
| 106 |
foreach ($form_state['values']['game']['parties'] as $uid => $party) { |
foreach ($form_state['values']['game']['battle']['parties'] as $uid => $party) { |
| 107 |
foreach ($party as $mob_num => $mob_id) { // init battle. |
foreach ($party as $mob_num => $mob_id) { // init battle. |
| 108 |
if ($mob_id) { // 1 vs. 2 battles, 1 vs. 1, etc., etc. |
if ($mob_id) { // 1 vs. 2 battles, 1 vs. 1, etc., etc. |
| 109 |
$state['battles'][$bid]['parties'][$uid][$mob_num] = $mobs[$mob_id]; |
$state['battle']['parties'][$uid][$mob_num] = $mobs[$mob_id]; |
| 110 |
} |
} |
| 111 |
} |
} |
| 112 |
} |
} |
| 113 |
|
|
| 114 |
// set the current user as an interactive. |
// set the current user as an interactive. |
| 115 |
$state['battles'][$bid]['state']['interactive'][$user->uid] = array(); |
$state['battle']['state']['interactive'][$user->uid] = array(); |
| 116 |
|
|
| 117 |
// save the new battle. |
// save the new battle. |
| 118 |
game_state_save($state); |
$state = game_state_save($state); |
| 119 |
|
|
| 120 |
// and send to our primary battle processor. |
// and send to our primary battle processor. |
| 121 |
$form_state['redirect'] = 'game/battle/'. $bid; |
$form_state['redirect'] = 'game/battle/'. $state['battle']['bid']; |
| 122 |
} |
} |
| 123 |
|
|
| 124 |
/** |
/** |
| 125 |
* Menu callback; process a battle turn by turn. |
* Menu callback; process a battle turn by turn. |
| 126 |
* |
* |
| 127 |
* @param $bid |
* @param $battle |
| 128 |
* The battle ID that is in-progress for the current user. |
* A loaded battle from game_battle_load() (menu wildcard loader). |
| 129 |
*/ |
*/ |
| 130 |
function game_battle_process_form(&$form_state, $bid) { |
function game_battle_process_form(&$form_state, $battle) { |
| 131 |
global $user; // keep structure. |
global $user; // keep structure. |
| 132 |
$form['game']['#tree'] = TRUE; |
$form['game']['#tree'] = TRUE; |
| 133 |
$state = game_state_load(); |
$state = game_state_load($user->uid, $battle['bid']); |
| 134 |
|
|
| 135 |
// pass control to game_battle_play(). game_battle_play() will automate all |
// pass control to game_battle_play(). game_battle_play() will automate all |
| 136 |
// non-interactive opponents and when it requires information (turn choices) |
// non-interactive opponents and when it requires information (turn choices) |
| 137 |
// from an interactive user, it'll return the current state. we'll also |
// from an interactive user, it'll return the current state. we'll also |
| 138 |
// save all its finished automating in the database before continuing. |
// save all its finished automating in the database before continuing. |
| 139 |
$state = game_state_save(game_battle_play($state, $bid)); |
$state = game_state_save(game_battle_play($state)); |
| 140 |
|
|
| 141 |
// if the next turn is the interactive user's, build the form. |
// if the next turn is the interactive user's, build the form. |
| 142 |
if ($state['battles'][$bid]['state']['attacker']['uid'] == $user->uid) { |
if ($state['battle']['state']['attacker']['uid'] == $user->uid) { |
| 143 |
$form['game']['bid'] = array( |
$form['game']['bid'] = array( |
| 144 |
'#type' => 'value', |
'#type' => 'value', |
| 145 |
'#value' => $bid, |
'#value' => $state['battle']['bid'], |
| 146 |
); |
); |
| 147 |
$form['submit'] = array( |
$form['submit'] = array( |
| 148 |
'#type' => 'submit', |
'#type' => 'submit', |
| 170 |
* Form #submit callback; starts a battle and passes to main handler. |
* Form #submit callback; starts a battle and passes to main handler. |
| 171 |
*/ |
*/ |
| 172 |
function game_battle_process_form_submit($form, &$form_state) { |
function game_battle_process_form_submit($form, &$form_state) { |
| 173 |
global $user; |
global $user; // side effects may include uncontrollable muscle movement. |
| 174 |
$state = game_state_load(); |
$state = game_state_load($user->uid, $form_state['values']['game']['bid']); |
|
$bid = $form_state['values']['game']['bid']; |
|
| 175 |
|
|
| 176 |
// @todo naturally, this needs to actually implement user choices based on FAPI. |
// @todo naturally, this needs to actually implement user choices based on FAPI. |
| 177 |
$state['battles'][$bid]['state']['interactive'][$user->uid]['turn_received'] = TRUE; |
$state['battle']['state']['interactive'][$user->uid]['turn_received'] = TRUE; |
| 178 |
$state = game_state_save(game_battle_play($state, $bid)); |
$state = game_state_save(game_battle_play($state)); |
| 179 |
} |
} |
| 180 |
|
|
| 181 |
/** |
/** |
| 186 |
* @param $state |
* @param $state |
| 187 |
* The current game state, which should contain further information on who |
* The current game state, which should contain further information on who |
| 188 |
* is current attacker and target, which attacks have been selected, etc. |
* is current attacker and target, which attacks have been selected, etc. |
|
* @param $bid |
|
|
* The battle ID whose current turn should be processed. |
|
| 189 |
* @return $state |
* @return $state |
| 190 |
* The modified game state when this battle turn has resolved. |
* The modified game state when this battle turn has resolved. |
| 191 |
*/ |
*/ |
| 192 |
function game_battle_play($state, $bid) { |
function game_battle_play($state) { |
| 193 |
// keep going as long as there are parties left to attack. this |
// keep going as long as there are parties left to attack. |
| 194 |
// while loop will be short-circuited by interactives as necessary. |
// loop will be short-circuited by interactives as necessary. |
| 195 |
while (count($state['battles'][$bid]['parties']) > 1) { |
while (count($state['battle']['parties']) > 1) { |
| 196 |
// if there are no more turns in this round, or if turn order has yet |
// if there are no more turns in this round, or if turn order has yet |
| 197 |
// to be established (new round, etc.), roll initiative and store it. |
// to be established (new round, etc.), roll initiative and store it. |
| 198 |
if (count($state['battles'][$bid]['state']['turn_order']) == 0) { |
if (count($state['battle']['state']['turn_order']) == 0) { |
| 199 |
$state['battles'][$bid]['state']['turn_order'] = game_roll_initiative($state['battles'][$bid]['parties']); |
$state['battle']['state']['turn_order'] = game_roll_initiative($state['battle']['parties']); |
| 200 |
} |
} |
| 201 |
|
|
| 202 |
// loop through the current turn order. |
// loop through the current turn order. |
| 203 |
foreach (array_keys($state['battles'][$bid]['state']['turn_order']) as $attacker_uid) { |
foreach (array_keys($state['battle']['state']['turn_order']) as $attacker_uid) { |
| 204 |
$state['battles'][$bid]['state']['attacker']['uid'] = $attacker_uid; |
$state['battle']['state']['attacker']['uid'] = $attacker_uid; |
|
|
|
|
// @todo need to check if there's anyone left to kill. |
|
| 205 |
|
|
| 206 |
// if the current turn is assigned to an interactive user who has not yet |
// if the current turn is assigned to an interactive user who has not yet |
| 207 |
// sent in their turn information, we'll return the $state to the caller and |
// sent in their turn information, we'll return the $state to the caller and |
| 208 |
// trust that the caller will ask for the inputs, then send it back to us. |
// trust that the caller will ask for the inputs, then send it back to us. |
| 209 |
if (is_array($state['battles'][$bid]['state']['interactive'][$attacker_uid])) { |
if (is_array($state['battle']['state']['interactive'][$attacker_uid])) { |
| 210 |
if (!$state['battles'][$bid]['state']['interactive'][$attacker_uid]['turn_received']) { |
if (!$state['battle']['state']['interactive'][$attacker_uid]['turn_received']) { |
| 211 |
return $state; |
return $state; |
| 212 |
} |
} |
| 213 |
else { |
else { |
| 214 |
// turn information has been received, so we'll continue processing below. |
// turn information has been received, so we'll continue processing below. |
| 215 |
// unset turn_received so that the user's next turn will be interactive too. |
// unset turn_received so that the user's next turn will be interactive too. |
| 216 |
unset($state['battles'][$bid]['state']['interactive'][$attacker_uid]['turn_received']); |
unset($state['battle']['state']['interactive'][$attacker_uid]['turn_received']); |
| 217 |
} |
} |
| 218 |
} |
} |
| 219 |
|
|
| 220 |
// loop through all the attackers remaining creatures and attack. |
// loop through all the attackers remaining creatures and attack. |
| 221 |
foreach (array_keys($state['battles'][$bid]['parties'][$attacker_uid]) as $attacking_mob_num) { |
foreach (array_keys($state['battle']['parties'][$attacker_uid]) as $attacking_mob_num) { |
| 222 |
$state['battles'][$bid]['state']['attacker']['mob_num'] = $attacking_mob_num; |
$state['battle']['state']['attacker']['mob_num'] = $attacking_mob_num; |
| 223 |
|
|
| 224 |
// if this mob has a target opponent and mob, use it. otherwise, random remaining. |
// if this mob has a target opponent and mob, use it. otherwise, random remaining. |
| 225 |
// this should really only be used when the AI is not automatically picking an |
// this should really only be used when the AI is not automatically picking an |
| 226 |
// opponent; users would always choose opponent + mob via the standard form UI. |
// opponent; users would always choose opponent + mob via the standard form UI. |
| 227 |
// @todo this defaulting should eventually go into an AI-sorta module. |
// @todo this defaulting should eventually go into an AI-sorta module. |
| 228 |
if (!$state['battles'][$bid]['state']['attacker']['party'][$attacking_mob_num]['target_uid']) { |
if (!$state['battle']['state']['attacker']['party'][$attacking_mob_num]['target_uid']) { |
| 229 |
$state['battles'][$bid]['state']['attacker']['party'][$attacking_mob_num]['target_uid'] = array_rand(array_diff_key($state['battles'][$bid]['parties'], array($attacker_uid => 1))); |
$state['battle']['state']['attacker']['party'][$attacking_mob_num]['target_uid'] = array_rand(array_diff_key($state['battle']['parties'], array($attacker_uid => 1))); |
| 230 |
$state['battles'][$bid]['state']['attacker']['party'][$attacking_mob_num]['target_mob_num'] = array_rand($state['battles'][$bid]['parties'][$state['battles'][$bid]['state']['attacker']['party'][$attacking_mob_num]['target_uid']]); |
$state['battle']['state']['attacker']['party'][$attacking_mob_num]['target_mob_num'] = array_rand($state['battle']['parties'][$state['battle']['state']['attacker']['party'][$attacking_mob_num]['target_uid']]); |
| 231 |
$state['battles'][$bid]['state']['attacker']['party'][$attacking_mob_num]['attack'] = array_rand($state['battles'][$bid]['parties'][$attacker_uid][$attacking_mob_num]['actions']); |
$state['battle']['state']['attacker']['party'][$attacking_mob_num]['attack'] = array_rand($state['battle']['parties'][$attacker_uid][$attacking_mob_num]['actions']); |
| 232 |
} |
} |
| 233 |
|
|
| 234 |
// roll attack; determine success or failure. |
// roll attack for success or failure. |
| 235 |
$state = game_battle_attack($state, $bid); |
$state = game_battle_attack($state); |
| 236 |
|
|
| 237 |
// @todo move this and other damage related stuff into a new function. |
// @todo move this and other damage related stuff into a new function. |
| 238 |
$attack_status = $state['battles'][$bid]['state']['attacker']['party'][$attacking_mob_num]['attack_roll']['status']; |
$attack_status = $state['battle']['state']['attacker']['party'][$attacking_mob_num]['attack_roll']['status']; |
| 239 |
|
|
| 240 |
// if this attack was a success, process the damage. |
// if this attack was a success, process the damage. |
| 241 |
if ($attack_status == t('hit') || $attack_status == t('critical hit')) { |
if ($attack_status == t('hit') || $attack_status == t('critical hit')) { |
| 242 |
$state['battles'][$bid]['parties'][game_battle_variables($state, $bid, '@target_uid')][game_battle_variables($state, $bid, '@target_mob_num')]['hp'] -= game_battle_variables($state, $bid, '@total_damage'); |
$state['battle']['parties'][game_battle_variables($state, '@target_uid')][game_battle_variables($state, '@target_mob_num')]['hp'] -= game_battle_variables($state, '@total_damage'); |
| 243 |
game_log('combat', '%attacking_mob_attack_name deals @total_damage damage to %target_mob_name (HP is now @target_mob_hp).', game_battle_variables($state, $bid)); |
game_log('combat', '%attacking_mob_attack_name deals @total_damage damage to %target_mob_name (HP is now @target_mob_hp).', game_battle_variables($state)); |
| 244 |
|
|
| 245 |
// remove this mob from the active party if destroyed. |
// remove this mob from the active party if destroyed. |
| 246 |
if (game_battle_variables($state, $bid, '@target_mob_hp') <= 0) { |
if (game_battle_variables($state, '@target_mob_hp') <= 0) { |
| 247 |
game_log('combat', '%target_mob_name has been destroyed.', game_battle_variables($state, $bid)); |
game_log('combat', '%target_mob_name has been destroyed.', game_battle_variables($state)); |
| 248 |
unset($state['battles'][$bid]['parties'][game_battle_variables($state, $bid, '@target_uid')][game_battle_variables($state, $bid, '@target_mob_num')]); |
unset($state['battle']['parties'][game_battle_variables($state, '@target_uid')][game_battle_variables($state, '@target_mob_num')]); |
| 249 |
} |
} |
| 250 |
|
|
| 251 |
// remove this player from the active parties if destroyed. |
// remove this player from the active parties if destroyed. |
| 252 |
if (count($state['battles'][$bid]['parties'][game_battle_variables($state, $bid, '@target_uid')]) == 0) { |
$target_uid = game_battle_variables($state, '@target_uid'); |
| 253 |
game_log('combat', '@target_uid has been defeated.', game_battle_variables($state, $bid)); |
if (count($state['battle']['parties'][$target_uid]) == 0) { |
| 254 |
unset($state['battles'][$bid]['parties'][game_battle_variables($state, $bid, '@target_uid')]); |
game_log('combat', '@target_uid has been defeated.', game_battle_variables($state)); |
| 255 |
|
unset($state['battle']['state']['turn_order'][$target_uid]); |
| 256 |
|
unset($state['battle']['parties'][$target_uid]); |
| 257 |
} |
} |
| 258 |
} |
} |
| 259 |
} |
} |
| 260 |
|
|
| 261 |
// this turn is done, so remove the turn state and attacker. |
// this turn is done, so remove the turn state and attacker. |
| 262 |
unset($state['battles'][$bid]['state']['turn_order'][$attacker_uid]); |
unset($state['battle']['state']['turn_order'][$attacker_uid]); |
| 263 |
unset($state['battles'][$bid]['state']['attacker']); |
unset($state['battle']['state']['attacker']); |
| 264 |
} |
} |
| 265 |
} |
} |
| 266 |
|
|
| 267 |
// if the battle is over, remove interim structure. |
// if the battle is over, remove interim structure. |
| 268 |
if (count($state['battles'][$bid]['parties']) == 1) { |
if (count($state['battle']['parties']) == 1) { |
| 269 |
unset($state['battles'][$bid]['parties']); |
game_battle_delete($state['battle']['bid']); |
| 270 |
unset($state['battles'][$bid]['state']); |
unset($state['battle']); // trashed from state. |
| 271 |
} |
} |
| 272 |
|
|
| 273 |
return $state; |
return $state; |
| 278 |
* |
* |
| 279 |
* @param $state |
* @param $state |
| 280 |
* The current game state to have variables generated from. |
* The current game state to have variables generated from. |
|
* @param $bid |
|
|
* The battle ID whose variables should be generated. |
|
| 281 |
*/ |
*/ |
| 282 |
function game_battle_attack($state, $bid) { |
function game_battle_attack($state) { |
| 283 |
$attacking_mob_num = $state['battles'][$bid]['state']['attacker']['mob_num']; |
$attacking_mob_num = $state['battle']['state']['attacker']['mob_num']; |
| 284 |
$state['battles'][$bid]['state']['attacker']['party'][$attacking_mob_num]['attack_roll'] = game_roll_d20(t('Attack roll for %attacking_mob_name\'s %attacking_mob_attack_name', game_battle_variables($state, $bid)), game_battle_variables($state, $bid, '@attacking_mob_attack_modifier')); |
$state['battle']['state']['attacker']['party'][$attacking_mob_num]['attack_roll'] = game_roll_d20(t('Attack roll for %attacking_mob_name\'s %attacking_mob_attack_name', game_battle_variables($state)), game_battle_variables($state, '@attacking_mob_attack_modifier')); |
| 285 |
drupal_alter('game_battle_attack_roll', $state); // allow modules to modify the game state before we determine if this attack was a hit or miss. |
drupal_alter('game_battle_attack_roll', $state); // allow modules to modify the game state before we determine if this attack was a hit or miss. |
| 286 |
|
|
| 287 |
// shorthand; we don't need up-to-date logging. |
// shorthand; don't need up-to-date logging. |
| 288 |
$bvars = game_battle_variables($state, $bid); |
$bvars = game_battle_variables($state); |
| 289 |
|
|
| 290 |
// this attack is a success if it's higher than the target's defense... |
// this attack is a success if it's higher than the target's defense... |
| 291 |
$state['battles'][$bid]['state']['attacker']['party'][$attacking_mob_num]['attack_roll']['status'] = |
$state['battle']['state']['attacker']['party'][$attacking_mob_num]['attack_roll']['status'] = |
| 292 |
$bvars['@attack_roll_result'] >= $bvars['@target_mob_defense_value'] ? t('hit') : t('miss'); |
$bvars['@attack_roll_result'] >= $bvars['@target_mob_defense_value'] ? t('hit') : t('miss'); |
| 293 |
|
|
| 294 |
// was this a critical hit... |
// was this a critical hit... |
| 295 |
if ($bvars['@attack_roll_raw'] == 20) { |
if ($bvars['@attack_roll_raw'] == 20) { |
| 296 |
$state['battles'][$bid]['state']['attacker']['party'][$attacking_mob_num]['attack_roll']['status'] = t('critical hit'); |
$state['battle']['state']['attacker']['party'][$attacking_mob_num]['attack_roll']['status'] = t('critical hit'); |
| 297 |
} |
} |
| 298 |
|
|
| 299 |
// or perhaps a critical miss? |
// or perhaps a critical miss? |
| 300 |
if ($bvars['@attack_roll_raw'] == 1) { |
if ($bvars['@attack_roll_raw'] == 1) { |
| 301 |
$state['battles'][$bid]['state']['attacker']['party'][$attacking_mob_num]['attack_roll']['status'] = t('critical miss'); |
$state['battle']['state']['attacker']['party'][$attacking_mob_num]['attack_roll']['status'] = t('critical miss'); |
| 302 |
} |
} |
| 303 |
|
|
| 304 |
// allow modules to react to determined attack status. |
// allow modules to react to determined attack status. |
| 307 |
// log the final determination after all modules have gotten their grubby hands on it. |
// log the final determination after all modules have gotten their grubby hands on it. |
| 308 |
// we assume, nay, hope, that modules will include extra log messages explaining any major oddities. |
// we assume, nay, hope, that modules will include extra log messages explaining any major oddities. |
| 309 |
// we don't use $bvars here since we want the latest values from all hook modifications, etc. |
// we don't use $bvars here since we want the latest values from all hook modifications, etc. |
| 310 |
game_log('combat', '%attacking_mob_name\'s %attacking_mob_attack_name (@attack_roll_result) vs. %target_mob_name\'s @target_mob_defense (@target_mob_defense_value): @attack_roll_status.', game_battle_variables($state, $bid)); |
game_log('combat', '%attacking_mob_name\'s %attacking_mob_attack_name (@attack_roll_result) vs. %target_mob_name\'s @target_mob_defense (@target_mob_defense_value): @attack_roll_status.', game_battle_variables($state)); |
| 311 |
|
|
| 312 |
return $state; |
return $state; |
| 313 |
} |
} |
| 317 |
* |
* |
| 318 |
* @param $state |
* @param $state |
| 319 |
* The current game state to have variables generated from. |
* The current game state to have variables generated from. |
|
* @param $bid |
|
|
* The battle ID whose variables should be generated. |
|
| 320 |
* @param $variable |
* @param $variable |
| 321 |
* A variable name that you'd like to retrieve the value for (only). |
* A variable name that you'd like to retrieve the value for (only). |
| 322 |
* @return $variable(s) |
* @return $variable(s) |
| 323 |
* Either an array of all $variables or the desired/passed $variable. |
* Either an array of all $variables or the desired/passed $variable. |
| 324 |
*/ |
*/ |
| 325 |
function game_battle_variables($state, $bid, $variable = NULL) { |
function game_battle_variables($state, $variable = NULL) { |
| 326 |
$variables['@battle_id'] = $bid; |
$variables['@battle_id'] = $state['battle']['bid']; |
| 327 |
$variables['@attacking_uid'] = $state['battles'][$bid]['state']['attacker']['uid']; |
$variables['@attacking_uid'] = $state['battle']['state']['attacker']['uid']; |
| 328 |
$variables['%attacking_uname'] = ''; |
$variables['%attacking_uname'] = ''; |
| 329 |
$variables['@attacking_initiative'] = $state['battles'][$bid]['state']['turn_order'][$variables['@attacking_uid']]; |
$variables['@attacking_initiative'] = $state['battle']['state']['turn_order'][$variables['@attacking_uid']]; |
| 330 |
$variables['@attacking_mob_num'] = $state['battles'][$bid]['state']['attacker']['mob_num']; |
$variables['@attacking_mob_num'] = $state['battle']['state']['attacker']['mob_num']; |
| 331 |
$variables['%attacking_mob_name'] = $state['battles'][$bid]['parties'][$variables['@attacking_uid']][$variables['@attacking_mob_num']]['name']; |
$variables['%attacking_mob_name'] = $state['battle']['parties'][$variables['@attacking_uid']][$variables['@attacking_mob_num']]['name']; |
| 332 |
$variables['@attacking_mob_attack_id'] = $state['battles'][$bid]['state']['attacker']['party'][$variables['@attacking_mob_num']]['attack']; |
$variables['@attacking_mob_attack_id'] = $state['battle']['state']['attacker']['party'][$variables['@attacking_mob_num']]['attack']; |
| 333 |
$variables['%attacking_mob_attack_name'] = $state['battles'][$bid]['parties'][$variables['@attacking_uid']][$variables['@attacking_mob_num']]['actions'][$variables['@attacking_mob_attack_id']]['name']; |
$variables['%attacking_mob_attack_name'] = $state['battle']['parties'][$variables['@attacking_uid']][$variables['@attacking_mob_num']]['actions'][$variables['@attacking_mob_attack_id']]['name']; |
| 334 |
$variables['@attacking_mob_attack_damage'] = $state['battles'][$bid]['parties'][$variables['@attacking_uid']][$variables['@attacking_mob_num']]['actions'][$variables['@attacking_mob_attack_id']]['damage']; |
$variables['@attacking_mob_attack_damage'] = $state['battle']['parties'][$variables['@attacking_uid']][$variables['@attacking_mob_num']]['actions'][$variables['@attacking_mob_attack_id']]['damage']; |
| 335 |
$variables['@attacking_mob_attack_modifier'] = $state['battles'][$bid]['parties'][$variables['@attacking_uid']][$variables['@attacking_mob_num']]['actions'][$variables['@attacking_mob_attack_id']]['modifier']; |
$variables['@attacking_mob_attack_modifier'] = $state['battle']['parties'][$variables['@attacking_uid']][$variables['@attacking_mob_num']]['actions'][$variables['@attacking_mob_attack_id']]['modifier']; |
| 336 |
$variables['@target_uid'] = $state['battles'][$bid]['state']['attacker']['party'][$variables['@attacking_mob_num']]['target_uid']; |
$variables['@target_uid'] = $state['battle']['state']['attacker']['party'][$variables['@attacking_mob_num']]['target_uid']; |
| 337 |
$variables['%target_uname'] = ''; |
$variables['%target_uname'] = ''; |
| 338 |
$variables['@target_mob_num'] = $state['battles'][$bid]['state']['attacker']['party'][$variables['@attacking_mob_num']]['target_mob_num']; |
$variables['@target_mob_num'] = $state['battle']['state']['attacker']['party'][$variables['@attacking_mob_num']]['target_mob_num']; |
| 339 |
$variables['%target_mob_name'] = $state['battles'][$bid]['parties'][$variables['@target_uid']][$variables['@target_mob_num']]['name']; |
$variables['%target_mob_name'] = $state['battle']['parties'][$variables['@target_uid']][$variables['@target_mob_num']]['name']; |
| 340 |
$variables['@target_mob_hp'] = $state['battles'][$bid]['parties'][$variables['@target_uid']][$variables['@target_mob_num']]['hp']; |
$variables['@target_mob_hp'] = $state['battle']['parties'][$variables['@target_uid']][$variables['@target_mob_num']]['hp']; |
| 341 |
$variables['@target_mob_defense'] = $state['battles'][$bid]['parties'][$variables['@attacking_uid']][$variables['@attacking_mob_num']]['actions'][$variables['@attacking_mob_attack_id']]['modifier against']; |
$variables['@target_mob_defense'] = $state['battle']['parties'][$variables['@attacking_uid']][$variables['@attacking_mob_num']]['actions'][$variables['@attacking_mob_attack_id']]['modifier against']; |
| 342 |
$variables['@target_mob_defense_value'] = $state['battles'][$bid]['parties'][$variables['@target_uid']][$variables['@target_mob_num']][$variables['@target_mob_defense']]; |
$variables['@target_mob_defense_value'] = $state['battle']['parties'][$variables['@target_uid']][$variables['@target_mob_num']][$variables['@target_mob_defense']]; |
| 343 |
$variables['@attack_roll_modifier'] = $state['battles'][$bid]['state']['attacker']['party'][$variables['@attacking_mob_num']]['attack_roll']['modifier']; |
$variables['@attack_roll_modifier'] = $state['battle']['state']['attacker']['party'][$variables['@attacking_mob_num']]['attack_roll']['modifier']; |
| 344 |
$variables['@attack_roll_raw'] = $state['battles'][$bid]['state']['attacker']['party'][$variables['@attacking_mob_num']]['attack_roll']['raw']; |
$variables['@attack_roll_raw'] = $state['battle']['state']['attacker']['party'][$variables['@attacking_mob_num']]['attack_roll']['raw']; |
| 345 |
$variables['@attack_roll_result'] = $state['battles'][$bid]['state']['attacker']['party'][$variables['@attacking_mob_num']]['attack_roll']['result']; |
$variables['@attack_roll_result'] = $state['battle']['state']['attacker']['party'][$variables['@attacking_mob_num']]['attack_roll']['result']; |
| 346 |
$variables['@attack_roll_status'] = $state['battles'][$bid]['state']['attacker']['party'][$variables['@attacking_mob_num']]['attack_roll']['status']; |
$variables['@attack_roll_status'] = $state['battle']['state']['attacker']['party'][$variables['@attacking_mob_num']]['attack_roll']['status']; |
| 347 |
$variables['@total_damage'] = $variables['@attack_roll_status'] == t('critical hit') ? $variables['@attacking_mob_attack_damage'] * 2 : $variables['@attacking_mob_attack_damage']; |
$variables['@total_damage'] = $variables['@attack_roll_status'] == t('critical hit') ? $variables['@attacking_mob_attack_damage'] * 2 : $variables['@attacking_mob_attack_damage']; |
| 348 |
|
|
| 349 |
return $variable ? $variables[$variable] : $variables; |
return $variable ? $variables[$variable] : $variables; |
| 417 |
$log->timestamp = time(); |
$log->timestamp = time(); |
| 418 |
drupal_write_record('game_log', $log); |
drupal_write_record('game_log', $log); |
| 419 |
|
|
|
// default to self. |
|
| 420 |
if (count($uids) == 0) { |
if (count($uids) == 0) { |
| 421 |
global $user; // sup. |
global $user; // sup. |
| 422 |
$uids[] = $user->uid; |
$uids[] = $user->uid; |
| 465 |
} |
} |
| 466 |
|
|
| 467 |
/** |
/** |
| 468 |
* Generate a random ID for game events. |
* Delete a battle state from the database. |
| 469 |
|
*/ |
| 470 |
|
function game_battle_delete($bid) { |
| 471 |
|
if ($bid) { // WHO DARES SEND ME NO BID? I SHALL KEEELlLYYOOUU. |
| 472 |
|
db_query('DELETE FROM game_battle_user WHERE bid = %d', $bid); |
| 473 |
|
db_query('DELETE FROM game_battle WHERE bid = %d', $bid); |
| 474 |
|
} |
| 475 |
|
} |
| 476 |
|
|
| 477 |
|
/** |
| 478 |
|
* Load a battle state from the database. |
| 479 |
|
* |
| 480 |
|
* Also used as a hook_menu() wildcard loader function. |
| 481 |
|
* |
| 482 |
|
* @param $bid |
| 483 |
|
* The battle ID to retrieve and de-serialize. |
| 484 |
|
* @return $battle |
| 485 |
|
* The battle state, ready for adding to the master game $state. |
| 486 |
|
* If the battle state doesn't exist, we'll return FALSE instead. |
| 487 |
|
*/ |
| 488 |
|
function game_battle_load($bid) { |
| 489 |
|
static $battles; |
| 490 |
|
|
| 491 |
|
if ($battles[$bid]) { |
| 492 |
|
return $battles[$bid]; |
| 493 |
|
} |
| 494 |
|
|
| 495 |
|
if ($result = db_fetch_object(db_query("SELECT state FROM {game_battle} WHERE bid = %d", $bid))) { |
| 496 |
|
$battles[$bid] = unserialize($result->state); |
| 497 |
|
$battles[$bid]['bid'] = $bid; // embedded. |
| 498 |
|
return $battles[$bid]; |
| 499 |
|
} |
| 500 |
|
|
| 501 |
|
return FALSE; |
| 502 |
|
} |
| 503 |
|
|
| 504 |
|
/** |
| 505 |
|
* Saves a battle state to the database. |
| 506 |
|
* |
| 507 |
|
* @param $battle |
| 508 |
|
* The current battle state to be saved. |
| 509 |
|
* @return $battle |
| 510 |
|
* The battle state after saving (newly updated 'changed', etc.). |
| 511 |
*/ |
*/ |
| 512 |
function game_random_id() { |
function game_battle_save($battle) { |
| 513 |
return drupal_substr(md5(uniqid()), 0, 8); |
$record = new stdClass(); |
| 514 |
|
$update = array('bid'); |
| 515 |
|
|
| 516 |
|
// has this battle just started? |
| 517 |
|
if (!$battle['started']) { // nothing? new state. |
| 518 |
|
$record->started = $battle['started'] = time(); |
| 519 |
|
$update = array(); |
| 520 |
|
} |
| 521 |
|
|
| 522 |
|
$record->changed = $battle['changed'] = time(); |
| 523 |
|
$record->bid = $battle['bid'] ? $battle['bid'] : NULL; |
| 524 |
|
$record->state = serialize($battle); |
| 525 |
|
drupal_write_record('game_battle', $record, $update); |
| 526 |
|
$battle['bid'] = $record->bid; // so caller knows us. |
| 527 |
|
|
| 528 |
|
// associate this battle with all relevant users. |
| 529 |
|
foreach (array_keys($battle['parties']) as $uid) { |
| 530 |
|
// skip AI users, invites, emails, etc. |
| 531 |
|
if (is_numeric($uid) && $uid != 0) { |
| 532 |
|
$battle_user = new stdClass(); |
| 533 |
|
$battle_user->uid = $uid; |
| 534 |
|
$battle_user->bid = $record->bid; |
| 535 |
|
drupal_write_record('game_battle_user', $battle_user); |
| 536 |
|
} |
| 537 |
|
} |
| 538 |
|
|
| 539 |
|
return $battle; |
| 540 |
} |
} |
| 541 |
|
|
| 542 |
/** |
/** |
| 544 |
* |
* |
| 545 |
* @param $uid |
* @param $uid |
| 546 |
* The user's game state to load. Defaults to global user. |
* The user's game state to load. Defaults to global user. |
| 547 |
|
* @param $bid |
| 548 |
|
* Optional; a battle ID to load into this game state. |
| 549 |
* @return $state |
* @return $state |
| 550 |
* The user's game state. If a game state doesn't exist in the database, |
* The user's game state. If a game state doesn't exist |
| 551 |
* an array of just "new_state" will be returned (which game_state_save() |
* in the database, an empty array will be returned. |
|
* will then recognize as a new record). |
|
| 552 |
*/ |
*/ |
| 553 |
function game_state_load($uid = NULL) { |
function game_state_load($uid = NULL, $bid = NULL) { |
| 554 |
if (!$uid) { |
if (!$uid) { |
| 555 |
global $user; |
global $user; |
| 556 |
$uid = $user->uid; |
$uid = $user->uid; |
| 557 |
} |
} |
| 558 |
|
|
| 559 |
$result = db_fetch_object(db_query('SELECT state FROM {game_state} WHERE uid = %d', $uid)); |
$result = db_fetch_object(db_query('SELECT state FROM {game_state} WHERE uid = %d', $uid)); |
| 560 |
return $result->state? unserialize($result->state) : array('new_state' => TRUE); |
|
| 561 |
|
if (!$result->state) { |
| 562 |
|
return array(); |
| 563 |
|
} |
| 564 |
|
|
| 565 |
|
if ($result->state) { |
| 566 |
|
$state = unserialize($result->state); |
| 567 |
|
$state['uid'] = $uid; // embedded. |
| 568 |
|
|
| 569 |
|
if ($bid) { // got a battle too? grand. |
| 570 |
|
$state['battle'] = game_battle_load($bid); |
| 571 |
|
} |
| 572 |
|
} |
| 573 |
|
|
| 574 |
|
return $state; |
| 575 |
} |
} |
| 576 |
|
|
| 577 |
/** |
/** |
| 581 |
* The current game state to be saved. |
* The current game state to be saved. |
| 582 |
* @param $uid |
* @param $uid |
| 583 |
* The owner of this game state. Defaults to global user. |
* The owner of this game state. Defaults to global user. |
| 584 |
|
* @return $state |
| 585 |
|
* The state after saving (newly updated 'changed', etc.). |
| 586 |
*/ |
*/ |
| 587 |
function game_state_save($state = array(), $uid = NULL) { |
function game_state_save($state = array(), $uid = NULL) { |
| 588 |
if (!$uid) { |
if (!$uid) { |
| 593 |
$record = new stdClass(); |
$record = new stdClass(); |
| 594 |
$update = array('uid'); |
$update = array('uid'); |
| 595 |
|
|
| 596 |
// has this state just been started? |
// has this state just started? |
| 597 |
if ($state['new_state'] == TRUE) { |
if (!$state['started']) { // nothing? new state. |
| 598 |
unset($state['new_state']); |
$record->started = $state['started'] = time(); |
|
$record->started = time(); |
|
| 599 |
$update = array(); |
$update = array(); |
| 600 |
} |
} |
| 601 |
|
|
| 602 |
$record->uid = $uid; |
// battles are saved elsewhere. |
| 603 |
$record->changed = time(); |
if ($state['battle']) { // save and remove. |
| 604 |
|
$battle = game_battle_save($state['battle']); |
| 605 |
|
unset($state['battle']); // don't save in game state. |
| 606 |
|
} |
| 607 |
|
|
| 608 |
|
$record->changed = $state['changed'] = time(); |
| 609 |
|
$record->uid = $state['uid'] = $uid; |
| 610 |
$record->state = serialize($state); |
$record->state = serialize($state); |
| 611 |
drupal_write_record('game_state', $record, $update); |
drupal_write_record('game_state', $record, $update); |
| 612 |
|
|
| 613 |
|
if ($battle) { // did we save off a battle in this load? |
| 614 |
|
// then add it back to state for caller expectations. |
| 615 |
|
$state['battle'] = $battle; |
| 616 |
|
} |
| 617 |
|
|
| 618 |
return $state; |
return $state; |
| 619 |
} |
} |
| 620 |
|
|