Implement missing SetAbility4 function stub. Add HasBuff function to both the Player and Monster classes. Implemented Giant Crab AI. 219/219 tests passing. Release Build 11710.

master
sigonasr2 2 months ago
parent 3684e0f211
commit 2f441f76b7
  1. 36
      Adventures in Lestoria Tests/BuffTests.cpp
  2. 4
      Adventures in Lestoria/Adventures in Lestoria.vcxproj
  3. 3
      Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters
  4. 84
      Adventures in Lestoria/GiantCrab.cpp
  5. 27
      Adventures in Lestoria/Monster.cpp
  6. 10
      Adventures in Lestoria/Monster.h
  7. 1
      Adventures in Lestoria/MonsterAttribute.h
  8. 13
      Adventures in Lestoria/Player.cpp
  9. 2
      Adventures in Lestoria/Player.h
  10. 1
      Adventures in Lestoria/RUN_STRATEGY.cpp
  11. 2
      Adventures in Lestoria/Version.h
  12. 14
      Adventures in Lestoria/assets/Campaigns/3_1.tmx
  13. 11
      Adventures in Lestoria/assets/config/MonsterStrategies.txt
  14. 2
      Adventures in Lestoria/assets/config/Monsters.txt
  15. BIN
      x64/Release/Adventures in Lestoria.exe

@ -125,5 +125,41 @@ namespace BuffTests
Game::Update(3.f);
Assert::AreEqual(95,game->GetPlayer()->GetHealth(),L"Player should have taken 5 health from the expired callback provided.");
}
TEST_METHOD(MonsterHasBuffFunctionTest){
Monster&m{game->SpawnMonster({},MONSTER_DATA.at("TestName"))};
Game::Update(0.f);
Assert::AreEqual(false,m.HasBuff(BuffType::SPEEDBOOST),L"Monster should not have a speedboost buff before being given one.");
m.AddBuff(BuffType::ADRENALINE_RUSH,1.f,1.f);
Assert::AreEqual(false,m.HasBuff(BuffType::SPEEDBOOST),L"Monster should not have a speedboost buff when given an unrelated buff.");
m.AddBuff(BuffType::SPEEDBOOST,1.f,1.f);
Assert::AreEqual(true,m.HasBuff(BuffType::SPEEDBOOST),L"Monster should now have a speedboost buff.");
m.AddBuff(BuffType::SPEEDBOOST,2.f,1.f);
Assert::AreEqual(true,m.HasBuff(BuffType::SPEEDBOOST),L"Monster should still report having a speedboost buff.");
Game::Update(0.f);
Game::Update(1.f);
Assert::AreEqual(true,m.HasBuff(BuffType::SPEEDBOOST),L"Monster should still have one speedboost buff.");
Game::Update(1.f);
Assert::AreEqual(false,m.HasBuff(BuffType::SPEEDBOOST),L"Monster should no longer have a speedboost buff.");
m.AddBuff(BuffType::SPEEDBOOST,1.f,1.f);
m.RemoveBuff(BuffType::SPEEDBOOST);
Assert::AreEqual(false,m.HasBuff(BuffType::SPEEDBOOST),L"Monster should no longer have a speedboost buff.");
}
TEST_METHOD(PlayerHasBuffFunctionTest){
Assert::AreEqual(false,game->GetPlayer()->HasBuff(BuffType::SPEEDBOOST),L"Player should not have a speedboost buff before being given one.");
game->GetPlayer()->AddBuff(BuffType::ADRENALINE_RUSH,1.f,1.f);
Assert::AreEqual(false,game->GetPlayer()->HasBuff(BuffType::SPEEDBOOST),L"Player should not have a speedboost buff when given an unrelated buff.");
game->GetPlayer()->AddBuff(BuffType::SPEEDBOOST,1.f,1.f);
Assert::AreEqual(true,game->GetPlayer()->HasBuff(BuffType::SPEEDBOOST),L"Player should now have a speedboost buff.");
game->GetPlayer()->AddBuff(BuffType::SPEEDBOOST,2.f,1.f);
Assert::AreEqual(true,game->GetPlayer()->HasBuff(BuffType::SPEEDBOOST),L"Player should still report having a speedboost buff.");
Game::Update(0.f);
Game::Update(1.f);
Assert::AreEqual(true,game->GetPlayer()->HasBuff(BuffType::SPEEDBOOST),L"Player should still have one speedboost buff.");
Game::Update(1.f);
Assert::AreEqual(false,game->GetPlayer()->HasBuff(BuffType::SPEEDBOOST),L"Player should no longer have a speedboost buff.");
game->GetPlayer()->AddBuff(BuffType::SPEEDBOOST,1.f,1.f);
game->GetPlayer()->RemoveBuff(BuffType::SPEEDBOOST);
Assert::AreEqual(false,game->GetPlayer()->HasBuff(BuffType::SPEEDBOOST),L"Player should no longer have a speedboost buff.");
}
};
}

