| 1 |
<?php
|
| 2 |
// $Id: fsgame.module,v 1.54 2008/09/28 14:16:36 aaron Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* Enables the 5 Second Game (inspired by rock-paper-scissors).
|
| 7 |
*
|
| 8 |
* @todo implement some sort of cluetip thingy for the classes.
|
| 9 |
*/
|
| 10 |
|
| 11 |
/**
|
| 12 |
* Implementation of hook_help().
|
| 13 |
*/
|
| 14 |
function fsgame_help($path, $arg) {
|
| 15 |
switch ($path) {
|
| 16 |
case 'admin/settings/fsgame':
|
| 17 |
return '<p>'. t('Configure 5 Second Game with these settings.') .'</p>';
|
| 18 |
}
|
| 19 |
}
|
| 20 |
|
| 21 |
/**
|
| 22 |
* Implementation of hook_menu().
|
| 23 |
*/
|
| 24 |
function fsgame_menu() {
|
| 25 |
$items = array();
|
| 26 |
|
| 27 |
$items['admin/settings/fsgame'] = array(
|
| 28 |
'access arguments' => array('administer 5 Second Game'),
|
| 29 |
'description' => 'Configure 5 Second Game with these settings.',
|
| 30 |
'file' => 'fsgame.admin.inc',
|
| 31 |
'page callback' => 'drupal_get_form',
|
| 32 |
'page arguments' => array('fsgame_settings'),
|
| 33 |
'title' => '5 Second Game',
|
| 34 |
);
|
| 35 |
$items['fsgame/contest'] = array(
|
| 36 |
'access arguments' => array('create 5 Second Game character'),
|
| 37 |
'description' => 'Competition between two 5 Second Game characters.',
|
| 38 |
'file' => 'fsgame.pages.inc',
|
| 39 |
'page callback' => 'drupal_get_form',
|
| 40 |
'page arguments' => array('fsgame_contest_form'),
|
| 41 |
'title' => '5 Second Game Contest',
|
| 42 |
);
|
| 43 |
$items['fsgame/autocomplete'] = array(
|
| 44 |
'access arguments' => array('access content'),
|
| 45 |
'file' => 'fsgame.pages.inc',
|
| 46 |
'page callback' => 'fsgame_autocomplete',
|
| 47 |
'title' => '5 Second Game autocomplete',
|
| 48 |
'type' => MENU_CALLBACK,
|
| 49 |
);
|
| 50 |
$items['fsgame/autocomplete-exclude'] = array(
|
| 51 |
'access arguments' => array('access content'),
|
| 52 |
'file' => 'fsgame.pages.inc',
|
| 53 |
'page callback' => 'fsgame_autocomplete_exclude',
|
| 54 |
'title' => '5 Second Game autocomplete (exclude)',
|
| 55 |
'type' => MENU_CALLBACK,
|
| 56 |
);
|
| 57 |
$items['fsgame/claim/%node'] = array(
|
| 58 |
'access' => 'fsgame_claim_access',
|
| 59 |
'access arguments' => array(2),
|
| 60 |
'file' => 'fsgame.pages.inc',
|
| 61 |
'page callback' => 'fsgame_character_claim',
|
| 62 |
'page arguments' => array(2),
|
| 63 |
'title' => 'Claim 5 Second Game character',
|
| 64 |
'type' => MENU_CALLBACK,
|
| 65 |
);
|
| 66 |
$items['fsgame/js/form'] = array(
|
| 67 |
'page callback' => 'fsgame_form_update',
|
| 68 |
'access arguments' => array('access content'),
|
| 69 |
'type' => MENU_CALLBACK,
|
| 70 |
);
|
| 71 |
|
| 72 |
return $items;
|
| 73 |
}
|
| 74 |
|
| 75 |
function fsgame_form_update() {
|
| 76 |
$class = $_POST['fsgame']['character']['class'];
|
| 77 |
if ($form = form_get_cache($_POST['form_build_id'], $form_state)) {
|
| 78 |
// Validate the bid.
|
| 79 |
if (isset($form['fsgame']['character']['classes']['class']['#options'][$class])) {
|
| 80 |
// Get the new options and update the cache.
|
| 81 |
$form['fsgame']['character']['skill-wrapper']['skills'] = _fsgame_skill_select($class);
|
| 82 |
form_set_cache($_POST['form_build_id'], $form, $form_state);
|
| 83 |
|
| 84 |
// Build and render the new select element, then return it in JSON format.
|
| 85 |
$form_state = array();
|
| 86 |
$form['#post'] = array();
|
| 87 |
$form = form_builder($form['form_id']['#value'] , $form, $form_state);
|
| 88 |
$output = drupal_render($form['fsgame']['character']['skill-wrapper']['skills']);
|
| 89 |
drupal_json(array('status' => TRUE, 'data' => $output));
|
| 90 |
}
|
| 91 |
else {
|
| 92 |
drupal_json(array('status' => FALSE, 'data' => ''));
|
| 93 |
}
|
| 94 |
}
|
| 95 |
else {
|
| 96 |
drupal_json(array('status' => FALSE, 'data' => ''));
|
| 97 |
}
|
| 98 |
exit();
|
| 99 |
}
|
| 100 |
|
| 101 |
function _fsgame_skill_select($class = '') {
|
| 102 |
$class = fsgame_world_load('classes', $class);
|
| 103 |
if (!$class) {
|
| 104 |
return;
|
| 105 |
}
|
| 106 |
|
| 107 |
if (!is_array($class['preferred modes'])) {
|
| 108 |
$class['preferred modes'] = isset($class['preferred modes']) ? (array) $class['preferred modes'] : array();
|
| 109 |
}
|
| 110 |
if (!is_array($class['preferred skills'])) {
|
| 111 |
$class['preferred skills'] = isset($class['preferred skills']) ? (array) $class['preferred skills'] : array();
|
| 112 |
}
|
| 113 |
|
| 114 |
// Also allow a skill selection.
|
| 115 |
$skill_options = array();
|
| 116 |
foreach (fsgame_world_load('skills') as $skill) {
|
| 117 |
if ($skill['contest'] == 'attack' && (in_array($skill['skill mode'], $class['preferred modes']) || in_array($skill['id'], $class['preferred skills']))) {
|
| 118 |
$skill_options[$skill['id']] = $skill['title'];
|
| 119 |
}
|
| 120 |
}
|
| 121 |
|
| 122 |
$form = array(
|
| 123 |
'#options' => $skill_options,
|
| 124 |
// when the form is submitted, make it a key of 'character'.
|
| 125 |
'#parents' => array('fsgame', 'character', 'skill'),
|
| 126 |
'#required' => TRUE,
|
| 127 |
'#title' => t('Beginning attack skill'),
|
| 128 |
'#type' => 'select',
|
| 129 |
);
|
| 130 |
return $form;
|
| 131 |
}
|
| 132 |
|
| 133 |
|
| 134 |
/**
|
| 135 |
* Implementation of hook_perm().
|
| 136 |
*/
|
| 137 |
function fsgame_perm() {
|
| 138 |
return array(
|
| 139 |
'administer 5 Second Game',
|
| 140 |
'claim 5 Second Game character',
|
| 141 |
'create 5 Second Game character',
|
| 142 |
'edit own 5 Second Game character',
|
| 143 |
'edit any 5 Second Game character',
|
| 144 |
'delete any 5 Second Game character',
|
| 145 |
'delete own 5 Second Game character',
|
| 146 |
);
|
| 147 |
}
|
| 148 |
|
| 149 |
function fsgame_claim_access($node) {
|
| 150 |
global $user;
|
| 151 |
return $user->uid && user_access('claim 5 Second Game character') && ($node->type == 'fsgame_character') && (!$node->uid) && ($_SESSION['fsgame_contest_anonymous_character'] == $node->nid);
|
| 152 |
}
|
| 153 |
|
| 154 |
/**
|
| 155 |
* Implementation of hook_theme().
|
| 156 |
*/
|
| 157 |
function fsgame_theme($existing, $type, $theme, $path) {
|
| 158 |
return array(
|
| 159 |
'fsgame_character_class' => array(
|
| 160 |
'arguments' => array('node' => NULL),
|
| 161 |
'file' => 'fsgame.theme.inc',
|
| 162 |
),
|
| 163 |
'fsgame_character_attributes' => array(
|
| 164 |
'arguments' => array('node' => NULL),
|
| 165 |
'file' => 'fsgame.theme.inc',
|
| 166 |
),
|
| 167 |
'fsgame_contest_selectors_character' => array(
|
| 168 |
'arguments' => array('character_nid' => 'latest', 'opponent_nid' => 'latest'),
|
| 169 |
'file' => 'fsgame.theme.inc',
|
| 170 |
),
|
| 171 |
'fsgame_contest_selectors_opponent' => array(
|
| 172 |
'arguments' => array('character_nid' => 'latest', 'opponent_nid' => 'latest'),
|
| 173 |
'file' => 'fsgame.theme.inc',
|
| 174 |
),
|
| 175 |
'test' => array(
|
| 176 |
'arguments' => array('file' => NULL),
|
| 177 |
'file' => 'fsgame.theme.inc',
|
| 178 |
),
|
| 179 |
);
|
| 180 |
}
|
| 181 |
|
| 182 |
function phptemplate_preprocess_test($variables) {
|
| 183 |
$variables['file'] = 'override';
|
| 184 |
}
|
| 185 |
|
| 186 |
/**
|
| 187 |
* Implementation of hook_node_info().
|
| 188 |
*/
|
| 189 |
function fsgame_node_info() {
|
| 190 |
$types = array();
|
| 191 |
|
| 192 |
$types['fsgame_character'] = array(
|
| 193 |
'name' => t('Character'),
|
| 194 |
'module' => 'fsgame_character',
|
| 195 |
'description' => t('A <em>character</em> defines who you play as in the 5 Second Game.'),
|
| 196 |
'title_label' => t('Name'),
|
| 197 |
'body_label' => t('Description'),
|
| 198 |
'locked' => TRUE,
|
| 199 |
);
|
| 200 |
|
| 201 |
return $types;
|
| 202 |
}
|
| 203 |
|
| 204 |
/**
|
| 205 |
* Implementation of hook_access for characters.
|
| 206 |
*/
|
| 207 |
function fsgame_character_access($op, $node, $account) {
|
| 208 |
if ($op == 'create') {
|
| 209 |
return user_access('create 5 Second Game character', $account);
|
| 210 |
}
|
| 211 |
|
| 212 |
if ($op == 'update') {
|
| 213 |
if (user_access('edit any 5 Second Game character', $account) ||
|
| 214 |
(user_access('edit own 5 Second Game character', $account) && ($account->uid == $node->uid))) {
|
| 215 |
return TRUE;
|
| 216 |
}
|
| 217 |
}
|
| 218 |
|
| 219 |
if ($op == 'delete') {
|
| 220 |
if (user_access('delete any 5 Second Game character', $account) ||
|
| 221 |
(user_access('delete own 5 Second Game Character', $account) && ($account->uid == $node->uid))) {
|
| 222 |
return TRUE;
|
| 223 |
}
|
| 224 |
}
|
| 225 |
}
|
| 226 |
|
| 227 |
/**
|
| 228 |
* Implementation of hook_form() for characters.
|
| 229 |
*/
|
| 230 |
function fsgame_character_form(&$node, &$param) {
|
| 231 |
drupal_add_css(drupal_get_path('module', 'fsgame') .'/fsgame.css');
|
| 232 |
$type = node_get_types('type', $node);
|
| 233 |
|
| 234 |
$form['title'] = array(
|
| 235 |
'#default_value' => isset($node->title) ? $node->title : '',
|
| 236 |
'#title' => check_plain($type->title_label),
|
| 237 |
'#type' => 'textfield',
|
| 238 |
'#required' => TRUE,
|
| 239 |
);
|
| 240 |
|
| 241 |
$form['fsgame'] = array('#tree' => TRUE);
|
| 242 |
$form['fsgame']['character']['attributes'] = array(
|
| 243 |
'#collapsible' => TRUE,
|
| 244 |
'#description' => t("Your character's attributes affect how well the character performs in contests against other characters."),
|
| 245 |
'#title' => t('Attributes'),
|
| 246 |
'#type' => 'fieldset',
|
| 247 |
);
|
| 248 |
foreach (fsgame_base_attributes() as $attribute) {
|
| 249 |
$form['fsgame']['character']['attributes'][$attribute['id']] = array(
|
| 250 |
'#default_value' => isset($node->fsgame['character'][$attribute['id']]) ? $node->fsgame['character'][$attribute['id']] : $attribute['default_value'],
|
| 251 |
'#description' => $attribute['description'],
|
| 252 |
// when the form is submitted, make them keys of 'character'.
|
| 253 |
'#parents' => array('fsgame', 'character', $attribute['id']),
|
| 254 |
'#title' => $attribute['title'],
|
| 255 |
'#type' => 'textfield',
|
| 256 |
);
|
| 257 |
|
| 258 |
// disable attribute alteration if non-admin.
|
| 259 |
if (!user_access('administer 5 Second Game')) {
|
| 260 |
// #input has to be true so that these items get sent via a POST.
|
| 261 |
// this saves us the effort of reloading the defaults in the 'insert'.
|
| 262 |
$form['fsgame']['character']['attributes'][$attribute['id']]['#input'] = TRUE;
|
| 263 |
$form['fsgame']['character']['attributes'][$attribute['id']]['#type'] = 'item';
|
| 264 |
$form['fsgame']['character']['attributes'][$attribute['id']]['#value'] = $form['fsgame']['character']['attributes'][$attribute['id']]['#default_value'];
|
| 265 |
}
|
| 266 |
}
|
| 267 |
|
| 268 |
// CSS wizardry to allow "centering" and larger sizes.
|
| 269 |
$form['fsgame']['character']['attributes']['rock']['#prefix'] = '<div class="fsgame-character-attributes">';
|
| 270 |
$form['fsgame']['character']['attributes']['scissors']['#suffix'] = '</div>';
|
| 271 |
|
| 272 |
$form['fsgame']['character']['classes'] = array(
|
| 273 |
'#collapsible' => TRUE,
|
| 274 |
'#title' => t('Character class'),
|
| 275 |
'#type' => 'fieldset',
|
| 276 |
);
|
| 277 |
|
| 278 |
// $form['fsgame']['character']['skills'] = array(
|
| 279 |
// '#collapsible' => TRUE,
|
| 280 |
// '#title' => t('Character skills'),
|
| 281 |
// '#type' => 'fieldset',
|
| 282 |
// );
|
| 283 |
|
| 284 |
// Wrapper for fieldset contents (used by ahah.js).
|
| 285 |
$form['fsgame']['character']['skill-wrapper'] = array(
|
| 286 |
'#type' => 'item',
|
| 287 |
'#prefix' => '<div id="fsgame-character-skill-wrapper">',
|
| 288 |
'#suffix' => '</div>',
|
| 289 |
);
|
| 290 |
|
| 291 |
// $form['fsgame']['character']['skills'] = _fsgame_skill_select();
|
| 292 |
|
| 293 |
// Need this for AJAX.
|
| 294 |
$form['#cache'] = TRUE;
|
| 295 |
drupal_add_js("if (Drupal.jsEnabled) { $(document).ready(function() { $('#edit-fsgame-character-pick-class').css('display', 'none'); }); }", 'inline');
|
| 296 |
|
| 297 |
$form['fsgame']['character']['pick-class'] = array(
|
| 298 |
'#type' => 'submit',
|
| 299 |
'#value' => t('Change class (update list of skills)'),
|
| 300 |
// Submit the node form so the parent select options get updated.
|
| 301 |
// This is typically only used when JS is disabled. Since the parent options
|
| 302 |
// won't be changed via AJAX, a button is provided in the node form to submit
|
| 303 |
// the form and generate options in the parent select corresponding to the
|
| 304 |
// selected book. This is similar to what happens during a node preview.
|
| 305 |
'#submit' => array('node_form_submit_build_node'),
|
| 306 |
'#weight' => 20,
|
| 307 |
);
|
| 308 |
|
| 309 |
|
| 310 |
// new character, so pick a class, bub.
|
| 311 |
if (!$node->nid) {
|
| 312 |
$class_checkboxes = array();
|
| 313 |
foreach (fsgame_world_load('classes') as $class) {
|
| 314 |
$class_checkboxes[$class['id']] = fsgame_attributes_modifiers_string($class);
|
| 315 |
}
|
| 316 |
|
| 317 |
if (count($class_checkboxes) == 0) {
|
| 318 |
drupal_set_message(t("No character classes found; a site administrator needs to enable a 5 Second Game world."), 'error');
|
| 319 |
return; // if the user hasn't enabled any game worlds, we need to exit immediately. classes are compulsory.
|
| 320 |
}
|
| 321 |
|
| 322 |
$form['fsgame']['character']['classes']['class'] = array(
|
| 323 |
'#options' => $class_checkboxes,
|
| 324 |
// when the form is submitted, make it a key of 'character'.
|
| 325 |
'#parents' => array('fsgame', 'character', 'class'),
|
| 326 |
'#required' => TRUE,
|
| 327 |
'#title' => t('Character class'),
|
| 328 |
'#type' => 'radios',
|
| 329 |
'#ahah' => array(
|
| 330 |
'path' => 'fsgame/js/form',
|
| 331 |
'wrapper' => 'fsgame-character-skill-wrapper',
|
| 332 |
'effect' => 'slide',
|
| 333 |
),
|
| 334 |
);
|
| 335 |
}
|
| 336 |
else { // existing character so stare at your stats, bub.
|
| 337 |
$class = fsgame_world_load('classes', $node->fsgame['character']['class']);
|
| 338 |
|
| 339 |
if (!$class) {
|
| 340 |
drupal_set_message("This character's class was not found; please contact a site administrator.", 'error');
|
| 341 |
return; // if this character no longer is plausible, complain loudly to the site admin cos they broke something.
|
| 342 |
}
|
| 343 |
|
| 344 |
$form['fsgame']['character']['classes']['class'] = array(
|
| 345 |
'#type' => 'item',
|
| 346 |
'#value' => t('Level @level !class_and_modifiers.',
|
| 347 |
array(
|
| 348 |
'@level' => $node->fsgame['character']['level'],
|
| 349 |
'!class_and_modifiers' => fsgame_attributes_modifiers_string($class),
|
| 350 |
)
|
| 351 |
),
|
| 352 |
);
|
| 353 |
|
| 354 |
foreach ($node->fsgame['character']['skills'] as $type => $skill) {
|
| 355 |
}
|
| 356 |
// $form['fsgame']['character']['skills']['skill'] = array(
|
| 357 |
// '#type' => 'item',
|
| 358 |
// '#value' => t('Level @level !class_and_modifiers.',
|
| 359 |
// array(
|
| 360 |
// '@level' => $node->fsgame['character']['level'],
|
| 361 |
// '!class_and_modifiers' => fsgame_attributes_modifiers_string($class),
|
| 362 |
// )
|
| 363 |
// ),
|
| 364 |
// );
|
| 365 |
}
|
| 366 |
|
| 367 |
$form['body'] = array(
|
| 368 |
'#default_value' => isset($node->body) ? $node->body : '',
|
| 369 |
'#title' => check_plain($type->body_label),
|
| 370 |
'#type' => 'textarea',
|
| 371 |
'#required' => FALSE,
|
| 372 |
'#rows' => 10,
|
| 373 |
);
|
| 374 |
|
| 375 |
$form['#validate'][] = 'fsgame_character_node_form_validate';
|
| 376 |
|
| 377 |
return $form;
|
| 378 |
}
|
| 379 |
|
| 380 |
/**
|
| 381 |
* FormAPI #validate for fsgame_character_form().
|
| 382 |
*/
|
| 383 |
function fsgame_character_node_form_validate($form, &$form_state) {
|
| 384 |
foreach (fsgame_base_attributes() as $attribute) {
|
| 385 |
if (!is_numeric($form_state['values']['fsgame']['character'][$attribute['id']])) {
|
| 386 |
form_set_error('fsgame][character]['. $attribute['id'], t('The %attribute attribute must be a number.', array('%attribute' => fsgame_base_attributes($attribute['id'], 'title'))));
|
| 387 |
}
|
| 388 |
}
|
| 389 |
}
|
| 390 |
|
| 391 |
/**
|
| 392 |
* Implementation of hook_load() for characters.
|
| 393 |
*/
|
| 394 |
function fsgame_character_load($node) {
|
| 395 |
$character = db_fetch_array(db_query("SELECT * FROM {fsgame_character} WHERE nid = %d", $node->nid));
|
| 396 |
return array('fsgame' => array('character' => $character));
|
| 397 |
}
|
| 398 |
|
| 399 |
/**
|
| 400 |
* Implementation of hook_view() for characters.
|
| 401 |
*/
|
| 402 |
function fsgame_character_view($node, $teaser = FALSE, $page = FALSE) {
|
| 403 |
drupal_add_css(drupal_get_path('module', 'fsgame') .'/fsgame.css');
|
| 404 |
|
| 405 |
$node = node_prepare($node, $teaser);
|
| 406 |
$node->content['fsgame_class'] = array(
|
| 407 |
'#value' => theme('fsgame_character_class', $node),
|
| 408 |
);
|
| 409 |
|
| 410 |
$node->content['fsgame_attributes'] = array(
|
| 411 |
'#value' => theme('fsgame_character_attributes', $node),
|
| 412 |
);
|
| 413 |
|
| 414 |
return $node;
|
| 415 |
}
|
| 416 |
|
| 417 |
/**
|
| 418 |
* Implementation of hook_insert() for characters.
|
| 419 |
*/
|
| 420 |
function fsgame_character_insert($node) {
|
| 421 |
global $user;
|
| 422 |
|
| 423 |
$node->fsgame['character']['nid'] = $node->nid;
|
| 424 |
|
| 425 |
// modify the attributes permanently based on the user's class.
|
| 426 |
$class = fsgame_world_load('classes', $node->fsgame['character']['class']);
|
| 427 |
if (isset($class['permanent modifiers'])) { // presuming, of course, they exist.
|
| 428 |
foreach ($class['permanent modifiers'] as $attribute_id => $modifier) {
|
| 429 |
$node->fsgame['character'][$attribute_id] += $modifier;
|
| 430 |
}
|
| 431 |
}
|
| 432 |
|
| 433 |
drupal_write_record('fsgame_character', $node->fsgame['character']);
|
| 434 |
|
| 435 |
$node->fsgame['character']['skills'][$node->fsgame['character']['skill']] = 1;
|
| 436 |
$skill = array();
|
| 437 |
$skill['skill'] = $node->fsgame['character']['skill'];
|
| 438 |
$skill['level'] = 1;
|
| 439 |
$skill['nid'] = $node->nid;
|
| 440 |
unset($node->fsgame['character']['skill']);
|
| 441 |
|
| 442 |
drupal_write_record('fsgame_character_skills', $skill);
|
| 443 |
|
| 444 |
// If this is an anonymous user, then set the session to this character.
|
| 445 |
if (!$user->uid) {
|
| 446 |
$_SESSION['fsgame_contest_anonymous_character'] = $node->nid;
|
| 447 |
}
|
| 448 |
else {
|
| 449 |
// Otherwise, this now counts as our latest character.
|
| 450 |
fsgame_user_set_latest_character($user->uid, $node->nid);
|
| 451 |
}
|
| 452 |
}
|
| 453 |
|
| 454 |
/**
|
| 455 |
* Implementation of hook_update() for characters.
|
| 456 |
*/
|
| 457 |
function fsgame_character_update($node) {
|
| 458 |
$node->fsgame['character']['nid'] = $node->nid;
|
| 459 |
drupal_write_record('fsgame_character', $node->fsgame['character'], 'nid');
|
| 460 |
}
|
| 461 |
|
| 462 |
/**
|
| 463 |
* Implementation of hook_delete() for characters.
|
| 464 |
*/
|
| 465 |
function fsgame_character_delete($node) {
|
| 466 |
db_query('DELETE FROM {fsgame_character} WHERE nid = %d', $node->nid);
|
| 467 |
}
|
| 468 |
|
| 469 |
/**
|
| 470 |
* Return the base definitions of our attributes.
|
| 471 |
*
|
| 472 |
* @param $attribute
|
| 473 |
* Defaults to NULL; one of 'rock', 'paper', or 'scissors'.
|
| 474 |
* @param $key
|
| 475 |
* Defaults to NULL; one of 'title', 'description', 'default_value', 'maximum' or 'minimum'.
|
| 476 |
* @return $array_or_string
|
| 477 |
* With no params, an array of 'rock', 'paper', and 'scissors', each containing:
|
| 478 |
* 'title' => The title assigned by the administrator to the attribute.
|
| 479 |
* 'description' => The description assigned by the administrator (default: none).
|
| 480 |
* 'default_value' => The value the attribute will default to for a new character.
|
| 481 |
* 'minimum' => The minimum value allowed. Normally the same as default_value.
|
| 482 |
* 'maximum' => The maximum value allowed. 0 means there is no maximum.
|
| 483 |
* 'trumps' => The internal attribute ID that this attribute beats in a tie.
|
| 484 |
* 'id' => The internal ID of the attribute.
|
| 485 |
*
|
| 486 |
* With an $attribute passed in, returns just the attribute specific keys above.
|
| 487 |
* With an $attribute and $key passed, the specific value of that key.
|
| 488 |
*/
|
| 489 |
function fsgame_base_attributes($attribute = NULL, $key = NULL) {
|
| 490 |
$internal_ids = array('rock', 'paper', 'scissors');
|
| 491 |
$trumps = array('scissors', 'rock', 'paper');
|
| 492 |
static $attributes = array();
|
| 493 |
|
| 494 |
if (!$attributes) {
|
| 495 |
foreach ($internal_ids as $internal_key => $internal_id) {
|
| 496 |
$attributes[$internal_id] = array(
|
| 497 |
'title' => variable_get('fsgame_attributes_'. $internal_id .'_title', t(drupal_ucfirst($internal_id))),
|
| 498 |
'description' => variable_get('fsgame_attributes_'. $internal_id .'_description', ''),
|
| 499 |
'default_value' => variable_get('fsgame_attributes_'. $internal_id .'_default', 1),
|
| 500 |
'minimum' => variable_get('fsgame_attributes_'. $internal_id .'_minimum', 1),
|
| 501 |
'maximum' => variable_get('fsgame_attributes_'. $internal_id .'_maximum', 0),
|
| 502 |
'trumps' => variable_get('fsgame_attributes_'. $attribute['id'] .'_trumps', $trumps[$internal_key]),
|
| 503 |
'id' => $internal_id, // make it explicit for easier array looping.
|
| 504 |
);
|
| 505 |
}
|
| 506 |
}
|
| 507 |
|
| 508 |
return $attribute ? ($key ? $attributes[$attribute][$key] : $attributes[$attribute]) : $attributes;
|
| 509 |
}
|
| 510 |
|
| 511 |
/**
|
| 512 |
* Return a list of attributes, suitable for use as FAPI #options.
|
| 513 |
*/
|
| 514 |
function fsgame_base_attributes_fapi() {
|
| 515 |
$options = array();
|
| 516 |
foreach (fsgame_base_attributes() as $attribute) {
|
| 517 |
$options[$attribute['id']] = t(drupal_ucfirst($attribute['title']));
|
| 518 |
} // this is not magick. we're just slightly lazy.
|
| 519 |
return $options;
|
| 520 |
}
|
| 521 |
|
| 522 |
/**
|
| 523 |
* Turn world data modifier into a human-readable string.
|
| 524 |
*
|
| 525 |
* The goal is ideally a string like: (Rock) (+2 Rock; -1 Paper).
|
| 526 |
* where the first "(Rock)" is the primary attribute of this item
|
| 527 |
* (or, in the case of classes, "(Rock/Paper/Paper)"), and then
|
| 528 |
* any modifiers (either permanent or temporary) semi-colon spliced.
|
| 529 |
*
|
| 530 |
* @param $world_data
|
| 531 |
* The array containing information about the world data item.
|
| 532 |
* @param $type
|
| 533 |
* What kind of human-readable data to return: defaults to "all".
|
| 534 |
* Can also be "permanent", "active", or "attributes". If you choose
|
| 535 |
* "all", the name of the world_data is also returned in the string.
|
| 536 |
* @return $string
|
| 537 |
* A string suitable for printing.
|
| 538 |
*/
|
| 539 |
function fsgame_attributes_modifiers_string($world_data = array(), $type = 'all') {
|
| 540 |
$attributes = array();
|
| 541 |
if (is_array($world_data['attributes'])) {
|
| 542 |
foreach ($world_data['attributes'] as $attribute_id) {
|
| 543 |
$attributes[] = fsgame_base_attributes($attribute_id, 'title');
|
| 544 |
} // build this item's attribute list (single or tri).
|
| 545 |
}
|
| 546 |
|
| 547 |
// permanent modifiers can never be removed once they're appended to the character.
|
| 548 |
// active modifiers only apply when the world data is in use (an equipped item, etc.).
|
| 549 |
foreach (array('permanent', 'active') as $modifier_type) {
|
| 550 |
if (!isset($world_data[$modifier_type .' modifiers'])) { continue; }
|
| 551 |
foreach ($world_data[$modifier_type .' modifiers'] as $attribute_id => $attribute_modifier) {
|
| 552 |
if ($attribute_modifier > 0) { $attribute_modifier = '+'. $attribute_modifier; } // math symbolism goOOOd.
|
| 553 |
$modifiers[$modifier_type][] = t('@attribute @modifier', array('@attribute' => fsgame_base_attributes($attribute_id, 'title'), '@modifier' => $attribute_modifier));
|
| 554 |
} // if we've got some modifiers, we'll bundle them all together into a happy string, overwriting the interim array we've created. they then get inserted into the final string we return below.
|
| 555 |
$modifiers[$modifier_type] = count($modifiers[$modifier_type]) > 0 ? t('<strong>@modifier_type</strong>: @modifiers', array('@modifier_type' => drupal_ucfirst($modifier_type), '@modifiers' => implode(', ', $modifiers[$modifier_type]))) : '';
|
| 556 |
}
|
| 557 |
|
| 558 |
switch ($type) {
|
| 559 |
case 'all':
|
| 560 |
return t('@title (@attributes!permanent_modifiers!active_modifiers)',
|
| 561 |
array(
|
| 562 |
'@title' => $world_data['title'],
|
| 563 |
'@attributes' => implode('/', $attributes),
|
| 564 |
'!permanent_modifiers' => $modifiers['permanent'] ? '; ' . $modifiers['permanent'] : '',
|
| 565 |
'!active_modifiers' => $modifiers['active'] ? '; ' . $modifiers['active'] : '',
|
| 566 |
)
|
| 567 |
);
|
| 568 |
case 'attributes':
|
| 569 |
return t('@attributes', array('@attributes' => implode('/', $attributes)));
|
| 570 |
case 'permanent':
|
| 571 |
return t('!permanent_modifiers', array('!permanent_modifiers' => $modifiers['permanent']));
|
| 572 |
case 'active':
|
| 573 |
return t('!active_modifiers', array('!active_modifiers' => $modifiers['active']));
|
| 574 |
}
|
| 575 |
}
|
| 576 |
|
| 577 |
/**
|
| 578 |
* This is the basic fight between two characters.
|
| 579 |
*
|
| 580 |
* When running the contest, all stats are determined
|
| 581 |
*
|
| 582 |
* @param &$contest
|
| 583 |
* This array will contain at a minimum the following elements. Modules implementing hook_fsgame_contest_alter may add to and alter
|
| 584 |
* this array at various stages in the contest.
|
| 585 |
*
|
| 586 |
* At a minimum, the array must contain the following elements:
|
| 587 |
* 'character' => A valid fsgame_character object owned by the current user.
|
| 588 |
* 'opponent' => A valid fsgame_character object not owned by the current user.
|
| 589 |
* 'character attack',
|
| 590 |
* 'character defense',
|
| 591 |
* 'opponent attack',
|
| 592 |
* 'opponent defense' => Arrays containing the selected attacks and defenses of the characters.
|
| 593 |
* These will each contain at least the following:
|
| 594 |
* 'skill' => the machine-name of the skill being used
|
| 595 |
* 'attribute' => the stat the skill uses
|
| 596 |
* 'title' => the human readable title of the skill being used
|
| 597 |
* 'modifiers' => an array with modifiers to the specific attack or defense.
|
| 598 |
* these will be created by modules invoking hook_fsgame_contest_alter, and each key of the 'mods' sub-array must
|
| 599 |
* at least contain the following:
|
| 600 |
* 'unique_modifier_id' => array('title' => A string describing the modifier, 'level' => The amount by which to modify the skill)
|
| 601 |
*
|
| 602 |
* Throughout the contest, as hook_fsgame_contest is invoked, the current stage of the contest will be sent as an additional parameter.
|
| 603 |
*
|
| 604 |
* After resolving the contest, a 'results' key in $contest will contain an array with information concerning the results.
|
| 605 |
* If that key is empty, then the contest was not resolved. Otherwise, it will contain at least the following elements:
|
| 606 |
* 'character' => the final result of the character's attack
|
| 607 |
* 'opponent' => the final result of the opponent's attack
|
| 608 |
* 'win' => either the character object, the opponent object, or the string 'draw'
|
| 609 |
*/
|
| 610 |
function fsgame_contest(&$contest) {
|
| 611 |
$contest['results'] = array();
|
| 612 |
|
| 613 |
if (!fsgame_contest_allow($contest)) {
|
| 614 |
// Set the win to disallowed. Additionally, a disallowing module may set an explanation string in $contest['results']['disallow'].
|
| 615 |
$contest['results']['win'] = 'disallowed';
|
| 616 |
return FALSE;
|
| 617 |
}
|
| 618 |
|
| 619 |
_fsgame_contest_select_opponent_modes($contest);
|
| 620 |
|
| 621 |
// modules may add modifiers here
|
| 622 |
drupal_alter('fsgame_contest', $contest, 'before');
|
| 623 |
|
| 624 |
// tally the modifiers
|
| 625 |
foreach (array('character', 'opponent') as $which) {
|
| 626 |
foreach (array('attack', 'defense') as $element) {
|
| 627 |
_fsgame_contest_tally_mid_results($contest, $which, $element);
|
| 628 |
}
|
| 629 |
}
|
| 630 |
|
| 631 |
// modules may affect the initial results here
|
| 632 |
drupal_alter('fsgame_contest', $contest, 'during');
|
| 633 |
|
| 634 |
// tally final results, deducting valid defense from attacks and comparing final results
|
| 635 |
foreach (array('character' => 'opponent', 'opponent' => 'character') as $defense => $attack) {
|
| 636 |
if ($contest["$defense defense"]['attribute'] == $contest["$attack attack"]['attribute']) {
|
| 637 |
$contest["$attack attack"]['result'] -= $contest["$defense defense"]['result'];
|
| 638 |
drupal_set_message("defense against {$contest["$defense defense"]['attribute']}: $attack attack modified to {$contest["$attack attack"]['result']}.");
|
| 639 |
}
|
| 640 |
}
|
| 641 |
|
| 642 |
_fsgame_contest_determine_winner($contest);
|
| 643 |
|
| 644 |
// modules may act on the final results here
|
| 645 |
drupal_alter('fsgame_contest', $contest, 'after');
|
| 646 |
|
| 647 |
fsgame_character_set_latest_opponent($contest['character']->nid, $contest['opponent']->nid);
|
| 648 |
}
|
| 649 |
|
| 650 |
/**
|
| 651 |
* Implement hook_fsgame_contest.
|
| 652 |
*/
|
| 653 |
function fsgame_fsgame_contest(&$contest, $stage) {
|
| 654 |
switch ($stage) {
|
| 655 |
case 'allow':
|
| 656 |
global $user;
|
| 657 |
// Unless the user is an admin or the game otherwise allows, fail if the characters belong to the same user.
|
| 658 |
if (!user_access('administer 5 Second Game') && !variable_get('fsgame_contest_allow_same_user', FALSE) && ($contest['character']->uid == $contest['opponent']->uid)) {
|
| 659 |
$contest['results']['disallow'] = variable_get('fsgame_contest_disallow_same_user_message', t('You may not fight another character that you own.'));
|
| 660 |
return FALSE;
|
| 661 |
}
|
| 662 |
return TRUE;
|
| 663 |
case 'during':
|
| 664 |
// TODO: add admin-determined dice rolls to results
|
| 665 |
}
|
| 666 |
}
|
| 667 |
|
| 668 |
/**
|
| 669 |
* Determine the opponent's contest modes.
|
| 670 |
*/
|
| 671 |
function _fsgame_contest_select_opponent_modes(&$contest) {
|
| 672 |
$attributes = fsgame_base_attributes();
|
| 673 |
foreach ($attributes as $key => $attribute) {
|
| 674 |
$attacks[$key] = $attribute['title'];
|
| 675 |
$defenses[$key] = $attribute['title'];
|
| 676 |
}
|
| 677 |
// Allow modules implementing hook_fsgame_available_modes_alter to add/remove their own skills to/from the selectors.
|
| 678 |
drupal_alter('fsgame_available_modes', $attacks, 'opponent', 'attack', $contest['character'], $contest['opponent']);
|
| 679 |
drupal_alter('fsgame_available_modes', $defenses, 'opponent', 'defense', $contest['character'], $contest['opponent']);
|
| 680 |
|
| 681 |
// select a random attack/defense from the remaining options
|
| 682 |
$contest['opponent attack'] = fsgame_contest_select_mode('attack', array_rand($attacks), $contest['opponent'], $contest['character']);
|
| 683 |
$contest['opponent defense'] = fsgame_contest_select_mode('defense', array_rand($defenses), $contest['opponent'], $contest['character']);
|
| 684 |
}
|
| 685 |
|
| 686 |
/**
|
| 687 |
* This will populate the appropriate array with the skill & modifiers for a contest.
|
| 688 |
* @param $mode
|
| 689 |
* 'attack' or 'defense'
|
| 690 |
* @param $skill
|
| 691 |
* A string with the key to a skill.
|
| 692 |
* @param $character
|
| 693 |
* The character node whose skill this is. Note that this may refer to a contest's character or opponent.
|
| 694 |
* @param $opponent
|
| 695 |
* The character node opposing the character.
|
| 696 |
*/
|
| 697 |
function fsgame_contest_select_mode($mode, $skill, $character, $opponent) {
|
| 698 |
return array(
|
| 699 |
'skill' => $skill,
|
| 700 |
'attribute' => $skill,
|
| 701 |
'title' => 'The skill title',
|
| 702 |
'modifiers' => array(
|
| 703 |
'base' => array(
|
| 704 |
'title' => 'A random modifier',
|
| 705 |
'level' => fsgame_dice('1d6'),
|
| 706 |
),
|
| 707 |
),
|
| 708 |
);
|
| 709 |
}
|
| 710 |
|
| 711 |
/**
|
| 712 |
* Allow modules to disallow a contest between characters.
|
| 713 |
* If a module implements hook_fsgame_allow_contest, then that hook will be invoked.
|
| 714 |
* If any hook returns FALSE, then the contest will be disallowed, halting further processing.
|
| 715 |
* @param $contest
|
| 716 |
* A contest array, as outlined in fsgame_contest.
|
| 717 |
*/
|
| 718 |
function fsgame_contest_allow(&$contest) {
|
| 719 |
// don't allow nodes that are not fsgame_character type to continue, or if they are the same character.
|
| 720 |
if ($contest['character']->type != 'fsgame_character' || $contest['opponent']->type != 'fsgame_character') {
|
| 721 |
$contest['results']['disallow'] = variable_get('fsgame_contest_disallow_illegal_type_message', t('Illegal character types.'));
|
| 722 |
return FALSE;
|
| 723 |
}
|
| 724 |
if ($contest['character']->nid == $contest['opponent']->nid) {
|
| 725 |
$contest['results']['disallow'] = variable_get('fsgame_contest_disallow_self_contest_message', t('You may not fight yourself.'));
|
| 726 |
return FALSE;
|
| 727 |
}
|
| 728 |
foreach (module_implements('fsgame_contest') as $module) {
|
| 729 |
if (!module_invoke($module, 'fsgame_contest', $contest, 'allow')) {
|
| 730 |
// If a module disallows a contest, it may send an explanation to $contest['results']['disallow'].
|
| 731 |
return FALSE;
|
| 732 |
}
|
| 733 |
}
|
| 734 |
return TRUE;
|
| 735 |
}
|
| 736 |
|
| 737 |
function _fsgame_contest_determine_winner(&$contest) {
|
| 738 |
foreach (array('character' => 'opponent', 'opponent' => 'character') as $attacker => $defender) {
|
| 739 |
$contest['results'][$attacker] = $contest["$attacker attack"]['result'];
|
| 740 |
if (fsgame_base_attributes($contest["$attacker attack"]['attribute'], 'trumps') == $contest["$defender attack"]['attribute']) {
|
| 741 |
$contest['results'][$attacker] = intval($contest['results'][$attacker] * variable_get('fsgame_trump_multiplier', 1.5));
|
| 742 |
drupal_set_message("$attacker {$contest["$attacker attack"]['attribute']} trumps {$contest["$defender attack"]['attribute']}: X 1.5 = {$contest['results'][$attacker]}.");
|
| 743 |
}
|
| 744 |
}
|
| 745 |
if ($contest['results']['character'] > $contest['results']['opponent']) {
|
| 746 |
$contest['results']['win'] = $contest['character'];
|
| 747 |
}
|
| 748 |
else if ($contest['results']['opponent'] > $contest['results']['character']) {
|
| 749 |
$contest['results']['win'] = $contest['opponent'];
|
| 750 |
}
|
| 751 |
else if (variable_get('fsgame_allow_draws', TRUE)) {
|
| 752 |
$contest['results']['win'] = 'draw';
|
| 753 |
}
|
| 754 |
else {
|
| 755 |
$contest['results']['win'] = $contest['opponent'];
|
| 756 |
}
|
| 757 |
}
|
| 758 |
|
| 759 |
function _fsgame_contest_tally_mid_results(&$contest, $which, $element) {
|
| 760 |
// $value = isset($contest[$which .' '. $element]['attribute']) ? $contest[$which]->{$contest[$which .' '. $element]['attribute']} : 0;
|
| 761 |
$contest[$which .' '. $element]['result'] = intval($value) + _fsgame_contest_apply_modifiers($contest[$which .' '. $element]);
|
| 762 |
drupal_set_message("$which $element: {$contest[$which .' '. $element]['result']} ({$contest[$which .' '. $element]['attribute']})");
|
| 763 |
}
|
| 764 |
|
| 765 |
function _fsgame_contest_apply_modifiers($mode) {
|
| 766 |
$level = 0;
|
| 767 |
if (is_array($mode['modifiers'])) {
|
| 768 |
foreach ($mode['modifiers'] as $modifier) {
|
| 769 |
$level += intval($modifier['level']);
|
| 770 |
}
|
| 771 |
}
|
| 772 |
return $level;
|
| 773 |
}
|
| 774 |
|
| 775 |
/**
|
| 776 |
* Load and cache our various world data.
|
| 777 |
*
|
| 778 |
* This is a generic world loading function so that new modules
|
| 779 |
* can benefit from this API, and the cache that it creates.
|
| 780 |
*
|
| 781 |
* @param $type
|
| 782 |
* The type of data to load (classes, items, arenas, etc.).
|
| 783 |
* @param $id
|
| 784 |
* If passed, the ID of $type that should be returned.
|
| 785 |
* @param $refresh
|
| 786 |
* Forces a refresh of the cached $type data.
|
| 787 |
* @return $items
|
| 788 |
* If $type not passed, all world data currently loaded.
|
| 789 |
* If $type is passed, an array of all known world data of that type.
|
| 790 |
* If $type and $id passed, the specific data of $type to return.
|
| 791 |
*/
|
| 792 |
function fsgame_world_load($type = NULL, $id = NULL, $refresh = FALSE) {
|
| 793 |
static $world = array();
|
| 794 |
|
| 795 |
if (!$world[$type] || $refresh) {
|
| 796 |
if (!$refresh && $cache = cache_get('fsgame_world_'. $type)) {
|
| 797 |
$world[$type] = unserialize($cache->data);
|
| 798 |
}
|
| 799 |
else {
|
| 800 |
$world[$type] = module_invoke_all('fsgame_world_'. $type);
|
| 801 |
foreach ($world[$type] as $type_id => $type_info) {
|
| 802 |
// store the ID inside for easier reference.
|
| 803 |
$world[$type][$type_id]['id'] = $type_id;
|
| 804 |
} // cache this world type data for one hour.
|
| 805 |
arsort($world[$type]); // alphabetical order please.
|
| 806 |
cache_set('fsgame_world_'. $type, serialize($world[$type]), 'cache', time() + 3600);
|
| 807 |
}
|
| 808 |
}
|
| 809 |
|
| 810 |
return $type ? ($id ? $world[$type][$id] : $world[$type]) : $world;
|
| 811 |
}
|
| 812 |
|
| 813 |
/**
|
| 814 |
* Roll dice and return the sum. Simple enough, eh?
|
| 815 |
*
|
| 816 |
* The only parameter is a string in traditional RPG dice notation. Examples
|
| 817 |
* include 4d6, 3d8, 3^5d6 (weighted, taking the highest 3 of 5 dice rolled),
|
| 818 |
* 1d100+50, 6d6-6, 1d50+50*4-1, and so on and so forth.
|
| 819 |
*/
|
| 820 |
function fsgame_dice($notation) {
|
| 821 |
|
| 822 |
// remove whitespace and turn "x" to "*".
|
| 823 |
$notation = str_replace('x', '*', $notation);
|
| 824 |
$notation = preg_replace('/\s/', '', $notation);
|
| 825 |
|
| 826 |
// if we're keeping high rolls, find out how many and store in $keep_highest.
|
| 827 |
if (strstr($notation, '^')) { list($keep_highest, $notation) = explode('^', $notation); }
|
| 828 |
|
| 829 |
// split our notation on the "d". nothing magical.
|
| 830 |
list($num_rolls, $remainder) = explode('d', $notation);
|
| 831 |
|
| 832 |
// if there are operations to be done after the dice roll,
|
| 833 |
// split at the first one so we can get the number of sides,
|
| 834 |
// and save the rest into $modifiers for eval()ing later on.
|
| 835 |
if (preg_match('/^\d*([\+\-\*\/])/', $remainder)) {
|
| 836 |
$matches = preg_split('/([\+\-\*\/])/', $remainder, -1, PREG_SPLIT_DELIM_CAPTURE);
|
| 837 |
$num_sides = array_shift($matches); $modifiers = implode('', $matches);
|
| 838 |
} else { $num_sides = $remainder; $modifiers = NULL; }
|
| 839 |
|
| 840 |
// roll however many times necessary and $keep_highest as needed.
|
| 841 |
for ($ctr = 0; $ctr < $num_rolls; $ctr++) { $virgins[] = rand(1, $num_sides); }
|
| 842 |
if (isset($keep_highest)) { rsort($virgins); $virgins = array_splice($virgins, 0, $keep_highest); }
|
| 843 |
$rolling_result = array_sum($virgins);
|
| 844 |
|
| 845 |
// eval is simply easiest here so if we have to run one,
|
| 846 |
// we'll remove anything not a number or math-related.
|
| 847 |
if (isset($modifiers)) {
|
| 848 |
// TODO: i think the "d" is misleading -- makes it seem like it processes multiple dice events,
|
| 849 |
// when it's actually ignored and fails everything after. -winborn
|
| 850 |
$modifiers = preg_replace('/[^(\d|\+|\-|\*|\/|\(|\))]/', '', $modifiers);
|
| 851 |
eval("\$final_result = $rolling_result $modifiers;"); // ssshShHhh.
|
| 852 |
} else { $final_result = $rolling_result; }
|
| 853 |
|
| 854 |
return $final_result;
|
| 855 |
}
|
| 856 |
|
| 857 |
/**
|
| 858 |
* Implement hook_user.
|
| 859 |
* @TODO: This doesn't seem to work properly.
|
| 860 |
*/
|
| 861 |
function fsgame_user($op, &$edit, &$account, $category = NULL) {
|
| 862 |
switch ($op) {
|
| 863 |
case 'login':
|
| 864 |
if ($_SESSION['fsgame_contest_anonymous_character']) {
|
| 865 |
$node = node_load($_SESSION['fsgame_contest_anonymous_character']);
|
| 866 |
if (fsgame_claim_access($node)) {
|
| 867 |
drupal_set_message(t("The character %title was created anonymously from this computer. You may not use the character again unless you !claim. If you do not claim that character before logging off, then it may not be used again.", array('%title' => $node->title, '!claim' => l(t('claim the character'), 'fsgame/claim/'. $node->nid))));
|
| 868 |
}
|
| 869 |
}
|
| 870 |
break;
|
| 871 |
case 'logout':
|
| 872 |
unset($_SESSION['fsgame_contest_anonymous_character']);
|
| 873 |
break;
|
| 874 |
case 'load':
|
| 875 |
$account->fsgame_latest_character = fsgame_user_get_latest_character($account->uid);
|
| 876 |
break;
|
| 877 |
case 'save':
|
| 878 |
fsgame_user_set_latest_character($account->uid, $account->fsgame_latest_character);
|
| 879 |
break;
|
| 880 |
case 'delete':
|
| 881 |
db_query('DELETE FROM {fsgame_user} WHERE uid = %d', $account->uid);
|
| 882 |
break;
|
| 883 |
}
|
| 884 |
}
|
| 885 |
|
| 886 |
/**
|
| 887 |
* Set the most recently accessed character of a user's account.
|
| 888 |
* @param $uid
|
| 889 |
* The account uid to set the latest character.
|
| 890 |
* If it equals $global $user->uid, then we also set $user->fsgame_latest_character to that character.
|
| 891 |
* @param $nid
|
| 892 |
* The nid of the character node.
|
| 893 |
* @return
|
| 894 |
* FALSE if unsuccessful. Otherwise SAVED_NEW or SAVED_UPDATED.
|
| 895 |
*/
|
| 896 |
function fsgame_user_set_latest_character($uid, $nid) {
|
| 897 |
if ($uid && is_numeric($uid) && $nid && is_numeric($nid)) {
|
| 898 |
global $user;
|
| 899 |
if ($uid == $user->uid) {
|
| 900 |
$user->fsgame_latest_character = $nid;
|
| 901 |
}
|
| 902 |
if (db_result(db_query("SELECT uid FROM {fsgame_user} WHERE uid=%d", $uid))) {
|
| 903 |
return drupal_write_record('fsgame_user', $user, 'fsgame_latest_character');
|
| 904 |
// db_query("UPDATE {fsgame_user} SET latest_character = %d WHERE uid = %d", $nid, $uid);
|
| 905 |
}
|
| 906 |
else {
|
| 907 |
return drupal_write_record('fsgame_user', $user);
|
| 908 |
// db_query("INSERT INTO {fsgame_user} (uid, latest_character) VALUES (%d, %d)", $uid, $nid);
|
| 909 |
}
|
| 910 |
}
|
| 911 |
return FALSE;
|
| 912 |
}
|
| 913 |
|
| 914 |
/**
|
| 915 |
* Return the most recently accessed character of an account.
|
| 916 |
* @param $uid
|
| 917 |
* The account to check for the latest character.
|
| 918 |
* @return
|
| 919 |
* The nid of the account's latest character node.
|
| 920 |
*/
|
| 921 |
function fsgame_user_get_latest_character($uid) {
|
| 922 |
return db_result(db_query("SELECT fsgame_latest_character FROM {fsgame_user} WHERE uid=%d", $uid));
|
| 923 |
}
|
| 924 |
|
| 925 |
/**
|
| 926 |
* Return the most recently fought opponent of a character.
|
| 927 |
* @param $nid
|
| 928 |
* The character to check for the latest opponent.
|
| 929 |
* @return
|
| 930 |
* The nid of the character's latest opponent node.
|
| 931 |
*/
|
| 932 |
function fsgame_character_get_latest_opponent($nid) {
|
| 933 |
return db_result(db_query("SELECT latest_opponent FROM {fsgame_character} WHERE nid=%d", $nid));
|
| 934 |
}
|
| 935 |
|
| 936 |
/**
|
| 937 |
* Set the most recently fought opponent of a character.
|
| 938 |
* @param $character_nid
|
| 939 |
* The nid of the character node.
|
| 940 |
* @param $opponent_nid
|
| 941 |
* The nid of the opponent node.
|
| 942 |
*/
|
| 943 |
function fsgame_character_set_latest_opponent($character_nid, $opponent_nid) {
|
| 944 |
if ($character_nid && is_numeric($character_nid) && $opponent_nid && is_numeric($opponent_nid)) {
|
| 945 |
db_query("UPDATE {fsgame_character} SET latest_opponent = %d WHERE nid = %d", $opponent_nid, $character_nid);
|
| 946 |
}
|
| 947 |
}
|