/[drupal]/contributions/modules/game_queue/game_queue.module
ViewVC logotype

Contents of /contributions/modules/game_queue/game_queue.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (show annotations) (download) (as text)
Tue Jan 6 03:57:35 2009 UTC (10 months, 2 weeks ago) by aaron
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-6--1
File MIME type: text/x-php
 * Create initial game queue module (aaron).
1 <?php
2 // $Id$
3
4 /**
5 * @file
6 * A Game Queue will act on clock ticks, allowing game characters to add
7 * actions to a queue, which will be processed in turn.
8 */
9
10 /**
11 * Implements hook_help().
12 */
13 function game_queue_help($section) {
14 switch ($section) {
15 case 'admin/settings/game_queue':
16 return t("
17 <p>A Game Queue will act on clock ticks, allowing game characters to add action to a queue, which will be processed in turn.</p>
18 <p>Actions take 1 or more Action Points (AP). A character is allowed 1 or more AP to be processed in a single tick.</p>
19 <p>Before processing, each action is also assigned an Initiative weight.</p>
20 ", array('!help' => l(t('Game Clock help'), 'admin/help/game_queue')));
21 case 'admin/help#game_queue':
22 module_load_include('inc', 'game_queue', 'includes/game_queue.help');
23 return _game_queue_help($section);
24 }
25 }
26
27 /**
28 * Implements hook_menu().
29 */
30 function game_queue_menu() {
31 module_load_include('inc', 'game_queue', 'includes/game_queue.menu');
32 return _game_queue_menu();
33 }
34
35 /**
36 * Implements hook_perm().
37 */
38 function game_queue_perm() {
39 return array('administer game queue');
40 }
41
42 /**
43 * Implements hook_game_clock_increment().
44 */
45 function game_queue_game_clock_increment($clock, $state) {
46 global $game_queue_full;
47 $game_queue_full = array();
48
49 $sql = "SELECT nid FROM {game_queue} WHERE cid=%d AND turn<%d GROUP BY nid ORDER BY turn, timestamp, aid";
50 $nodes = db_query($sql, $state->cid, $state->turn);
51 while ($node = db_fetch_object($nodes)) {
52 $actions = db_query("SELECT * FROM {game_queue} WHERE cid=%d AND turn<%d AND nid=%d ORDER BY turn, timestamp, aid", $state->cid, $state->turn, $node->nid);
53 while ($action = db_fetch_object($actions)) {
54 $action->options = unserialize($action->options);
55 game_queue_add_to_full_queue($action, $state);
56 }
57 }
58 game_queue_process_full_queue($state);
59 }
60
61 /**
62 * This will go through the queue turn by turn, character by character, and
63 * sort it by initiative.
64 * @param $state
65 * The clock's state. We need turn & ticks in particular.
66 */
67 function game_queue_process_full_queue($state) {
68 global $game_queue_full;
69
70 if (empty($game_queue_full)) {
71 return;
72 }
73
74 $game_queue = array();
75
76 $turn = $state->turn - $state->ticks + 1;
77
78 // Process each turn separately, in case things like character AP change.
79 while ($turn <= $state->turn) {
80 drupal_set_message("Turn: $turn");
81 // Build a new queue.
82 $game_queue = array();
83
84 // Go through whatever's left in the queue.
85 // We first go through each character and fill in the turns,
86 // according to the character's initiative.
87 foreach ($game_queue_full as $nid => $actions) {
88 // Go through each available action from the character until they have no further actions for this turn.
89 foreach ($actions as $number => $action) {
90 // If the next action isn't set to occur until a later turn, then break.
91 // (Actions are inserted into the queue sorted by turn).
92 if ($action->turn > $turn) {
93 break;
94 }
95
96 if ($action->prep) {
97 $action->ap -= $action->available_ap;
98 }
99
100 // The action knows how many AP are still available at this point.
101 $action->available_ap = isset($available_ap) ? $available_ap : ($available_ap = game_queue_available_ap($action->nid));
102 // The action knows its initiative as well.
103 $action->initiative = isset($initiative) ? $initiative : ($initiative = game_queue_initiative($action));
104
105 // Initialize the turn's queue initiative slot.
106 if (!isset($game_queue[$action->initiative])) {
107 $game_queue[$action->initiative] = array();
108 }
109
110 // If we don't have enough action points available, then the action is simply being prepped.
111 if ($action->ap > $action->available_ap) {
112 // The action can only be prepped this turn.
113 $action->prep = TRUE;
114 // Add the action to the turn's queue.
115 $game_queue[$action->initiative][] = $action;
116
117 // We have no available AP left.
118 $available_ap = 0;
119 // We'll need to make sure we grab the action on the next go-around, with the new AP if possible.
120 }
121 else {
122 // The action will be performed, so knock it off the queue.
123 unset($game_queue_full[$nid][$number]);
124 // How many AP are available after performing the action?
125 $available_ap -= $action->ap;
126 // Unset $action->prep, in case it's been set from the last turn.
127 unset($action->prep);
128 // Add the action to the turn's queue.
129 $game_queue[$action->initiative][] = $action;
130 }
131 // If this character has no further available AP this turn, then go to the next character.
132 if ($available_ap <= 0) {
133 break;
134 }
135 }
136 // Clear available AP & Initiative for the next character.
137 unset($available_ap);
138 unset($initiative);
139 }
140 // We have the queue filled up for the turn. Process it!
141 game_queue_process_turn($game_queue);
142 // Go to the next turn.
143 $turn++;
144 }
145 unset($game_queue_full);
146 }
147
148 /**
149 * Set up the initial "full" queue as an array by nid.
150 * Later we'll process by turns.
151 */
152 function game_queue_add_to_full_queue($action, $state) {
153 global $game_queue_full;
154
155 if (!isset($game_queue_full[$action->nid])) {
156 $game_queue_full[$action->nid] = array();
157 }
158 $game_queue_full[$action->nid][] = $action;
159 }
160
161 /**
162 * Determine a game character's available AP.
163 * Base of 1 by default, but can be altered with
164 * hook_game_queue_available_ap_alter(&$points, $nid).
165 */
166 function game_queue_available_ap($nid) {
167 static $ap;
168
169 if (!isset($ap)) {
170 $ap = array();
171 }
172 if (!isset($ap[$nid])) {
173 $points = variable_get('game_queue_available_ap', 1) + rand(0, 2);
174 drupal_alter('game_queue_available_ap', $points, $nid);
175 $ap[$nid] = $points;
176 }
177 return $ap[$nid];
178 }
179
180 /**
181 * Determine the initiative of a specific action.
182 * Actions are performed from lowest initiative to highest.
183 */
184 function game_queue_initiative($action) {
185 // Set our base initiative.
186 $initiative = variable_get('game_queue_base_initiative', 1) + rand(1, 6);
187 // Allow modules to invoke hook_game_queue_initiative(&$initiative, $action);
188 drupal_alter('game_queue_initiative', $initiative, $action);
189 return $initiative;
190 }
191
192 /**
193 * Process all actions in a turn.
194 */
195 function game_queue_process_turn($queue) {
196 ksort($queue);
197 foreach ($queue as $initiative => $actions) {
198 foreach ($actions as $action) {
199 // Allow modules to alter an action.
200 drupal_alter('game_queue_action', $action, $queue);
201 // Allow modules to act on the action. We send the queue in case future actions are to be deleted or altered.
202 module_invoke_all('game_queue_action', $action, $queue);
203
204 // If the action was in process of being prepared, then write it back with the new turn, etc.
205 // That way, it can be processed in a later turn, just in case we don't get to that turn this go-around.
206 // Otherwise (in most cases), delete it from the database.
207 if ($action->prep) {
208 $action->options = serialize($action->options);
209 drupal_write_record('game_queue', $action, array('aid'));
210 }
211 else {
212 db_query("DELETE FROM {game_queue} WHERE aid=%d", $action->aid);
213 }
214 }
215 }
216 }
217
218 /**
219 * Add an action object or array to the queue.
220 * 'nid' => The character's nid.
221 * 'cid' => The clock cid.
222 * 'action' => A string describing the action, usually machine readable.
223 * 'options' => An array of options to pass when processing the action.
224 * 'turn' => The turn to process the action. If 0, then process on the next turn.
225 * 'ap' => How many Action Points (AP) it will take to process this action.
226 */
227 function game_queue_add_action(&$action) {
228 // Convert to an object in case the action comes to us as an array.
229 if (is_array($action)) {
230 $action = (object) $action;
231 $is_array = TRUE;
232 }
233 else {
234 $is_array = FALSE;
235 }
236
237 // If the clock isn't set, then set it to a default clock.
238 if (!$action->cid) {
239 // TODO: Optional defaults clocks for node types and fields.
240 if ($clock = variable_get('game_queue_default_clock', 1)) {
241 $action->cid = $clock;
242 }
243 }
244
245 $action->timestamp = time();
246 $action->options = serialize($action->options);
247
248 drupal_write_record('game_queue', $action);
249
250 $action->options = unserialize($action->options);
251 if ($is_array) {
252 $action = (array) $action;
253 }
254 }
255
256 /**
257 * For debugging purposes.
258 */
259 function game_queue_game_queue_action($action) {
260 drupal_set_message("Action: {$action->action}, NID: {$action->nid}, Initiative: {$action->initiative}, Prep: {$action->prep}, AP: {$action->ap}, Available AP: {$action->available_ap}");
261 }

  ViewVC Help
Powered by ViewVC 1.1.2