/*
* ActionQueues.cpp
* created for Marathon: Aleph One
Copyright (C) 1991-2002 and beyond by Bungie Studios, Inc.
and the "Aleph One" developers.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
This license is contained in the file "COPYING",
which is included with this source code; it is available online at
http://www.gnu.org/licenses/gpl.html
May 9, 2002 (Loren Petrich):
Changed enqueueActionFlags() so that it can make zombie players controllable by Pfhortran;
did this by adding the argument "ZombiesControllable" (default: false)
Jun 9, 2002 (tiennou):
Following the above example, I modified dequeueActionFlags() & countActionFlags().
Feb 3, 2003 (Woody Zenfell):
Made 'ZombiesControllable' a property of a queue-set rather than an argument to the methods.
May 14, 2003 (Woody Zenfell):
Can reset a single action queue within a set now, principally for use with
LegacyActionQueueToTickBasedQueueAdapter.
June 14, 2003 (Woody Zenfell):
Added "peekActionFlags()" method to examine action_flags without removing them
* An ActionQueues object encapsulates a set of players' action_queues.
*
* Created by woody on Wed Feb 20 2002.
*/
#include "ActionQueues.h"
#include "player.h" // for get_player_data()
#include "Logging.h"
// Lifted from player.cpp; changed short to int
struct ActionQueues::action_queue {
unsigned int read_index, write_index;
uint32 *buffer;
};
// basically ripped from player.cpp::allocate_player_memory().
ActionQueues::ActionQueues(unsigned int inNumPlayers, unsigned int inQueueSize, bool inZombiesControllable) : mNumPlayers(inNumPlayers), mQueueSize(inQueueSize), mZombiesControllable(inZombiesControllable) {
/* allocate space for our action queue headers and the queues themselves */
mQueueHeaders = new action_queue[mNumPlayers];
mFlagsBuffer = new uint32[mNumPlayers * mQueueSize];
assert(mQueueHeaders && mFlagsBuffer);
/* tell the queues where their buffers are */
for (unsigned i = 0; i < mNumPlayers; ++i)
{
mQueueHeaders[i].buffer= mFlagsBuffer + i*mQueueSize;
// From reset()
mQueueHeaders[i].read_index = mQueueHeaders[i].write_index = 0;
}
}
ActionQueues::~ActionQueues() {
if(mFlagsBuffer)
delete [] mFlagsBuffer;
if(mQueueHeaders)
delete [] mQueueHeaders;
}
// Lifted from player.cpp::reset_player_queues()
void
ActionQueues::reset()
{
for (unsigned i=0; i < mNumPlayers; ++i) {
mQueueHeaders[i].read_index = mQueueHeaders[i].write_index = 0;
}
}
void
ActionQueues::resetQueue(int inPlayerIndex)
{
assert(inPlayerIndex >= 0 && inPlayerIndex < static_cast(mNumPlayers));
mQueueHeaders[inPlayerIndex].read_index = mQueueHeaders[inPlayerIndex].write_index = 0;
}
// Lifted from player.cpp::queue_action_flags()
/* queue an action flag on the given playerŐs queue (no zombies allowed) */
void
ActionQueues::enqueueActionFlags(
int player_index,
const uint32 *action_flags,
int count)
{
struct player_data *player= get_player_data(player_index);
struct action_queue *queue= mQueueHeaders+player_index;
// Cannot enqueue onto a Zombie queue unless explicitly allowed
if (!mZombiesControllable && PLAYER_IS_ZOMBIE(player))
return;
while ((count-= 1)>=0)
{
queue->buffer[queue->write_index]= *action_flags++;
queue->write_index= (queue->write_index+1) % mQueueSize;
if (queue->write_index==queue->read_index)
logError1("blew player %dŐs queue", player_index);
}
return;
}
// Lifted from player.cpp::dequeue_action_flags()
/* dequeueŐs a single action flag from the given queue (zombies always return zero) */
uint32
ActionQueues::dequeueActionFlags(
int player_index)
{
struct player_data *player= get_player_data(player_index);
struct action_queue *queue= mQueueHeaders+player_index;
uint32 action_flags;
// Non-controllable zombies always just return 0 for their action_flags.
if (!mZombiesControllable && PLAYER_IS_ZOMBIE(player))
{
action_flags= 0;
}
else if (queue->read_index==queue->write_index)
{
// None to be read
action_flags= 0;
logError1("dequeueing empty ActionQueue for player %d", player_index);
}
else
{
// assert(queue->read_index!=queue->write_index);
action_flags= queue->buffer[queue->read_index];
queue->read_index= (queue->read_index+1) % mQueueSize;
}
return action_flags;
}
uint32
ActionQueues::peekActionFlags(int inPlayerIndex, size_t inElementsFromHead)
{
// ZZZ: much of this body copied from dequeueActionFlags. Sorry about that...
struct player_data *player= get_player_data(inPlayerIndex);
struct action_queue *queue= mQueueHeaders+inPlayerIndex;
uint32 action_flags;
// Non-controllable zombies always just return 0 for their action_flags.
if (!mZombiesControllable && PLAYER_IS_ZOMBIE(player))
{
action_flags= 0;
}
else if (inElementsFromHead >= countActionFlags(inPlayerIndex))
{
// None to be read
action_flags= 0;
logError3("peeking too far ahead (%d/%d) in ActionQueue for player %d", inElementsFromHead, countActionFlags(inPlayerIndex), inPlayerIndex);
}
else
{
size_t theQueueIndex = (queue->read_index + inElementsFromHead) % mQueueSize;
action_flags= queue->buffer[theQueueIndex];
}
return action_flags;
}
// Lifted from player.cpp::get_action_queue_size()
/* returns the number of elements sitting in the given queue (zombies always return queue diameter) */
unsigned int
ActionQueues::countActionFlags(
int player_index)
{
struct player_data *player= get_player_data(player_index);
struct action_queue *queue= mQueueHeaders+player_index;
unsigned int size;
// Non-controllable zombies have lots and lots of do-nothing flags available.
if (!mZombiesControllable && PLAYER_IS_ZOMBIE(player))
{
size= mQueueSize;
}
else
{
// ZZZ: better? phrasing of this operation (no branching; only one store; also, works with unsigned's)
size = (mQueueSize + queue->write_index - queue->read_index) % mQueueSize;
}
return size;
}
bool
ActionQueues::zombiesControllable() {
return mZombiesControllable;
}
void
ActionQueues::setZombiesControllable(bool inZombiesControllable) {
mZombiesControllable = inZombiesControllable;
}