Files
Coleman-Code/COM380/Project5/GambleKit/Engine/Game/Entities/GkGameReels.cpp
T
Amrit Panesar 39ee821f54 start 380 project5
changes to 380 project 4
changes to 350 project 2

Signed-off-by: Amrit Panesar <apanesar@4195tech.com>
2015-05-06 10:18:39 -07:00

517 lines
14 KiB
C++

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// GambleKit Copyright (C) 2014 Ivan Donev
//
// This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
//
// This library 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// contact: gamblekit@gmail.com
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//#include <stdlib.h>
// Consider reels options:
// 1. GkGameReel is a class, a fully visual GkGameEntity
// GkGameReels is a collection of GkGameReel objects and manager for lines, winnings, sequential starting/stopping a reel, etc.
// Pros. GkGameReels is lighest, GkGameReel is a fully useful GkGameEntity
// Cons. Many settings, such as the "items" collection of AnimatedTextures, the "reelMap" and etc. must reoccur in all GkGameReel objects and the GkGameReels object, Changing a setting in GkGameReels will not "automatically" take effect until it is changed in all GkGameReel objects also
// 2. GkGameReel is a class, and is abstract in a sense that it provides only the mechanics of a reel via a spinning position
// GkGameReels is a collection of GkGameReel objects and aside from all the other things, also does the drawing of the reels
// Pros. GkGameReels is relatively light, GkGameReel functionality is separated in its own class
// Cons. GkGameReel is not useful unless used with GkGameReels. GkGameReels holds relatively little (maybe close to irrelevant for a whole class) logic and value
// 3. GkGameReels has each reel internal and has methods processing a reel. All the logic is inside that class.
// Pros. No GkGameReel class, no need for different objects to share or have the same information (for settings)
// Cons. GkGameReels is more heavily loaded with code logic. Does not quite correspond to the architecture model so far.
#include "GkGameReels.h"
#include "..\..\OSSpecific\GkOSUtils.h"
#include "..\..\Utils\GkMaths.h"
#include "..\GkGame.h"
#include "..\..\Utils\GkMaths.h"
GkGameReels::GkGameReels(int numReels, int numReelItems, int numSymbols, int width, int height)
: GkBaseReelMap(numReels, numReelItems)
{
this->width = width;
this->height = height;
this->numSymbols = numSymbols;
this->state = Idle;
this->stateOld = Idle;
this->stateChange = Undefined;
this->numReelAnimations = this->numReelItems + 2;
this->reels = new GkGameReelInfo[numReels];
for (int i = 0; i < numReels; i++)
{
this->reels[i].state = Idle;
this->reels[i].stateOld = Idle;
this->reels[i].stateChange = Undefined;
this->reels[i].position = 0.0f;
this->reels[i].animations = new GkGameAnimation*[this->numReelAnimations];
for (int itemIndex = 0; itemIndex < this->numReelAnimations; itemIndex++)
{
this->reels[i].animations[itemIndex] = new GkGameAnimation();
this->reels[i].animations[itemIndex]->visible = true;
this->reels[i].animations[itemIndex]->active = false;
this->reels[i].animations[itemIndex]->loop = false;
}
}
this->symbols = new GkAnimatedTexture*[numSymbols];
this->speed = 20.0f;
this->acceleration = 40.0f;
this->stoppingTime = 1.0f;
this->preStartOffset = 0.15f;
this->preStartSpeed = 2.0f;
this->postStopOffset = 0.15f;
this->postStopSpeed = 2.0f;
this->itemGenerator = 0;
}
GkGameReels::~GkGameReels(void)
{
for (int i = 0; i < numReels; i++)
{
for (int j = 0; j < this->numReelAnimations; j++)
{
delete[] this->reels[i].animations[j];
}
delete[] this->reels[i].animations;
}
delete[] this->symbols;
delete[] this->reels;
}
void GkGameReels::SetItemGenerator(GkGameReelsCombinationGenerator *itemGenerator)
{
this->itemGenerator = itemGenerator;
}
GkAnimatedTexture *GkGameReels::Reel_GetNewSymbol(int reelIndex)
{
if (this->itemGenerator != 0)
{
return this->symbols[this->itemGenerator->reels[reelIndex].model->GetSymbol()];
}
else
return this->symbols[GkMaths::Random(this->numSymbols)];
}
void GkGameReels::Reel_ProcessPosition(int reelIndex, GkGame *game)
{
GkGameReelInfo *reel = &this->reels[reelIndex];
// Handle position ranging and shifting of symbols when position hops over 1.0
reel->position += game->timer->tickTime * reel->speed;
if (reel->position >= 1.0f)
{
int numShifts = (int)reel->position;
reel->position -= numShifts;
int reelShifts = GkMaths::Min(numShifts, this->numReelItems - reel->reelMapSetIndex + 1);
for (int shiftIndex = 0; shiftIndex < reelShifts; shiftIndex++)
{
GkGameAnimation *rotAnimation = reel->animations[this->numReelAnimations - 1];
for (int i = 0; i < this->numReelAnimations; i++)
{
GkGameAnimation *t = reel->animations[i];
reel->animations[i] = rotAnimation;
rotAnimation = t;
}
if (reel->state == Stopping)
{
if (reel->reelMapSetIndex < this->numReelItems)
reel->animations[0]->SetAnimatedTexture(this->symbols[this->GetSymbol(reelIndex, this->numReelItems - 1 - reel->reelMapSetIndex)]);
else
{
reel->animations[0]->SetAnimatedTexture(this->Reel_GetNewSymbol(reelIndex));
}
reel->reelMapSetIndex++;
}
else
{
reel->animations[0]->SetAnimatedTexture(this->Reel_GetNewSymbol(reelIndex));
}
}
}
for (int i = 0; i < this->numReelAnimations; i++)
{
reel->animations[i]->Process(game);
}
}
void GkGameReels::Reel_ProcessState(int reelIndex, GkGameTimer *timer)
{
GkGameReelInfo *reel = &this->reels[reelIndex];
switch (reel->state)
{
case Idle:
{
reel->speed = 0.0f;
reel->position = 0.0f;
// User interaction expected
break;
}
case PreStarting:
{
reel->speed = 0.0f;
reel->position -= timer->tickTime * this->preStartSpeed;
if (reel->position < -this->preStartOffset)
{
reel->position = -this->preStartOffset;
reel->state = Starting;
}
break;
}
case Starting:
{
reel->speed += this->acceleration * timer->tickTime;
if (reel->speed >= this->speed)
{
reel->speed = this->speed;
reel->state = Spinning;
}
break;
}
case Spinning:
{
// User interaction expected
break;
}
case Stopping:
{
if ((reel->reelMapSetIndex > this->numReelItems) && (reel->position >= this->postStopOffset))
{
reel->position = this->postStopOffset;
reel->state = PostStopping;
}
break;
}
case PostStopping:
{
reel->speed = 0.0f;
reel->position -= timer->tickTime * this->postStopSpeed;
if (reel->position < 0.0f)
{
reel->position = 0.0f;
reel->state = Idle;
}
break;
}
}
reel->stateChange = reel->state != reel->stateOld ? reel->state : Undefined;
reel->stateOld = reel->state;
}
bool GkGameReels::Reel_Start(int reelIndex)
{
GkGameReelInfo *reel = &this->reels[reelIndex];
if (reel->state == Idle)
{
reel->state = PreStarting;
reel->reelMapSetIndex = 0;
return true;
}
return false;
}
bool GkGameReels::Reel_Stop(int reelIndex)
{
GkGameReelInfo *reel = &this->reels[reelIndex];
if (reel->state == Spinning)
{
reel->state = Stopping;
reel->reelMapSetIndex = 0;
return true;
}
return false;
}
// Gives a summary state. If all reels have the same state, returns that state, otherwise returns Undefined. If a reel has a Blocked state, it's ignored, unless all reels have Blocked state, in which case Blocked is returned.
GameReelState GkGameReels::GetGeneralState()
{
GameReelState result = Undefined;
int reelIndex = 0;
while (reelIndex < this->numReels)
{
GameReelState reelState = this->reels[reelIndex].state;
if (result == Undefined)
{
result = reelState;
}
else if (result == Blocked)
{
if (reelState != Blocked)
{
result = reelState;
}
}
else
{
if ((result != reelState) && (reelState != Blocked))
{
return Undefined;
}
}
reelIndex++;
}
return result;
}
void GkGameReels::ProcessState(GkGameTimer *timer)
{
GameReelState generalState = this->GetGeneralState();
// Ensure each state is followed by the next for at least one frame
switch (this->state)
{
case Idle:
{
if ((this->state != generalState) && (generalState != Undefined))
this->state = PreStarting;
break;
}
case PreStarting:
{
if ((this->state != generalState) && (generalState != Undefined))
this->state = Starting;
break;
}
case Starting:
{
if ((this->state != generalState) && (generalState != Undefined))
this->state = Spinning;
break;
}
case Spinning:
{
if ((this->state != generalState) && (generalState != Undefined))
this->state = Stopping;
break;
}
case Stopping:
{
float fullStopTime = GkMaths::Max(this->stoppingTime - this->numReelItems / this->speed - this->postStopOffset / this->postStopSpeed, 0.0f);
float timeSinceStopInitiated = GkGameTimer::GetSampleTime(this->stopInitiatedTime);
int reelsStopped = fullStopTime != 0 ? GkMaths::Min((int)(1 + (this->numReels - 1) * timeSinceStopInitiated / fullStopTime), this->numReels) : this->numReels;
int stopCount = 0;
for (int i = 0; i < this->numReels; i++)
{
this->Reel_Stop(i);
if ((this->reels[i].state != Blocked) && (this->reels[i].state != Spinning))
stopCount++;
if (stopCount >= reelsStopped)
break;
}
if (reelsStopped == this->numReels)
this->state = PostStopping;
break;
}
case PostStopping:
{
if ((generalState == Idle) | (generalState == Blocked))
this->state = Idle;
//if ((this->state != generalState) && (generalState != Undefined))
// this->state = Idle;
break;
}
default:
{
this->state = generalState;
}
}
this->stateChange = this->state != this->stateOld ? this->state : Undefined;
this->stateOld = this->state;
}
void GkGameReels::Process(GkGame *game)
{
for (int reelIndex = 0; reelIndex < this->numReels; reelIndex++)
{
this->Reel_ProcessPosition(reelIndex, game);
this->Reel_ProcessState(reelIndex, game->timer);
}
this->ProcessState(game->timer);
}
void GkGameReels::Draw(GkGame *game)
{
int itemWidth = this->symbols[0]->frames[0]->width;
int itemHeight = this->symbols[0]->frames[0]->height;
float horizontalDistance = this->numReels == 1 ? itemWidth : itemWidth + (this->width - this->numReels * itemWidth) / ((float)this->numReels - 1.0f);
for (int reelIndex = 0; reelIndex < this->numReels; reelIndex++)
{
int x = (int)(this->x + reelIndex * horizontalDistance);
for (int itemIndex = 0; itemIndex < this->numReelAnimations; itemIndex++)
{
int y = (int)(this->y + (this->height - this->numReelAnimations * itemHeight) / 2 + this->reels[reelIndex].position * itemHeight + itemIndex * itemHeight);
GkGameAnimation *reelItemAnimation = this->reels[reelIndex].animations[itemIndex];
game->graphicsDevice->DrawClipped(x, y, this->x, this->y, this->width, this->height, reelItemAnimation->animatedTexture->frames[(int)reelItemAnimation->currentFrame]);
}
}
}
void GkGameReels::ApplyReelMap(const int *fullItemMap)
{
if (fullItemMap != 0)
{
this->SetItems(fullItemMap);
}
for (int reelIndex = 0; reelIndex < this->numReels; reelIndex++)
{
this->reels[reelIndex].animations[0]->SetAnimatedTexture(this->symbols[GkMaths::Random(this->numSymbols)]);
this->reels[reelIndex].animations[this->numReelAnimations - 1]->SetAnimatedTexture(this->symbols[GkMaths::Random(this->numSymbols)]);
}
for (int reelIndex = 0; reelIndex < this->numReels; reelIndex++)
{
for (int itemIndex = 0; itemIndex < this->numReelItems; itemIndex++)
{
this->reels[reelIndex].animations[itemIndex + 1]->SetAnimatedTexture(this->symbols[this->GetSymbol(reelIndex, itemIndex)]);
}
}
}
bool GkGameReels::Start()
{
this->reelingTime = GkGameTimer::GetSample();
bool result = true;
if (this->state == Idle)
{
for (int i = 0; i < this->numReels; i++)
result &= this->Reel_Start(i);
return result;
}
return false;
}
bool GkGameReels::Stop()
{
if (this->state = Spinning)
{
this->stopInitiatedTime = GkGameTimer::GetSample();
this->state = Stopping;
return true;
}
return false;
bool result = true;
if (this->state == Spinning)
{
for (int i = 0; i < this->numReels; i++)
result &= this->Reel_Stop(i);
return result;
}
return false;
}
bool GkGameReels::ItemsAnimationsPlaying()
{
for (int reelIndex = 0; reelIndex < this->numReels; reelIndex++)
{
for (int itemIndex = 0; itemIndex < this->numReelItems; itemIndex++)
{
if (this->reels[reelIndex].animations[itemIndex + 1]->active)
return true;
}
}
return false;
}
void GkGameReels::StopItemsAnimations()
{
for (int reelIndex = 0; reelIndex < this->numReels; reelIndex++)
{
for (int itemIndex = 0; itemIndex < this->numReelItems; itemIndex++)
{
this->reels[reelIndex].animations[itemIndex + 1]->active = false;
this->reels[reelIndex].animations[itemIndex + 1]->currentFrame = 0.0f;
}
}
}
float GkGameReels::GetReelingTime()
{
return GkGameTimer::GetSampleTime(this->reelingTime);
}
float GkGameReels::GetIdleTime()
{
return GkGameTimer::GetSampleTime(this->idleTime);
}