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.
SeasonI/test/test.cpp

393 lines
16 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 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;
int testCount=0;
int MAX_ITERATIONS=1000;
int iterations=0;
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(){
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);
updateGame();
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) {
updateGame();
}
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},5),
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);
updateGame();
Test("Current action should be fading",
CurrentAction==ActionType::FADE);
double previous_fade_value=CUTSCENE_FADE_VALUE;
updateGame();
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);
TestWhile("Fade out should finish",CurrentAction==ActionType::FADE) {
updateGame();
}
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);
updateGame();
Test("Next cutscene action should be Fade back in",
CurrentAction==ActionType::FADE);
previous_fade_value=CUTSCENE_FADE_VALUE;
updateGame();
Test("Fading in causes CUTSCENE_FADE_VALUE to decrease",
CUTSCENE_FADE_VALUE<previous_fade_value);
TestWhile("Fade in should finish",CurrentAction==ActionType::FADE) {
updateGame();
}
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());
updateGame();
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);
updateGame();
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) {
updateGame();
}
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();
updateGame();
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);
updateGame();
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);
return true;
}
bool SeasonI::OnUserUpdate(float fElapsedTime)
{
return true;
}
int main() {
SeasonI demo;
if (demo.Construct(WIDTH, HEIGHT, 4, 4))
demo.Start();
return 0;
}