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