@ -835,6 +835,10 @@
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="GiantCrab.cpp">
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="IBullet.cpp" />
<ClCompile Include="BuyItemWindow.cpp">
<SubType>

@ -1250,6 +1250,9 @@
<ClCompile Include="Seagull.cpp">
<Filter>Source Files\Monster Strategies</Filter>
</ClCompile>
<ClCompile Include="GiantCrab.cpp">
<Filter>Source Files\Monster Strategies</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="cpp.hint" />

@ -0,0 +1,84 @@
#pragma region License
/*
License (OLC-3)
~~~~~~~~~~~~~~~
Copyright 2024 Joshua Sigona <sigonasr2@gmail.com>
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions or derivations of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions or derivative works in binary form must reproduce the above
copyright notice. This list of conditions and the following disclaimer must be
reproduced in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may
be used to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
Portions of this software are copyright © 2024 The FreeType
Project (www.freetype.org). Please see LICENSE_FT.txt for more information.
All rights reserved.
*/
#pragma endregion
#include "MonsterStrategyHelpers.h"
#include "util.h"
#include "AdventuresInLestoria.h"
#include "SoundEffect.h"
#include "BulletTypes.h"
using A=Attribute;
INCLUDE_game
void Monster::STRATEGY::GIANT_CRAB(Monster&m,float fElapsedTime,std::string strategy){
enum PhaseName{
PREPARE_CHARGE,
CHARGE,
};
switch(PHASE()){
case PREPARE_CHARGE:{
m.F(A::CASTING_TIMER)-=fElapsedTime;
if(m.F(A::CASTING_TIMER)<=0.f){
m.AddBuff(BuffType::SPEEDBOOST,ConfigFloat("Charge Time"),0.f);
m.F(A::SPEED_RAMPUP_TIMER)=0.1f;
SETPHASE(CHARGE);
}
}break;
case CHARGE:{
m.F(A::CHASE_TIMER)+=fElapsedTime;
m.F(A::SPEED_RAMPUP_TIMER)-=fElapsedTime;
if(m.F(A::CHASE_TIMER)>=ConfigFloat("Charge Time")||m.ReachedTargetPos()){
m.F(A::CHASE_TIMER)=0.f;
m.target=geom2d::line<float>(m.GetPos(),game->GetPlayer()->GetPos()).rpoint(util::distance(m.GetPos(),game->GetPlayer()->GetPos())+ConfigPixels("Charge Extend Distance"));
m.RemoveBuff(BuffType::SPEEDBOOST);
m.F(A::CASTING_TIMER)=ConfigFloat("Charge Wait Time");
SETPHASE(PREPARE_CHARGE);
}
if(m.F(A::SPEED_RAMPUP_TIMER)<=0.f){
m.F(A::SPEED_RAMPUP_TIMER)=0.1f;
if(m.HasBuff(BuffType::SPEEDBOOST)){
const float buffIntensity{m.GetBuffs(BuffType::SPEEDBOOST)[0].intensity};
m.EditBuff(BuffType::SPEEDBOOST,0).intensity=std::min(buffIntensity+ConfigFloat("Movespeed Rampup Final Amount")/100.f/(ConfigFloat("Movespeed Rampup Time")/0.1f),ConfigFloat("Movespeed Rampup Final Amount")/100.f);
}
}
RUN_TOWARDS(m,fElapsedTime,"Run Towards");
}break;
}
}

