generated from sigonasr2/CPlusPlusProjectTemplate
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
780 lines
29 KiB
780 lines
29 KiB
#include "../entity.h"
|
|
#include "../item.h"
|
|
#include "../layers.h"
|
|
#include <string>
|
|
#define OLC_PGE_APPLICATION
|
|
#include "../pixelGameEngine.h"
|
|
#define OLC_PGEX_SPLASHSCREEN
|
|
#include "../splash.h"
|
|
#define OLC_SOUNDWAVE
|
|
#include "../defines.h"
|
|
#include "../soundwaveEngine.h"
|
|
#include "../tiles.h"
|
|
#include "../references.h"
|
|
#include "../states.h"
|
|
#include "../flags.h"
|
|
#include <assert.h>
|
|
#include "../cutscene.h"
|
|
#include "../encounters.h"
|
|
#include "../particle.h"
|
|
#include "../effect.h"
|
|
#include "../battleproperty.h"
|
|
#include "test.h"
|
|
#include "../SeasonI.h"
|
|
#include "../map.h"
|
|
|
|
#define TestWhileMax(testname,condition,maxIterations) _TestWait(testname);while(_TestResolve(condition,maxIterations))
|
|
#define TestWhile(testname,condition) TestWhileMax(testname,condition,1000)
|
|
|
|
extern int frameCount;
|
|
extern double CUTSCENE_FADE_VALUE;
|
|
extern Cutscene*CurrentCutscene;
|
|
extern ActionType CurrentAction;
|
|
extern vd2d cameraPos;
|
|
extern bool messageBoxVisible;
|
|
extern std::string messageBoxText;
|
|
extern std::array<Entity*,7> PARTY_MEMBER_STATS;
|
|
extern Entity::pstats_t partyMemberDefaultStats;
|
|
extern std::map<std::string,Decal*> SPRITES;
|
|
extern std::map<std::string,Animation*> ANIMATIONS;
|
|
extern std::array<NPC_Obj*,4> PARTY_MEMBER_OBJ;
|
|
extern std::map<int,Object*> OBJ_INFO;
|
|
extern std::map<BattleMoveName,Battle::Move*>MOVELIST;
|
|
extern std::vector<Encounter*>ENCOUNTER_LIST;
|
|
extern std::map<Property,BattleProperty*> BATTLE_PROPERTIES;
|
|
extern std::map<MapName::Map,Map*> MAPS;
|
|
extern std::vector<CutsceneAction*>CUTSCENE_QUEUE;
|
|
extern std::vector<std::vector<TILE*>> MAP;
|
|
extern std::vector<std::vector<TILE*>> MAP2;
|
|
extern std::vector<std::vector<TILE*>> MAP3;
|
|
extern std::vector<std::vector<TILE*>> MAP4;
|
|
extern std::vector<std::vector<TILE*>> MAP5;
|
|
extern std::vector<std::vector<TILE*>> MAP6;
|
|
|
|
int testCount=0;
|
|
int MAX_ITERATIONS=1000;
|
|
int iterations=0;
|
|
|
|
enum class KeyIdentifier{
|
|
UP,
|
|
RIGHT,
|
|
DOWN,
|
|
LEFT,
|
|
BACK,
|
|
};
|
|
|
|
struct TestKey{
|
|
Key k;
|
|
std::string keyName;
|
|
KeyIdentifier id;
|
|
bool operator==(TestKey&other){
|
|
return id==other.id;
|
|
}
|
|
};
|
|
|
|
namespace key{
|
|
TestKey UP{Key::UP,"UP",KeyIdentifier::UP};
|
|
TestKey DOWN{Key::DOWN,"DOWN",KeyIdentifier::DOWN};
|
|
TestKey LEFT{Key::LEFT,"LEFT",KeyIdentifier::LEFT};
|
|
TestKey RIGHT{Key::RIGHT,"RIGHT",KeyIdentifier::RIGHT};
|
|
TestKey BACK{Key::BACK,"BACKSPACE",KeyIdentifier::BACK};
|
|
TestKey ESCAPE{Key::ESCAPE,"ESCAPE",KeyIdentifier::BACK};
|
|
TestKey X{Key::X,"X",KeyIdentifier::BACK};
|
|
TestKey CTRL{Key::CTRL,"CTRL",KeyIdentifier::BACK};
|
|
TestKey DEL{Key::DEL,"DEL",KeyIdentifier::BACK};
|
|
TestKey END{Key::END,"END",KeyIdentifier::BACK};
|
|
TestKey NP_DECIMAL{Key::NP_DECIMAL,"Numpad Decimal",KeyIdentifier::BACK};
|
|
TestKey NP_SUB{Key::NP_SUB,"Numpad Subtract",KeyIdentifier::BACK};
|
|
TestKey MINUS{Key::MINUS,"MINUS",KeyIdentifier::BACK};
|
|
TestKey PAUSE{Key::PAUSE,"PAUSE",KeyIdentifier::BACK};
|
|
TestKey TAB{Key::TAB,"TAB",KeyIdentifier::BACK};
|
|
TestKey CAPS_LOCK{Key::CAPS_LOCK,"CAPS LOCK",KeyIdentifier::BACK};
|
|
TestKey W{Key::W,"W",KeyIdentifier::UP};
|
|
TestKey A{Key::A,"A",KeyIdentifier::LEFT};
|
|
TestKey S{Key::S,"S",KeyIdentifier::DOWN};
|
|
TestKey D{Key::D,"D",KeyIdentifier::RIGHT};
|
|
TestKey NP8{Key::NP8,"NP8",KeyIdentifier::UP};
|
|
TestKey NP4{Key::NP4,"NP4",KeyIdentifier::LEFT};
|
|
TestKey NP5{Key::NP5,"NP5",KeyIdentifier::DOWN};
|
|
TestKey NP6{Key::NP6,"NP6",KeyIdentifier::RIGHT};
|
|
TestKey NP2{Key::NP2,"NP2",KeyIdentifier::DOWN};
|
|
}
|
|
|
|
void CopyMapContents(std::vector<std::vector<TILE*>>&from,std::vector<std::vector<TILE>>&to) {
|
|
for (int x=0;x<from.size();x++) {
|
|
std::vector<TILE> tiles;
|
|
for (int y=0;y<from[x].size();y++) {
|
|
tiles.push_back(TILE(from[x][y]->tileX,from[x][y]->tileY,from[x][y]->tileDegree));
|
|
}
|
|
to.push_back(tiles);
|
|
}
|
|
}
|
|
|
|
bool ValidateEntireMap(std::vector<std::vector<TILE*>>&mapref1,std::vector<std::vector<TILE>>&mapref2) {
|
|
for (int x=0;x<mapref1.size();x++) {
|
|
for (int y=0;y<mapref1[x].size();y++) {
|
|
if (mapref2[x][y]!=mapref1[x][y]) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool GetKeyPressed(SeasonI&instance,TestKey&k) {
|
|
if (k==key::UP) {
|
|
return instance.UpPressed();
|
|
}
|
|
if (k==key::DOWN) {
|
|
return instance.DownPressed();
|
|
}
|
|
if (k==key::RIGHT) {
|
|
return instance.RightPressed();
|
|
}
|
|
if (k==key::LEFT) {
|
|
return instance.LeftPressed();
|
|
}
|
|
if (k==key::BACK) {
|
|
return instance.BackPressed();
|
|
}
|
|
std::cerr<<"Something went terribly wrong! THIS SHOULD NOT BE HAPPENING!\n";
|
|
return false;
|
|
}
|
|
|
|
bool GetKeyHeld(SeasonI&instance,TestKey&k) {
|
|
if (k==key::UP) {
|
|
return instance.UpHeld();
|
|
}
|
|
if (k==key::DOWN) {
|
|
return instance.DownHeld();
|
|
}
|
|
if (k==key::RIGHT) {
|
|
return instance.RightHeld();
|
|
}
|
|
if (k==key::LEFT) {
|
|
return instance.LeftHeld();
|
|
}
|
|
if (k==key::BACK) {
|
|
return instance.BackHeld();
|
|
}
|
|
std::cerr<<"Something went terribly wrong! THIS SHOULD NOT BE HAPPENING!\n";
|
|
return false;
|
|
}
|
|
|
|
bool GetKeyReleased(SeasonI&instance,TestKey&k) {
|
|
if (k==key::UP) {
|
|
return instance.UpReleased();
|
|
}
|
|
if (k==key::DOWN) {
|
|
return instance.DownReleased();
|
|
}
|
|
if (k==key::RIGHT) {
|
|
return instance.RightReleased();
|
|
}
|
|
if (k==key::LEFT) {
|
|
return instance.LeftReleased();
|
|
}
|
|
if (k==key::BACK) {
|
|
return instance.BackReleased();
|
|
}
|
|
std::cerr<<"Something went terribly wrong! THIS SHOULD NOT BE HAPPENING!\n";
|
|
return false;
|
|
}
|
|
|
|
void Test(std::string name,bool success) {
|
|
testCount++;
|
|
std::cout<<"Test ("<<testCount<<") "<<name<<"..."<<std::endl;
|
|
assert(success);
|
|
std::cout<<" Passed"<<std::endl;
|
|
};
|
|
|
|
void _TestWait(std::string name) {
|
|
testCount++;
|
|
std::cout<<"Test ("<<testCount<<") "<<name<<"..."<<std::endl;
|
|
iterations=0;
|
|
};
|
|
|
|
bool _TestResolve(bool testCase,int maxIterations=MAX_ITERATIONS) {
|
|
if (!testCase) {
|
|
std::cout<<" Passed"<<std::endl;
|
|
return false;
|
|
}
|
|
if (iterations++>MAX_ITERATIONS) {
|
|
std::cout<<" FAILED! (Iterations>"<<maxIterations<<")"<<std::endl;
|
|
assert(!testCase);
|
|
}
|
|
return true;
|
|
};
|
|
|
|
void TestSpriteUndefined(std::vector<std::string> sprList) {
|
|
for (int i=0;i<sprList.size();i++) {
|
|
Test("Sprite "+sprList[i]+" should not be initialized",
|
|
SPRITES[sprList[i]]==nullptr);
|
|
}
|
|
}
|
|
void TestSpriteInitialized(std::vector<std::string> sprList) {
|
|
for (int i=0;i<sprList.size();i++) {
|
|
Test("Sprite "+sprList[i]+" should be initialized",
|
|
SPRITES[sprList[i]]!=nullptr);
|
|
Test("Sprite "+sprList[i]+" should have a non-zero width and height",
|
|
SPRITES[sprList[i]]->sprite->width!=0&&SPRITES[sprList[i]]->sprite->height!=0);
|
|
}
|
|
}
|
|
|
|
bool SeasonI::OnUserCreate(){
|
|
srand(time(NULL));
|
|
GAME=this;
|
|
for (int i=1;i<7;i++) {
|
|
CreateLayer();
|
|
EnableLayer(i,true);
|
|
}
|
|
SetPixelMode(Pixel::ALPHA);
|
|
GAME_STATE=GameState::TEST_GAME;
|
|
Test("We start in the TEST_GAME state",
|
|
GAME_STATE==GameState::TEST_GAME);
|
|
for (int i=0;i<PARTY_MEMBER_STATS.size();i++) {
|
|
Test("Party Member stats should not be initialized",
|
|
PARTY_MEMBER_STATS[i]==nullptr);
|
|
}
|
|
Test("No battle moves are loaded",
|
|
MOVELIST.size()==0);
|
|
SetupPartyMemberStats();
|
|
Test("Battle moves now exist (still not defined)",
|
|
MOVELIST.size()>0);
|
|
for (int i=0;i<PARTY_MEMBER_STATS.size();i++) {
|
|
Test("Party Members get initialized with correct defaults",
|
|
PARTY_MEMBER_STATS[i]->stats==partyMemberDefaultStats);
|
|
}
|
|
TestSpriteUndefined({"terrainmap.png","pixel.png","bufficons.png","rollingcounter.png","additionalFont.png"});
|
|
SetupAnimations();
|
|
TestSpriteInitialized({"terrainmap.png","pixel.png","bufficons.png","rollingcounter.png","additionalFont.png"});
|
|
Test("Player animation is undefined",
|
|
ANIMATIONS.count("player.png")==0);
|
|
Test("Party Member Object is not setup",
|
|
PARTY_MEMBER_OBJ[0]==nullptr);
|
|
vd2d testPos={0,0},testScale={2,2};
|
|
CreateObjectInfo(new Standard_Obj(PLAYER,"player",testPos,nullptr,testScale,MAGENTA,32),"player.png",{24,32});
|
|
Test("Player animation is defined",
|
|
ANIMATIONS["player.png"]!=nullptr);
|
|
Decal*playerAnimPointer=ANIMATIONS["player.png"]->spr;
|
|
Test("Player animation is setup correctly",
|
|
ANIMATIONS["player.png"]->frames>0&&ANIMATIONS["player.png"]->spr!=nullptr);
|
|
Test("Object Info database now has 1 entry",
|
|
OBJ_INFO.size()==1);
|
|
Test("Object Info is correctly assigned",
|
|
OBJ_INFO[0]->name=="player"&&OBJ_INFO[0]->id==PLAYER&&OBJ_INFO[0]->GetPos()==testPos&&OBJ_INFO[0]->GetScale()==testScale&&OBJ_INFO[0]->color==MAGENTA&&OBJ_INFO[0]->spr->sprSize.x==24&&OBJ_INFO[0]->spr->sprSize.y==32);
|
|
delete OBJ_INFO[PLAYER];
|
|
OBJ_INFO.erase(PLAYER);
|
|
Test("Object Info is cleared",
|
|
OBJ_INFO.size()==0);
|
|
SetupObjectInfo();
|
|
Test("Using the same sprite definition does not cause memory leak",
|
|
playerAnimPointer==OBJ_INFO[0]->spr->spr);
|
|
Test("No encounters are loaded",
|
|
ENCOUNTER_LIST.size()==0);
|
|
SetupEncounters();
|
|
Test("SetupEncounters() loads up new encounters",
|
|
ENCOUNTER_LIST.size()>0);
|
|
Encounter*testEncounter=new Encounter(encounter::ENCOUNTER_1,{0,0},std::array<vd2d,4>{vd2d
|
|
{grid(1,2)},{grid(2,2)},{grid(3,2)},{grid(4,2)}},
|
|
std::vector<Entity*>{
|
|
new Entity(new Standard_Obj(
|
|
NPC1_4,"Test Obj",3,2,ANIMATIONS["player.png"]),
|
|
{HP:70,maxHP:70,PP:10,maxPP:10,baseAtk:14,speed:5,resistances:{0,0,0,0}},std::vector<Battle::Move*>{
|
|
MOVELIST[BattleMoveName::TESTMOVE1],
|
|
MOVELIST[BattleMoveName::TESTMOVE2],
|
|
MOVELIST[BattleMoveName::TESTMOVE3],
|
|
},
|
|
{ITEMLIST[ItemName::COOKIE]},
|
|
돈 20),
|
|
new Entity(new Standard_Obj(
|
|
NPC1_4,"Test Obj 2",1,3,ANIMATIONS["player.png"]),
|
|
{HP:70,maxHP:70,PP:10,maxPP:10,baseAtk:14,speed:5,resistances:{0,0,0,0}},std::vector<Battle::Move*>{
|
|
MOVELIST[BattleMoveName::TESTMOVE1],
|
|
MOVELIST[BattleMoveName::TESTMOVE2],
|
|
},
|
|
{ITEMLIST[ItemName::PIZZA]}),
|
|
new Entity(new Standard_Obj(
|
|
NPC1_4,"Test Obj 3",2,2,ANIMATIONS["player.png"]),
|
|
{HP:70,maxHP:70,PP:10,maxPP:10,baseAtk:14,speed:5,resistances:{0,0,0,0}},std::vector<Battle::Move*>{
|
|
MOVELIST[BattleMoveName::TESTMOVE1],
|
|
}),
|
|
});
|
|
Test("Test encounter has three entities",
|
|
testEncounter->objs.size()==3);
|
|
Test("Test encounter uses ID ENCOUNTER_1",
|
|
testEncounter->id==encounter::ENCOUNTER_1);
|
|
testPos={0,0};
|
|
Test("Test encounter uses position ("+std::to_string(testPos.x)+","+std::to_string(testPos.y)+")",
|
|
testEncounter->pos==testPos);
|
|
Test("Test encounter player positions are correct",
|
|
testEncounter->playerPos==std::array<vd2d,4>{vd2d{grid(1,2)},{grid(2,2)},{grid(3,2)},{grid(4,2)}});
|
|
Test("Test encounter grid positions are correct",
|
|
testEncounter->playerPos==std::array<vd2d,4>{vd2d{grid(1,2)},{grid(2,2)},{grid(3,2)},{grid(4,2)}});
|
|
Test("Enemy 1 has 3 battle moves",
|
|
testEncounter->objs[0]->moveSet==std::vector<Battle::Move*>{
|
|
MOVELIST[BattleMoveName::TESTMOVE1],
|
|
MOVELIST[BattleMoveName::TESTMOVE2],
|
|
MOVELIST[BattleMoveName::TESTMOVE3],
|
|
});
|
|
Test("Enemy 1 has a cookie as a drop",
|
|
testEncounter->objs[0]->inventory==std::vector<Item*>{ITEMLIST[ItemName::COOKIE]});
|
|
Test("Enemy 1 gives 20 money.",
|
|
testEncounter->objs[0]->money==20);
|
|
Test("Enemy 2 has 2 battle moves.",
|
|
testEncounter->objs[1]->moveSet==std::vector<Battle::Move*>{
|
|
MOVELIST[BattleMoveName::TESTMOVE1],
|
|
MOVELIST[BattleMoveName::TESTMOVE2],
|
|
});
|
|
Test("Enemy 2 has a pizza as a drop",
|
|
testEncounter->objs[1]->inventory==std::vector<Item*>{ITEMLIST[ItemName::PIZZA]});
|
|
Test("Enemy 2 gives 0 money.",
|
|
testEncounter->objs[1]->money==0);
|
|
Test("Enemy 3 has 1 battle move.",
|
|
testEncounter->objs[2]->moveSet==std::vector<Battle::Move*>{
|
|
MOVELIST[BattleMoveName::TESTMOVE1],
|
|
});
|
|
Test("Enemy 3 has no items to drop",
|
|
testEncounter->objs[2]->inventory==std::vector<Item*>{});
|
|
Test("Enemy 3 gives 0 money.",
|
|
testEncounter->objs[2]->money==0);
|
|
Test("There are no battle properties",
|
|
BATTLE_PROPERTIES.size()==0);
|
|
SetupBattleProperties();
|
|
Test("Battle Properties populated",
|
|
BATTLE_PROPERTIES.size()>0);
|
|
Test("Test Move 1 exists in the map.",
|
|
MOVELIST.count(BattleMoveName::TESTMOVE1));
|
|
Test("Test Move 1 is undefined",
|
|
MOVELIST[BattleMoveName::TESTMOVE1]==nullptr);
|
|
MOVELIST[BattleMoveName::TESTMOVE1]=SetupMove(TESTMOVE1)"Test Move 1","An attack",baseDmg:30,randomDmg:5,range:6,channelTime:27,friendly:false};
|
|
Test("Verify Test Move 1's now set properly",
|
|
MOVELIST[BattleMoveName::TESTMOVE1]!=nullptr);
|
|
Test("Verify Test Move 1's Power Name shows up correctly",
|
|
MOVELIST[BattleMoveName::TESTMOVE1]->GetPowerName()=="Test Move 1");
|
|
MOVELIST[BattleMoveName::TESTMOVE1]->grade=GAMMA;
|
|
Test("Verify Test Move 1's Power Name shows up correctly with a grade",
|
|
MOVELIST[BattleMoveName::TESTMOVE1]->GetPowerName()=="Test Move 1 "+std::string(1,(char)GAMMA));
|
|
Test("Cookie is undefined",
|
|
ITEMLIST[ItemName::COOKIE]==nullptr);
|
|
SetupItemList();
|
|
Test("Cookie is defined",
|
|
ITEMLIST[ItemName::COOKIE]!=nullptr);
|
|
delete ITEMLIST[ItemName::COOKIE];
|
|
ITEMLIST.erase(ItemName::COOKIE);
|
|
ITEMLIST[ItemName::COOKIE]=SetupItem(COOKIE)"Cookie","A delightful little treat. Restores 40 HP.",2,{hpRecovery:40,consumable:Consumable::FRIENDLY,sellPrice:2});
|
|
Test("Cookie name is set properly",
|
|
ITEMLIST[ItemName::COOKIE]->name=="Cookie");
|
|
Test("Cookie description is set properly",
|
|
ITEMLIST[ItemName::COOKIE]->description=="A delightful little treat. Restores 40 HP.");
|
|
Test("Cookie drop chance is set properly",
|
|
ITEMLIST[ItemName::COOKIE]->dropChance==2);
|
|
delete ITEMLIST[ItemName::FREEZE_PACKET];
|
|
ITEMLIST.erase(ItemName::FREEZE_PACKET);
|
|
ITEMLIST[ItemName::FREEZE_PACKET]=SetupItem(FREEZE_PACKET)"Freeze Packet","Lets out some blistering cold weather.",256,{consumable:Consumable::ENEMY,sellPrice:36},MOVELIST[BattleMoveName::FREEZE_PACKET]);
|
|
Test("Freeze Packet name is set properly",
|
|
ITEMLIST[ItemName::FREEZE_PACKET]->name=="Freeze Packet");
|
|
Test("Freeze Packet description is set properly",
|
|
ITEMLIST[ItemName::FREEZE_PACKET]->description=="Lets out some blistering cold weather.");
|
|
Test("Freeze Packet drop chance is set properly",
|
|
ITEMLIST[ItemName::FREEZE_PACKET]->dropChance==256);
|
|
Test("No Maps are loaded",
|
|
MAPS.size()==0);
|
|
SetupMapList();
|
|
Test("Maps are loaded",
|
|
MAPS.size()!=0);
|
|
Test("No Cutscenes are loaded",
|
|
CUTSCENES.size()==0);
|
|
SetupCutscenes();
|
|
Test("Calling SetupCutscenes() loads up different cutscenes",
|
|
CUTSCENES.size()!=0);
|
|
Test("No active cutscene yet",
|
|
CurrentCutscene==nullptr);
|
|
StartCutscene(CUTSCENES[CutsceneName::TEST_CUTSCENE]);
|
|
Test("Starting a cutscene sets the current cutscene",
|
|
CurrentCutscene!=nullptr);
|
|
Test("Current Action should not be updated yet",
|
|
CurrentAction==ActionType::NONE);
|
|
OnUserUpdate(1/60.f);
|
|
Test("HandleCutscenes should get called in updateGame(), updating the current action",
|
|
CurrentAction!=ActionType::NONE);
|
|
int startFrame=frameCount;
|
|
TestWhile("Cutscene should complete entirely",CurrentAction!=ActionType::NONE) {
|
|
OnUserUpdate(1/60.f);
|
|
}
|
|
std::cout<<"Frame Count: "<<(frameCount-startFrame)<<std::endl;
|
|
Test("Cutscene is now finished",
|
|
CurrentAction==ActionType::NONE);
|
|
Test("Test Flag 1 is set",
|
|
GetGameFlag(Flag::TEST_FLAG1));
|
|
Test("Test Flag 2 is not set",
|
|
!GetGameFlag(Flag::TEST_FLAG2));
|
|
Test("Test Flag 1 (int cast) is still set",
|
|
GetGameFlag((int)Flag::TEST_FLAG1));
|
|
Test("Test Flag 2 (int cast) is still not set",
|
|
!GetGameFlag((int)Flag::TEST_FLAG2));
|
|
Test("Test Flag 1 (Flag cast) is still set",
|
|
GetGameFlag((Flag)1));
|
|
Test("Test Flag 2 (Flag cast) is still not set",
|
|
!GetGameFlag((Flag)2));
|
|
Test("Current Map is not set",
|
|
CURRENT_MAP==nullptr);
|
|
Test("Main Character flag is not set",
|
|
!GetGameFlag(Flag::HAS_MAIN));
|
|
SetGameFlag(Flag::HAS_MAIN,true);
|
|
Test("Main Character flag is set",
|
|
GetGameFlag(Flag::HAS_MAIN));
|
|
SetGameFlag(Flag::HAS_MAIN,false);
|
|
Test("Main Character flag is unset",
|
|
!GetGameFlag(Flag::HAS_MAIN));
|
|
SetGameFlag(Flag::HAS_MAIN,true);
|
|
Cutscene*FeatureTestCutscene=new Cutscene({
|
|
액션 Fade(),
|
|
액션 CreateObjects({
|
|
new Standard_Obj(PLAYER,"player",{64,64},ANIMATIONS["player.png"],{1,1},MAGENTA),
|
|
new Standard_Obj(PLAYER,"player",{136,136},ANIMATIONS["player.png"],{1,1},RED),
|
|
new Standard_Obj(PLAYER,"player",{96,96},ANIMATIONS["player.png"],{1,1},DARK_GREEN),
|
|
}),
|
|
액션 Fade(true),
|
|
액션 SetFlagWhenCutsceneEnds(Flag::TEST_FLAG3),
|
|
액션 SetFlag(Flag::TEST_FLAG2,true),
|
|
액션 PanCamera({128,128},BOTH,1),
|
|
액션 MoveCutsceneObjectAsync(1,{80,64},50),
|
|
액션 PanCameraAsync({64,0},BOTH),
|
|
액션 DialogBoxAsync(R"(Hello!
|
|
This is a test message that lets us trigger straight from a cutscene! Cool!)"),
|
|
액션 ModifyObject(0,ANIMATIONS["player.png"],{5,5},MAGENTA),
|
|
액션 MoveCutsceneObject(1,{320,64},1),
|
|
액션 DialogBox(R"(Hello!)"),
|
|
액션 class LoadMap(MAPS[MapName::TWOSON]),
|
|
액션 MovePlayerObjects({16,16}),});
|
|
Test("No cutscene is playing",
|
|
CurrentCutscene==nullptr);
|
|
StartCutscene(FeatureTestCutscene);
|
|
OnUserUpdate(1/60.f);
|
|
Test("Current action should be fading",
|
|
CurrentAction==ActionType::FADE);
|
|
double previous_fade_value=CUTSCENE_FADE_VALUE;
|
|
OnUserUpdate(1/60.f);
|
|
Test("Fading causes CUTSCENE_FADE_VALUE to increase",
|
|
CUTSCENE_FADE_VALUE>previous_fade_value);
|
|
Test("There should be no objects in the game",
|
|
OBJECTS.size()==0);
|
|
Test("Player should not be able to move during a cutscene",
|
|
!PlayerCanMove());
|
|
TestWhile("Fade out should finish",CurrentAction==ActionType::FADE) {
|
|
OnUserUpdate(1/60.f);
|
|
}
|
|
Test("When faded out, CUTSCENE_FADE_VALUE should be 255",
|
|
CUTSCENE_FADE_VALUE==255);
|
|
Test("Next cutscene action should be CreateObjects",
|
|
CurrentAction==ActionType::CREATE_OBJECTS);
|
|
Test("There should be 3 objects in the game",
|
|
OBJECTS.size()==3);
|
|
Test("Cutscene objects should have the temp flag set",
|
|
OBJECTS[0]->temp&&OBJECTS[1]->temp&&OBJECTS[2]->temp);
|
|
OnUserUpdate(1/60.f);
|
|
Test("Next cutscene action should be Fade back in",
|
|
CurrentAction==ActionType::FADE);
|
|
previous_fade_value=CUTSCENE_FADE_VALUE;
|
|
OnUserUpdate(1/60.f);
|
|
Test("Fading in causes CUTSCENE_FADE_VALUE to decrease",
|
|
CUTSCENE_FADE_VALUE<previous_fade_value);
|
|
TestWhile("Fade in should finish",CurrentAction==ActionType::FADE) {
|
|
OnUserUpdate(1/60.f);
|
|
}
|
|
Test("Next cutscene action should be setting a flag when the cutscene ends",
|
|
CurrentAction==ActionType::SET_FLAG_WHEN_CUTSCENE_ENDS);
|
|
Test("Ending cutscene flag is stored properly with proper flag and value",
|
|
CurrentCutscene->GetEndingCutsceneFlag()==Flag::TEST_FLAG3&&CurrentCutscene->GetEndingCutsceneVal());
|
|
OnUserUpdate(1/60.f);
|
|
Test("Next cutscene action should be setting a flag on the spot",
|
|
CurrentAction==ActionType::SET_FLAG);
|
|
Test("Test Flag 2 should now be set",
|
|
GetGameFlag(Flag::TEST_FLAG2));
|
|
Test("Test Flag 2 should still not be set",
|
|
!GetGameFlag(Flag::TEST_FLAG3));
|
|
cameraPos={0,0};
|
|
Test("Camera position should be {0,0}",
|
|
cameraPos.x==0&&cameraPos.y==0);
|
|
OnUserUpdate(1/60.f);
|
|
Test("Next cutscene action should be panning the camera",
|
|
CurrentAction==ActionType::PAN_CAMERA);
|
|
Test("Camera position should be moving towards {128,128}",
|
|
cameraPos.x>0&&cameraPos.y>0);
|
|
Test("Temporary cutscene object 1 is at position {136,136}",
|
|
CurrentCutscene->GetCutsceneObjects()[1]->GetPos().x==136&&CurrentCutscene->GetCutsceneObjects()[1]->GetPos().y==136);
|
|
TestWhile("Panning Camera should finish",CurrentAction==ActionType::PAN_CAMERA) {
|
|
OnUserUpdate(1/60.f);
|
|
}
|
|
Test("Camera position should be {128,128}",
|
|
cameraPos.x==128&&cameraPos.y==128);
|
|
Test("Next cutscene action is the async cutscene object movement",
|
|
CurrentAction==ActionType::MOVE_CUTSCENE_OBJ_ASYNC);
|
|
vd2d prevCutsceneObjPosition=CurrentCutscene->GetCutsceneObjects()[1]->GetPos();
|
|
OnUserUpdate(1/60.f);
|
|
Test("Cutscene object is moving towards {80,64}",
|
|
CurrentCutscene->GetCutsceneObjects()[1]->GetPos().x<prevCutsceneObjPosition.x&&CurrentCutscene->GetCutsceneObjects()[1]->GetPos().y<prevCutsceneObjPosition.y);
|
|
vd2d prevCameraPos=cameraPos;
|
|
Test("Due to async actions, next cutscene action should be Pan Camera Async",
|
|
CurrentAction==ActionType::PAN_CAMERA_ASYNC);
|
|
OnUserUpdate(1/60.f);
|
|
Test("Camera is moving towards {64,0}",
|
|
prevCameraPos.x>cameraPos.x&&prevCameraPos.y>cameraPos.y);
|
|
Test("Due to async actions, next cutscene action should be Dialog Box Async",
|
|
CurrentAction==ActionType::DIALOG_ASYNC);
|
|
Test("A message box should be on-screen",
|
|
messageBoxVisible);
|
|
GetAnyKeyPress(H);
|
|
GetAnyKeyPress(H);
|
|
Test("Pressing any key should close the message box",
|
|
!messageBoxVisible);
|
|
OnUserUpdate(1/60.f);
|
|
Test("Next cutscene action should be Modify Object 0",
|
|
CurrentAction==ActionType::MODIFY_OBJECT);
|
|
Test("Cutscene Object 0 is now size {5,5}",
|
|
CurrentCutscene->GetCutsceneObjects()[0]->GetScale().x==5&&CurrentCutscene->GetCutsceneObjects()[0]->GetScale().y==5);
|
|
OnUserUpdate(1/60.f);
|
|
Test("Next cutscene action should be Move Cutscene Object 1",
|
|
CurrentAction==ActionType::MOVE_CUTSCENE_OBJ);
|
|
prevCutsceneObjPosition=CurrentCutscene->GetCutsceneObjects()[1]->GetPos();
|
|
OnUserUpdate(1/60.f);
|
|
Test("Cutscene Object 1 is moving towards position {320,64}",
|
|
CurrentCutscene->GetCutsceneObjects()[1]->GetPos().x>prevCutsceneObjPosition.x&&CurrentCutscene->GetCutsceneObjects()[1]->GetPos().y==prevCutsceneObjPosition.y);
|
|
TestWhile("Move Cutscene Object should finish",CurrentAction==ActionType::MOVE_CUTSCENE_OBJ) {
|
|
OnUserUpdate(1/60.f);
|
|
}
|
|
Test("Cutscene Object 1 should be at position {320,64}",
|
|
CurrentCutscene->GetCutsceneObjects()[1]->GetPos().x==320&&CurrentCutscene->GetCutsceneObjects()[1]->GetPos().y==64);
|
|
Test("Next cutscene action is Dialog Box",
|
|
CurrentAction==ActionType::DIALOG);
|
|
Test("Dialog box should be visible",
|
|
messageBoxVisible);
|
|
GetAnyKeyPress(S);
|
|
Test("Pressing a key should show the entire message",
|
|
messageBoxText=="Hello!");
|
|
GetAnyKeyPress(S);
|
|
Test("Pressing a key should close the message box",
|
|
!messageBoxVisible);
|
|
int prevDestructionCount=OBJECT_DESTRUCTION_COUNT;
|
|
OnUserUpdate(1/60.f);
|
|
Test("Next cutscene action should be loading a map",
|
|
CurrentAction==ActionType::LOAD_MAP);
|
|
Test("Current Map should now be TWOSON",
|
|
CURRENT_MAP==MAPS[MapName::TWOSON]);
|
|
Test("All temporary objects should now be destroyed",
|
|
OBJECT_DESTRUCTION_COUNT-3==prevDestructionCount);
|
|
OnUserUpdate(1/60.f);
|
|
Test("Next action should be moving player objects",
|
|
CurrentAction==ActionType::MOVE_PLAYER_OBJS);
|
|
Test("All player objects should now be at position {16,16}",
|
|
PARTY_MEMBER_OBJ[0]->GetPos().x==16&&PARTY_MEMBER_OBJ[0]->GetPos().y==16);
|
|
Test("Next cutscene action should be cleanup",
|
|
CurrentCutscene->CurrentAction()==ActionType::CLEANUP);
|
|
OnUserUpdate(1/60.f);
|
|
Test("All cutscene and action variables should be cleaned up",
|
|
CurrentCutscene==nullptr&&
|
|
CurrentAction==ActionType::NONE);
|
|
TestKey testkeys[] = {key::UP,key::DOWN,key::LEFT,key::RIGHT,key::W,key::A,key::S,key::D,key::NP8,key::NP4,key::NP5,key::NP6,key::NP2,key::BACK,key::ESCAPE,key::X,key::CTRL,key::DEL,key::END,key::NP_DECIMAL,key::NP_SUB,key::MINUS,key::PAUSE,key::TAB,key::CAPS_LOCK};
|
|
for (TestKey k : testkeys) {
|
|
PressTestKey(k.k);
|
|
Test(k.keyName+" key is pressed",
|
|
GetKeyPressed(*this,k));
|
|
OnUserUpdate(1/60.f);
|
|
Test(k.keyName+" key is no longer pressed",
|
|
!GetKeyPressed(*this,k));
|
|
Test(k.keyName+" key is held down",
|
|
GetKeyHeld(*this,k));
|
|
OnUserUpdate(1/60.f);
|
|
Test(k.keyName+" key is still held down",
|
|
GetKeyHeld(*this,k));
|
|
for (int i=0;i<50;i++) {
|
|
OnUserUpdate(1/60.f);
|
|
}
|
|
Test(k.keyName+" key is still held down after multiple updates",
|
|
GetKeyHeld(*this,k));
|
|
ReleaseTestKey(k.k);
|
|
Test(k.keyName+" key is no longer held down",
|
|
!GetKeyHeld(*this,k));
|
|
Test(k.keyName+" key is released",
|
|
GetKeyReleased(*this,k));
|
|
OnUserUpdate(1/60.f);
|
|
Test(k.keyName+" key is no longer released",
|
|
!GetKeyReleased(*this,k));
|
|
}
|
|
Test("We are still in the TEST_GAME state",
|
|
GAME_STATE==GameState::TEST_GAME);
|
|
TestKey testRepeatKeys[] = {key::UP,key::DOWN,key::LEFT,key::RIGHT};
|
|
for (TestKey k : testRepeatKeys) {
|
|
frameCount=0;
|
|
PressTestKey(k.k);
|
|
for (int i=0;i<23;i++) {
|
|
updateGame();
|
|
Test(k.keyName+" key is not considered pressed",
|
|
!GetKeyPressed(*this,k));
|
|
keyUpdates();
|
|
}
|
|
int attemptCount=1;
|
|
updateGame();
|
|
Test(k.keyName+" key is considered pressed again (Attempt "+std::to_string(attemptCount++)+")",
|
|
GetKeyPressed(*this,k));
|
|
keyUpdates();
|
|
for (int j=0;j<2;j++) {
|
|
for (int i=0;i<3;i++) {
|
|
updateGame();
|
|
Test(k.keyName+" key is not considered pressed",
|
|
!GetKeyPressed(*this,k));
|
|
keyUpdates();
|
|
}
|
|
updateGame();
|
|
Test(k.keyName+" key is considered pressed again (Attempt "+std::to_string(attemptCount++)+")",
|
|
GetKeyPressed(*this,k));
|
|
keyUpdates();
|
|
}
|
|
ResetTestKeys();
|
|
SetDrawTarget(nullptr);
|
|
GetDrawTarget()->GetData()[0].a=4;
|
|
}
|
|
LoadMap(MAPS[MapName::TEST]);
|
|
GAME_STATE=GameState::GAME_WORLD;
|
|
Test("Player can move when there is no cutscene and the game is in a normal state",
|
|
PlayerCanMove());
|
|
GAME_STATE=GameState::TEST_GAME;
|
|
Test("Player cannot move during testing",
|
|
!PlayerCanMove());
|
|
SetGameFlag(Flag::INTRO_COMPLETED,true);
|
|
GAME_STATE=GameState::GAME_WORLD;
|
|
vd2d prevPlayerPos = PARTY_MEMBER_OBJ[0]->GetPos();
|
|
CenterCameraOnPlayer();
|
|
PressTestKeyAndRun(RIGHT);
|
|
Test("Player has moved to the right",
|
|
PARTY_MEMBER_OBJ[0]->GetPos().x>prevPlayerPos.x&&PARTY_MEMBER_OBJ[0]->GetPos().y==prevPlayerPos.y);
|
|
prevPlayerPos = PARTY_MEMBER_OBJ[0]->GetPos();
|
|
PressTestKeyAndRun(UP);
|
|
Test("Player has moved up-right",
|
|
PARTY_MEMBER_OBJ[0]->GetPos().x>prevPlayerPos.x&&PARTY_MEMBER_OBJ[0]->GetPos().y<prevPlayerPos.y);
|
|
ReleaseTestKey(UP);
|
|
prevPlayerPos = PARTY_MEMBER_OBJ[0]->GetPos();
|
|
PressTestKeyAndRun(DOWN);
|
|
Test("Player has moved down-right",
|
|
PARTY_MEMBER_OBJ[0]->GetPos().x>prevPlayerPos.x&&PARTY_MEMBER_OBJ[0]->GetPos().y>prevPlayerPos.y);
|
|
ResetTestKeys();
|
|
prevPlayerPos = PARTY_MEMBER_OBJ[0]->GetPos();
|
|
PressTestKeyAndRun(LEFT);
|
|
Test("Player has moved to the left",
|
|
PARTY_MEMBER_OBJ[0]->GetPos().x<prevPlayerPos.x&&PARTY_MEMBER_OBJ[0]->GetPos().y==prevPlayerPos.y);
|
|
prevPlayerPos = PARTY_MEMBER_OBJ[0]->GetPos();
|
|
PressTestKeyAndRun(UP);
|
|
Test("Player has moved up-left",
|
|
PARTY_MEMBER_OBJ[0]->GetPos().x<prevPlayerPos.x&&PARTY_MEMBER_OBJ[0]->GetPos().y<prevPlayerPos.y);
|
|
ReleaseTestKey(UP);
|
|
prevPlayerPos = PARTY_MEMBER_OBJ[0]->GetPos();
|
|
PressTestKeyAndRun(DOWN);
|
|
Test("Player has moved down-left",
|
|
PARTY_MEMBER_OBJ[0]->GetPos().x<prevPlayerPos.x&&PARTY_MEMBER_OBJ[0]->GetPos().y>prevPlayerPos.y);
|
|
ReleaseTestKey(LEFT);
|
|
prevPlayerPos = PARTY_MEMBER_OBJ[0]->GetPos();
|
|
OnUserUpdate(1/60.f);
|
|
Test("Player has moved down",
|
|
PARTY_MEMBER_OBJ[0]->GetPos().x==prevPlayerPos.x&&PARTY_MEMBER_OBJ[0]->GetPos().y>prevPlayerPos.y);
|
|
ReleaseTestKey(DOWN);
|
|
prevPlayerPos = PARTY_MEMBER_OBJ[0]->GetPos();
|
|
PressTestKeyAndRun(UP);
|
|
Test("Player has moved up",
|
|
PARTY_MEMBER_OBJ[0]->GetPos().x==prevPlayerPos.x&&PARTY_MEMBER_OBJ[0]->GetPos().y<prevPlayerPos.y);
|
|
ResetTestKeys();
|
|
PARTY_MEMBER_OBJ[0]->SetPos({32-PARTY_MEMBER_OBJ[0]->originPoint.x,16-PARTY_MEMBER_OBJ[0]->originPoint.y});
|
|
Test("Player is now centered at 32,16",
|
|
PARTY_MEMBER_OBJ[0]->GetPosWithOrigin().x==32&&PARTY_MEMBER_OBJ[0]->GetPosWithOrigin().y==16);
|
|
CenterCameraOnPlayer();
|
|
for (int i=0;i<10;i++) {
|
|
PressTestKeyAndRun(LEFT);
|
|
ReleaseTestKey(LEFT);
|
|
}
|
|
Test("Player does not move due to tile collision",
|
|
PARTY_MEMBER_OBJ[0]->GetPosWithOrigin().x==32&&PARTY_MEMBER_OBJ[0]->GetPosWithOrigin().y==16);
|
|
SetupGameDrawing();
|
|
SetDrawTarget(layer::COLLISION);
|
|
bool isAllMagenta=true;
|
|
for (int x=0;x<WIDTH;x++) {
|
|
for (int y=0;y<HEIGHT;y++) {
|
|
if (GetDrawTarget()->GetData()[y*WIDTH+x]!=MAGENTA) {
|
|
isAllMagenta=false;
|
|
goto endOfScreenCheck;
|
|
}
|
|
}
|
|
}
|
|
endOfScreenCheck:
|
|
Test("Entire screen should be wiped to magenta before drawing anything",
|
|
isAllMagenta);
|
|
std::vector<std::vector<TILE>> TEMPMAP;
|
|
std::vector<std::vector<TILE>> TEMPMAP2;
|
|
std::vector<std::vector<TILE>> TEMPMAP3;
|
|
std::vector<std::vector<TILE>> TEMPMAP4;
|
|
std::vector<std::vector<TILE>> TEMPMAP5;
|
|
std::vector<std::vector<TILE>> TEMPMAP6;
|
|
CopyMapContents(MAP,TEMPMAP);
|
|
CopyMapContents(MAP2,TEMPMAP2);
|
|
CopyMapContents(MAP3,TEMPMAP3);
|
|
CopyMapContents(MAP4,TEMPMAP4);
|
|
CopyMapContents(MAP5,TEMPMAP5);
|
|
CopyMapContents(MAP6,TEMPMAP6);
|
|
Test("Entire map should be copied over properly for testing",
|
|
ValidateEntireMap(MAP,TEMPMAP)&&
|
|
ValidateEntireMap(MAP2,TEMPMAP2)&&
|
|
ValidateEntireMap(MAP3,TEMPMAP3)&&
|
|
ValidateEntireMap(MAP4,TEMPMAP4)&&
|
|
ValidateEntireMap(MAP5,TEMPMAP5)&&
|
|
ValidateEntireMap(MAP6,TEMPMAP6));
|
|
TILE prevTile1=TEMPMAP[6][4];
|
|
TILE prevTile2=TEMPMAP2[2][0];
|
|
TILE prevTile3=TEMPMAP3[7][2];
|
|
TILE prevTile4=TEMPMAP4[1][14];
|
|
TILE prevTile5=TEMPMAP5[7][2];
|
|
TILE prevTile6=TEMPMAP6[9][6];
|
|
TEMPMAP[6][4]=TILE(9,4,0);
|
|
TEMPMAP2[2][0]=TILE(4,7,0);
|
|
TEMPMAP3[7][2]=TILE(4,9,0);
|
|
TEMPMAP4[1][14]=TILE(1,2,-1);
|
|
TEMPMAP5[7][2]=TILE(6,8,0);
|
|
TEMPMAP6[9][6]=TILE(4,17,0);
|
|
Test("After modifications, some parts of the map should no longer be equal",
|
|
!ValidateEntireMap(MAP,TEMPMAP)&&
|
|
!ValidateEntireMap(MAP2,TEMPMAP2)&&
|
|
!ValidateEntireMap(MAP3,TEMPMAP3)&&
|
|
!ValidateEntireMap(MAP4,TEMPMAP4)&&
|
|
!ValidateEntireMap(MAP5,TEMPMAP5)&&
|
|
!ValidateEntireMap(MAP6,TEMPMAP6));
|
|
TEMPMAP[6][4]=prevTile1;
|
|
TEMPMAP2[2][0]=prevTile2;
|
|
TEMPMAP3[7][2]=prevTile3;
|
|
TEMPMAP4[1][14]=prevTile4;
|
|
TEMPMAP5[7][2]=prevTile5;
|
|
TEMPMAP6[9][6]=prevTile6;
|
|
LoadMap(MAPS[MapName::TEST]);
|
|
Test("Upon reloading a map every tile should match up once again",
|
|
ValidateEntireMap(MAP,TEMPMAP)&&
|
|
ValidateEntireMap(MAP2,TEMPMAP2)&&
|
|
ValidateEntireMap(MAP3,TEMPMAP3)&&
|
|
ValidateEntireMap(MAP4,TEMPMAP4)&&
|
|
ValidateEntireMap(MAP5,TEMPMAP5)&&
|
|
ValidateEntireMap(MAP6,TEMPMAP6));
|
|
return true;
|
|
}
|
|
|
|
bool SeasonI::OnUserUpdate(float fElapsedTime)
|
|
{
|
|
updateGame();
|
|
keyUpdates();
|
|
SetupGameDrawing();
|
|
drawGame();
|
|
return true;
|
|
}
|
|
|
|
int main() {
|
|
SeasonI demo;
|
|
if (demo.Construct(WIDTH, HEIGHT, 4, 4))
|
|
demo.Start();
|
|
|
|
return 0;
|
|
} |