1 /*
2 * ActionQueues.cpp
3 * created for Marathon: Aleph One <http://source.bungie.org/>
4
5 Copyright (C) 1991-2002 and beyond by Bungie Studios, Inc.
6 and the "Aleph One" developers.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 This license is contained in the file "COPYING",
19 which is included with this source code; it is available online at
20 http://www.gnu.org/licenses/gpl.html
21
22
23 May 9, 2002 (Loren Petrich):
24 Changed enqueueActionFlags() so that it can make zombie players controllable by Pfhortran;
25 did this by adding the argument "ZombiesControllable" (default: false)
26
27 Jun 9, 2002 (tiennou):
28 Following the above example, I modified dequeueActionFlags() & countActionFlags().
29
30 Feb 3, 2003 (Woody Zenfell):
31 Made 'ZombiesControllable' a property of a queue-set rather than an argument to the methods.
32
33 May 14, 2003 (Woody Zenfell):
34 Can reset a single action queue within a set now, principally for use with
35 LegacyActionQueueToTickBasedQueueAdapter.
36
37 June 14, 2003 (Woody Zenfell):
38 Added "peekActionFlags()" method to examine action_flags without removing them
39
40 * An ActionQueues object encapsulates a set of players' action_queues.
41 *
42 * Created by woody on Wed Feb 20 2002.
43 */
44
45 #include "ActionQueues.h"
46
47 #include "player.h" // for get_player_data()
48 #include "Logging.h"
49
50 // basically ripped from player.cpp::allocate_player_memory().
ActionQueues(unsigned int inNumPlayers,unsigned int inQueueSize,bool inZombiesControllable)51 ActionQueues::ActionQueues(unsigned int inNumPlayers, unsigned int inQueueSize, bool inZombiesControllable) : mNumPlayers(inNumPlayers), mQueueSize(inQueueSize), mZombiesControllable(inZombiesControllable) {
52
53 /* allocate space for our action queue headers and the queues themselves */
54 mQueueHeaders = new action_queue[mNumPlayers];
55 mFlagsBuffer = new uint32[mNumPlayers * mQueueSize];
56
57 assert(mQueueHeaders && mFlagsBuffer);
58
59 /* tell the queues where their buffers are */
60 for (unsigned i = 0; i < mNumPlayers; ++i)
61 {
62 mQueueHeaders[i].buffer= mFlagsBuffer + i*mQueueSize;
63 // From reset()
64 mQueueHeaders[i].read_index = mQueueHeaders[i].write_index = 0;
65 }
66 }
67
68
69
~ActionQueues()70 ActionQueues::~ActionQueues() {
71 if(mFlagsBuffer)
72 delete [] mFlagsBuffer;
73
74 if(mQueueHeaders)
75 delete [] mQueueHeaders;
76 }
77
78
79
80 // Lifted from player.cpp::reset_player_queues()
81 void
reset()82 ActionQueues::reset()
83 {
84 for (unsigned i=0; i < mNumPlayers; ++i) {
85 mQueueHeaders[i].read_index = mQueueHeaders[i].write_index = 0;
86 }
87 }
88
89
90
91 void
resetQueue(int inPlayerIndex)92 ActionQueues::resetQueue(int inPlayerIndex)
93 {
94 assert(inPlayerIndex >= 0 && inPlayerIndex < static_cast<int>(mNumPlayers));
95 mQueueHeaders[inPlayerIndex].read_index = mQueueHeaders[inPlayerIndex].write_index = 0;
96 }
97
98
99
100 // Lifted from player.cpp::queue_action_flags()
101 /* queue an action flag on the given player�s queue (no zombies allowed) */
102 void
enqueueActionFlags(int player_index,const uint32 * action_flags,int count)103 ActionQueues::enqueueActionFlags(
104 int player_index,
105 const uint32 *action_flags,
106 int count)
107 {
108 struct player_data *player= get_player_data(player_index);
109 struct action_queue *queue= mQueueHeaders+player_index;
110
111 // Cannot enqueue onto a Zombie queue unless explicitly allowed
112 if (!mZombiesControllable && PLAYER_IS_ZOMBIE(player))
113 return;
114
115 while ((count-= 1)>=0)
116 {
117 queue->buffer[queue->write_index]= *action_flags++;
118 queue->write_index= (queue->write_index+1) % mQueueSize;
119 if (queue->write_index==queue->read_index)
120 logError("blew player %d's queue", player_index);
121 }
122
123 return;
124 }
125
126
127 // Lifted from player.cpp::dequeue_action_flags()
128 /* dequeue�s a single action flag from the given queue (zombies always return zero) */
129 uint32
dequeueActionFlags(int player_index)130 ActionQueues::dequeueActionFlags(
131 int player_index)
132 {
133 struct player_data *player= get_player_data(player_index);
134 struct action_queue *queue= mQueueHeaders+player_index;
135
136 uint32 action_flags;
137
138 // Non-controllable zombies always just return 0 for their action_flags.
139 if (!mZombiesControllable && PLAYER_IS_ZOMBIE(player))
140 {
141 action_flags= 0;
142 }
143 else if (queue->read_index==queue->write_index)
144 {
145 // None to be read
146 action_flags= 0;
147 logError("dequeueing empty ActionQueue for player %d", player_index);
148 }
149 else
150 {
151 // assert(queue->read_index!=queue->write_index);
152 action_flags= queue->buffer[queue->read_index];
153 queue->read_index= (queue->read_index+1) % mQueueSize;
154 }
155
156 return action_flags;
157 }
158
159
160
161 uint32
peekActionFlags(int inPlayerIndex,size_t inElementsFromHead)162 ActionQueues::peekActionFlags(int inPlayerIndex, size_t inElementsFromHead)
163 {
164 // ZZZ: much of this body copied from dequeueActionFlags. Sorry about that...
165 struct player_data *player= get_player_data(inPlayerIndex);
166 struct action_queue *queue= mQueueHeaders+inPlayerIndex;
167
168 uint32 action_flags;
169
170 // Non-controllable zombies always just return 0 for their action_flags.
171 if (!mZombiesControllable && PLAYER_IS_ZOMBIE(player))
172 {
173 action_flags= 0;
174 }
175 else if (inElementsFromHead >= countActionFlags(inPlayerIndex))
176 {
177 // None to be read
178 action_flags= 0;
179 logError("peeking too far ahead (%d/%d) in ActionQueue for player %d", inElementsFromHead, countActionFlags(inPlayerIndex), inPlayerIndex);
180 }
181 else
182 {
183 size_t theQueueIndex = (queue->read_index + inElementsFromHead) % mQueueSize;
184 action_flags= queue->buffer[theQueueIndex];
185 }
186
187 return action_flags;
188 }
189
190
191 // Lifted from player.cpp::get_action_queue_size()
192 /* returns the number of elements sitting in the given queue (zombies always return queue diameter) */
193 unsigned int
countActionFlags(int player_index)194 ActionQueues::countActionFlags(
195 int player_index)
196 {
197 struct player_data *player= get_player_data(player_index);
198 struct action_queue *queue= mQueueHeaders+player_index;
199 unsigned int size;
200
201 // Non-controllable zombies have lots and lots of do-nothing flags available.
202 if (!mZombiesControllable && PLAYER_IS_ZOMBIE(player))
203 {
204 size= mQueueSize;
205 }
206 else
207 {
208 // ZZZ: better? phrasing of this operation (no branching; only one store; also, works with unsigned's)
209 size = (mQueueSize + queue->write_index - queue->read_index) % mQueueSize;
210 }
211
212 return size;
213 }
214
215
216
217 bool
zombiesControllable()218 ActionQueues::zombiesControllable() {
219 return mZombiesControllable;
220 }
221
222
223
224 void
setZombiesControllable(bool inZombiesControllable)225 ActionQueues::setZombiesControllable(bool inZombiesControllable) {
226 mZombiesControllable = inZombiesControllable;
227 }
228
modifyActionFlags(int inPlayerIndex,uint32 inFlags,uint32 inFlagsMask)229 void ModifiableActionQueues::modifyActionFlags(int inPlayerIndex, uint32 inFlags, uint32 inFlagsMask)
230 {
231 if (!countActionFlags(inPlayerIndex))
232 {
233 logError("no flags when modifying ActionQueue for player %d", inPlayerIndex);
234 return;
235 }
236
237 action_queue *queue = mQueueHeaders + inPlayerIndex;
238 if (queue->buffer[queue->read_index] != 0xffffffff)
239 queue->buffer[queue->read_index] = (queue->buffer[queue->read_index] & ~inFlagsMask) | (inFlags & inFlagsMask);
240
241 }
242