@ -92,23 +92,23 @@ const int Monster::GetHealth()const{
const int Monster::GetMaxHealth()const{
return int(GetModdedStatBonuses("Health"));
}
int Monster::GetAttack(){
int Monster::GetAttack()const{
return int(GetModdedStatBonuses("Attack"));
}
float Monster::GetMoveSpdMult(){
float moveSpdPct=stats.A("Move Spd %")/100.f;
float Monster::GetMoveSpdMult()const{
float moveSpdPct=stats.A_Read("Move Spd %")/100.f;
float mod_moveSpd=moveSpdPct;
for(Buff&b:GetBuffs(SLOWDOWN)){
for(const Buff&b:GetBuffs(SLOWDOWN)){
mod_moveSpd-=moveSpdPct*b.intensity;
}
for(Buff&b:GetBuffs(SELF_INFLICTED_SLOWDOWN)){
for(const Buff&b:GetBuffs(SELF_INFLICTED_SLOWDOWN)){
mod_moveSpd-=moveSpdPct*b.intensity;
}
for(Buff&b:GetBuffs(LOCKON_SPEEDBOOST)){
for(const Buff&b:GetBuffs(LOCKON_SPEEDBOOST)){
mod_moveSpd+=moveSpdPct*b.intensity;
}
for(Buff&b:GetBuffs(SPEEDBOOST)){
for(const Buff&b:GetBuffs(SPEEDBOOST)){
mod_moveSpd+=moveSpdPct*b.intensity;
}
return mod_moveSpd;
@ -460,7 +460,7 @@ void Monster::Draw()const{
if(markedForDeletion)return;
Pixel blendCol{WHITE};
std::optional<std::reference_wrapper<Buff>>glowPurpleBuff;
std::optional<Buff>glowPurpleBuff;
if(GetBuffs(BuffType::GLOW_PURPLE).size()>0)glowPurpleBuff=GetBuffs(BuffType::GLOW_PURPLE)[0];
@ -473,7 +473,7 @@ void Monster::Draw()const{
else if(HasBuff(BuffType::CURSE_OF_DEATH))blendCol=GetBuffBlendCol(BuffType::CURSE_OF_DEATH,1.4f,{255,0,0});
else if(HasBuff(BuffType::COLOR_MOD))blendCol=GetBuffBlendCol(BuffType::COLOR_MOD,1.4f,PixelRaw(GetBuffs(BuffType::COLOR_MOD)[0].intensity),1.f);
else if(HasBuff(BuffType::SLOWDOWN))blendCol=GetBuffBlendCol(BuffType::SLOWDOWN,1.4f,{255,255,128},0.5f);
else if(glowPurpleBuff.has_value())blendCol=Pixel{uint8_t(255*abs(sin(1.4*glowPurpleBuff.value().get().duration))),uint8_t(255*abs(sin(1.4*glowPurpleBuff.value().get().duration))),uint8_t(128+127*abs(sin(1.4*glowPurpleBuff.value().get().duration)))};
else if(glowPurpleBuff.has_value())blendCol=Pixel{uint8_t(255*abs(sin(1.4*glowPurpleBuff.value().duration))),uint8_t(255*abs(sin(1.4*glowPurpleBuff.value().duration))),uint8_t(128+127*abs(sin(1.4*glowPurpleBuff.value().duration)))};
const vf2d hitTimerOffset=vf2d{sin(20*PI*lastHitTimer+randomFrameOffset),0.f}*2.f*GetSizeMult();
const vf2d zOffset=-vf2d{0,GetZ()};
@ -961,13 +961,13 @@ std::vector<std::reference_wrapper<Buff>>Monster::EditBuffs(BuffType buff){
return filteredBuffs;
}
std::vector<Buff>Monster::GetBuffs(BuffType buff)const{
const std::vector<Buff>Monster::GetBuffs(BuffType buff)const{
std::vector<Buff>filteredBuffs;
std::copy_if(buffList.begin(),buffList.end(),std::back_inserter(filteredBuffs),[&buff](const Buff&b){return b.type==buff;});
return filteredBuffs;
}
std::vector<Buff>Monster::GetBuffs(std::vector<BuffType>buffs)const{
const std::vector<Buff>Monster::GetBuffs(std::vector<BuffType>buffs)const{
std::vector<Buff>filteredBuffs;
std::copy_if(buffList.begin(),buffList.end(),std::back_inserter(filteredBuffs),[&buffs](const Buff&b){return std::find(buffs.begin(),buffs.end(),b.type)!=buffs.end();});
return filteredBuffs;
@ -1252,7 +1252,7 @@ const float Monster::GetDamageReductionFromBuffs()const{
const float Monster::GetCollisionDamage()const{
float collisionDmg=0.f;
for(Buff&b:GetBuffs(FIXED_COLLISION_DMG)){
for(const Buff&b:GetBuffs(FIXED_COLLISION_DMG)){
collisionDmg+=b.intensity;
}
if(collisionDmg>0)return collisionDmg;
@ -1661,4 +1661,7 @@ void Monster::SetPhase(const std::string&strategyName,int phase){
const int Monster::GetPhase(const std::string&strategyName){
if(!phase.contains(strategyName))phase[strategyName]=0;
return this->phase[strategyName];
}
const bool Monster::HasBuff(BuffType buff)const{
return std::find_if(buffList.begin(),buffList.end(),[type=buff](const Buff&buff){return buff.type==type;})!=buffList.end();
}

@ -86,9 +86,9 @@ public:
const vf2d&GetPos()const;
const int GetHealth()const;
const int GetMaxHealth()const;
int GetAttack();
int GetAttack()const;
//This function returns the multiplier for the movespd from the base spd. So 100 movespd is 1.0.
float GetMoveSpdMult();
float GetMoveSpdMult()const;
//Obtains the size multiplier (from 0.f-1.f).
float GetSizeMult()const;
Animate2D::Frame GetFrame()const;
@ -149,8 +149,9 @@ public:
void AddBuff(BuffRestorationType type,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks,Buff::MonsterBuffExpireCallbackFunction expireCallback);
void AddBuff(BuffType type,BuffRestorationType restorationType,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks);
void AddBuff(BuffType type,BuffRestorationType restorationType,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks,Buff::MonsterBuffExpireCallbackFunction expireCallback);
std::vector<Buff>GetBuffs(BuffType buff)const;
std::vector<Buff>GetBuffs(std::vector<BuffType>buffs)const;
const bool HasBuff(BuffType buff)const;
const std::vector<Buff>GetBuffs(BuffType buff)const;
const std::vector<Buff>GetBuffs(std::vector<BuffType>buffs)const;
//Removes all buffs of a given type.
void RemoveBuff(BuffType type);
State::State GetState();
@ -370,6 +371,7 @@ private:
static void PIRATE_BUCCANEER(Monster&m,float fElapsedTime,std::string strategy);
static void PARROT(Monster&m,float fElapsedTime,std::string strategy);
static void CRAB(Monster&m,float fElapsedTime,std::string strategy);
static void GIANT_CRAB(Monster&m,float fElapsedTime,std::string strategy);
};
bool bumpedIntoTerrain=false; //Gets set to true before a strategy executes if the monster runs into some terrain on this frame.
bool attackedByPlayer=false; //Gets set to true before a strategy executes if the monster has been attacked by the player.

@ -149,4 +149,5 @@ enum class Attribute{
PARROT_FLY_TIMER,
MID_PHASE,
RUM_DRINK_COUNT,
SPEED_RAMPUP_TIMER,
};

@ -2290,7 +2290,15 @@ void Player::SetTestScreenAimingLocation(vf2d forcedAimingLoc){
testAimingLoc=forcedAimingLoc;
}
void Player::SetAbility4(const Ability&ability){
switch(GetClass()){
case WARRIOR:{Warrior::ability4=ability;}break;
case RANGER:{Ranger::ability4=ability;}break;
case WIZARD:{Wizard::ability4=ability;}break;
case THIEF:{Thief::ability4=ability;}break;
case TRAPPER:{Trapper::ability4=ability;}break;
case WITCH:{Witch::ability4=ability;}break;
default:{ERR(std::format("WARNING! Class {} is invalid! THIS SHOULD NOT BE HAPPENING!",int(GetClass())));}
}
}
void Player::RemoveMoney(const uint32_t moneyCost){
@ -2300,4 +2308,7 @@ void Player::RemoveMoney(const uint32_t moneyCost){
void Player::AddMoney(const uint32_t moneyCost){
SetMoney(GetMoney()+moneyCost);
}
const bool Player::HasBuff(BuffType buff)const{
return std::find_if(buffList.begin(),buffList.end(),[type=buff](const Buff&buff){return buff.type==type;})!=buffList.end();
}

@ -184,7 +184,7 @@ public:
void AddBuff(BuffRestorationType type,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks,Buff::PlayerBuffExpireCallbackFunction expireCallbackFunc);
void AddBuff(BuffType type,BuffRestorationType restorationType,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks);
void AddBuff(BuffType type,BuffRestorationType restorationType,BuffOverTimeType::BuffOverTimeType overTimeType,float duration,float intensity,float timeBetweenTicks,Buff::PlayerBuffExpireCallbackFunction expireCallbackFunc);
const bool HasBuff(BuffType buff)const;
const std::vector<Buff>GetBuffs(BuffType buff)const;
const std::vector<Buff>GetStatBuffs(const std::vector<std::string>&attr)const;

@ -74,6 +74,7 @@ void Monster::InitializeStrategies(){
STRATEGY_DATA.insert("Seagull",Monster::STRATEGY::SEAGULL);
STRATEGY_DATA.insert("Sandworm",Monster::STRATEGY::SANDWORM);
STRATEGY_DATA.insert("Parrot",Monster::STRATEGY::PARROT);
STRATEGY_DATA.insert("Giant Crab",Monster::STRATEGY::GIANT_CRAB);
STRATEGY_DATA.SetInitialized();
}

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 1
#define VERSION_MINOR 3
#define VERSION_PATCH 0
#define VERSION_BUILD 11683
#define VERSION_BUILD 11710
#define stringify(a) stringify_(a)
#define stringify_(a) #a

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.10.2" class="Map" orientation="orthogonal" renderorder="right-down" width="335" height="165" tilewidth="24" tileheight="24" infinite="0" nextlayerid="8" nextobjectid="100">
<map version="1.10" tiledversion="1.10.2" class="Map" orientation="orthogonal" renderorder="right-down" width="335" height="165" tilewidth="24" tileheight="24" infinite="0" nextlayerid="8" nextobjectid="102">
<properties>
<property name="Background Music" propertytype="BGM" value="beach"/>
<property name="Level Type" type="int" propertytype="LevelType" value="0"/>
@ -1243,17 +1243,7 @@
</properties>
<point/>
</object>
<object id="97" template="../maps/Monsters/Crab.tx" x="576" y="1458">
<properties>
<property name="spawner" type="object" value="8"/>
</properties>
</object>
<object id="98" template="../maps/Monsters/Crab.tx" x="588" y="1422">
<properties>
<property name="spawner" type="object" value="8"/>
</properties>
</object>
<object id="99" template="../maps/Monsters/Crab.tx" x="588" y="1398">
<object id="101" template="../maps/Monsters/Giant Crab.tx" x="594" y="1590">
<properties>
<property name="spawner" type="object" value="8"/>
</properties>

@ -1173,4 +1173,15 @@ MonsterStrategy
Charge Wait Time = 0.3s
Charge Max Time = 3s
}
Giant Crab
{
Charge Time = 5s
Charge Wait Time = 1s
Charge Extend Distance = 600
Movespeed Rampup Time = 2s
# Amount of movespeed gain by end of rampup time.
Movespeed Rampup Final Amount = 100%
}
}

@ -1561,7 +1561,7 @@ Monsters
Collision Radius = 10
Strategy = Crab
Strategy = Giant Crab
#Size of each animation frame
SheetFrameSize = 48,48

Loading…
Cancel
Save