Update Stone Pillar graphic. Update Stone Pillar Monster data. Include a do nothing strategy. Implement immovable property for monsters. Implement Invulnerable property for monsters. Implement lifetime property for monsters. Include a fadeout timer for when the lifetime expires. Implement capability for monsters to be deleted from the map. Release Build 9271.

pull/57/head
sigonasr2 7 months ago
parent 39303e2438
commit c2b2652810
  1. 4
      Adventures in Lestoria/Adventures in Lestoria.vcxproj
  2. 10
      Adventures in Lestoria/AdventuresInLestoria.cpp
  3. 2
      Adventures in Lestoria/AdventuresInLestoria.h
  4. 41
      Adventures in Lestoria/Do_Nothing.cpp
  5. 37
      Adventures in Lestoria/Monster.cpp
  6. 8
      Adventures in Lestoria/Monster.h
  7. 1
      Adventures in Lestoria/RUN_STRATEGY.cpp
  8. 2
      Adventures in Lestoria/Version.h
  9. 4
      Adventures in Lestoria/assets/config/MonsterStrategies.txt
  10. 12
      Adventures in Lestoria/assets/config/Monsters.txt
  11. 48
      Adventures in Lestoria/assets/config/credits.txt
  12. BIN
      Adventures in Lestoria/assets/gamepack.pak
  13. BIN
      x64/Release/Adventures in Lestoria.exe

@ -693,6 +693,10 @@
<ClCompile Include="discord-files\types.cpp" />
<ClCompile Include="discord-files\user_manager.cpp" />
<ClCompile Include="discord-files\voice_manager.cpp" />
<ClCompile Include="Do_Nothing.cpp">
<SubType>
</SubType>
</ClCompile>
<ClCompile Include="drawutil.cpp" />
<ClCompile Include="DynamicCounter.cpp">
<SubType>

@ -3951,6 +3951,10 @@ rcode AiL::LoadResource(Renderable&renderable,std::string_view imgPath,bool filt
void AiL::UpdateMonsters(){
for(std::unique_ptr<Monster>&m:MONSTER_LIST){
if(m->markedForDeletion){
AMonsterIsMarkedForDeletion();
continue;
}
m->Update(game->GetElapsedTime());
}
for(Monster&m:game->monstersToBeSpawned){
@ -3958,6 +3962,8 @@ void AiL::UpdateMonsters(){
MONSTER_LIST.push_back(std::make_unique<Monster>(m));
if(MONSTER_LIST.capacity()>prevCapacity)LOG(std::format("WARNING! The monster list has automatically reserved more space and resized to {}! This caused one potential frame where bullet/effect hitlists that stored information on what monsters were hit to potentially be hit a second time or cause monsters that should've been hit to never be hit. Consider starting with a larger default reserved size for MONSTER_LIST if your intention was to have this many monsters!",MONSTER_LIST.capacity()));
}
if(aMonsterIsMarkedForDeletion)std::erase_if(MONSTER_LIST,[](const std::unique_ptr<Monster>&m){return m->markedForDeletion;});
aMonsterIsMarkedForDeletion=false;
game->monstersToBeSpawned.clear();
}
@ -4078,3 +4084,7 @@ void AiL::UpdateEntities(){
ItemDrop::UpdateDrops(GetElapsedTime());
UpdateBullets(GetElapsedTime());
}
void AiL::AMonsterIsMarkedForDeletion(){
aMonsterIsMarkedForDeletion=true;
}

@ -168,6 +168,7 @@ private:
States::State transitionState=States::State::GAME_RUN;
bool gameEnd=false;
std::vector<Monster>monstersToBeSpawned;
bool aMonsterIsMarkedForDeletion=false; //DO NOT MODIFY DIRECTLY! Use AMonsterIsMarkedForDeletion() instead!
time_t gameStarted;
std::function<void(std::string_view)>responseCallback;
float fadeInDuration=0;
@ -338,6 +339,7 @@ public:
void ResetCompletedStageFlag();
void UpdateEntities();
Minimap minimap;
void AMonsterIsMarkedForDeletion(); //The way this is implemented is that monsters marked for deletion will cause the monster update loop to detect there's at least one or more monsters that must be deleted and will call erase_if on the list at the end of the iteration loop.
struct TileGroupData{
vi2d tilePos;

@ -0,0 +1,41 @@
#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 "Monster.h"
void Monster::STRATEGY::DONOTHING(Monster&m,float fElapsedTime,std::string strategy){}

@ -65,7 +65,7 @@ safemap<std::string,std::function<void(Monster&,float,std::string)>>STRATEGY_DAT
std::map<std::string,Renderable*>MonsterData::imgs;
Monster::Monster(vf2d pos,MonsterData data,bool upperLevel,bool bossMob):
pos(pos),spawnPos(pos),hp(data.GetHealth()),size(data.GetSizeMult()),targetSize(data.GetSizeMult()),strategy(data.GetAIStrategy()),name(data.GetDisplayName()),upperLevel(upperLevel),isBoss(bossMob),facingDirection(Direction::SOUTH){
pos(pos),spawnPos(pos),hp(data.GetHealth()),size(data.GetSizeMult()),targetSize(data.GetSizeMult()),strategy(data.GetAIStrategy()),name(data.GetDisplayName()),upperLevel(upperLevel),isBoss(bossMob),facingDirection(Direction::SOUTH),lifetime(GetTotalLifetime()){
for(const std::string&anim:data.GetAnimations()){
animation.AddState(anim,ANIMATION_DATA[std::format("{}_{}",name,anim)]);
}
@ -269,6 +269,20 @@ bool Monster::Update(float fElapsedTime){
lastFacingDirectionChange+=fElapsedTime;
timeSpentAlive+=fElapsedTime;
#pragma region Handle Monster Lifetime and fade timer.
if(fadeTimer>0.f){
fadeTimer=std::max(0.f,fadeTimer-fElapsedTime);
if(fadeTimer==0.f)MarkForDeletion();
}else
if(GetLifetime().has_value()){
lifetime.value()=std::max(0.f,lifetime.value()-fElapsedTime);
if(lifetime.value()==0.f){
fadeTimer=1.f;
lifetime={}; //Nullify the lifetime value as the monster has expired. So we'll prevent a loop by doing this.
}
}
#pragma endregion
if(size!=targetSize){
if(size>targetSize){
size=std::max(targetSize,size-AiL::SIZE_CHANGE_SPEED*fElapsedTime);
@ -323,12 +337,13 @@ bool Monster::Update(float fElapsedTime){
geom2d::line line(pos,m->GetPos());
float dist = line.length();
m->SetPos(line.rpoint(dist*1.1f));
if(m->IsAlive()){
if(!Immovable()&&m->IsAlive()){
vel=line.vector().norm()*-128;
}
}
}
if(!game->GetPlayer()->HasIframes()&&abs(game->GetPlayer()->GetZ()-GetZ())<=1&&game->GetPlayer()->OnUpperLevel()==OnUpperLevel()&&geom2d::overlaps(geom2d::circle(pos,12*size/2),geom2d::circle(game->GetPlayer()->GetPos(),12*game->GetPlayer()->GetSizeMult()/2))){
if(!Immovable()&&
!game->GetPlayer()->HasIframes()&&abs(game->GetPlayer()->GetZ()-GetZ())<=1&&game->GetPlayer()->OnUpperLevel()==OnUpperLevel()&&geom2d::overlaps(geom2d::circle(pos,12*size/2),geom2d::circle(game->GetPlayer()->GetPos(),12*game->GetPlayer()->GetSizeMult()/2))){
geom2d::line line(pos,game->GetPlayer()->GetPos());
float dist = line.length();
SetPos(line.rpoint(-0.1f));
@ -400,9 +415,14 @@ void Monster::Draw()const{
}
const bool NotOnTitleScreen=GameState::STATE!=GameState::states[States::MAIN_MENU];
uint8_t blendColAlpha=255U;
if(NotOnTitleScreen
&&(game->GetPlayer()->HasIframes()||OnUpperLevel()!=game->GetPlayer()->OnUpperLevel()||abs(GetZ()-game->GetPlayer()->GetZ())>1))blendCol.a=160;
&&(game->GetPlayer()->HasIframes()||OnUpperLevel()!=game->GetPlayer()->OnUpperLevel()||abs(GetZ()-game->GetPlayer()->GetZ())>1))blendColAlpha=160;
if(fadeTimer>0.f)blendColAlpha=uint8_t(util::lerp(0,blendCol.a,fadeTimer)); //Fade timer goes from 1 to 0 seconds.
blendCol.a=blendColAlpha;
game->view.DrawPartialRotatedDecal(GetPos()-vf2d{0,GetZ()},GetFrame().GetSourceImage()->Decal(),spriteRot,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,vf2d(GetSizeMult()*(!HasFourWaySprites()&&GetFacingDirection()==Direction::EAST?-1:1),GetSizeMult()),blendCol);
if(overlaySprite.length()!=0){
@ -559,7 +579,7 @@ const bool Monster::AttackAvoided(const float attackZ)const{
}
bool Monster::Hurt(int damage,bool onUpperLevel,float z){
if(!IsAlive()||onUpperLevel!=OnUpperLevel()||AttackAvoided(z)) return false;
if(Invulnerable()||!IsAlive()||onUpperLevel!=OnUpperLevel()||AttackAvoided(z)) return false;
if(game->InBossEncounter()){
game->StartBossEncounter();
}
@ -1011,8 +1031,15 @@ const bool Monster::Invulnerable()const{
return MONSTER_DATA.at(GetName()).Invulnerable();
}
const std::optional<float>Monster::GetLifetime()const{
return lifetime;
}
const std::optional<float>Monster::GetTotalLifetime()const{
return MONSTER_DATA.at(GetName()).GetLifetime();
}
const std::optional<float>Monster::GetCollisionRadius()const{
return MONSTER_DATA.at(GetName()).GetCollisionRadius();
}
void Monster::MarkForDeletion(){
markedForDeletion=true;
}

@ -168,9 +168,13 @@ public:
const bool Invulnerable()const;
//If an object has a lifetime set, returns it.
const std::optional<float>GetLifetime()const;
const std::optional<float>GetTotalLifetime()const;
//If an object has a collision radius, returns it.
const std::optional<float>GetCollisionRadius()const;
private:
//NOTE: Marking a monster for deletion does not trigger any death events. It just simply removes the monster from the field!!
// The way this works is that monsters marked for deletion will cause the monster update loop to detect there's at least one or more monsters that must be deleted and will call erase_if on the list at the end of the iteration loop.
void MarkForDeletion();
std::string name;
vf2d pos;
vf2d vel={0,0};
@ -240,6 +244,9 @@ private:
std::vector<DeathSpawnInfo>deathData; //Data that contains further actions and information when this monster dies. Mostly used to spawn sub-monsters from a defeated monster.
vf2d mountedSprOffset{};
float timeSpentAlive{0.f};
std::optional<float>lifetime{};
float fadeTimer{0.f};
bool markedForDeletion{false}; //DO NOT MODIFY DIRECTLY. Use MarkForDeletion() if this monster needs to be marked. NOTE: Marking a monster for deletion does not trigger any death events. It just simply removes the monster from the field!!
private:
struct STRATEGY{
static std::string ERR;
@ -269,6 +276,7 @@ private:
static void GOBLIN_BOMB(Monster&m,float fElapsedTime,std::string strategy);
static void HAWK(Monster&m,float fElapsedTime,std::string strategy);
static void STONE_ELEMENTAL(Monster&m,float fElapsedTime,std::string strategy);
static void DONOTHING(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.

@ -62,6 +62,7 @@ void Monster::InitializeStrategies(){
STRATEGY_DATA.insert("Goblin Bomb",Monster::STRATEGY::GOBLIN_BOMB);
STRATEGY_DATA.insert("Hawk",Monster::STRATEGY::HAWK);
STRATEGY_DATA.insert("Stone Elemental",Monster::STRATEGY::STONE_ELEMENTAL);
STRATEGY_DATA.insert("Do Nothing",Monster::STRATEGY::DONOTHING);
STRATEGY_DATA.SetInitialized();
}

@ -39,7 +39,7 @@ All rights reserved.
#define VERSION_MAJOR 1
#define VERSION_MINOR 2
#define VERSION_PATCH 0
#define VERSION_BUILD 9270
#define VERSION_BUILD 9271
#define stringify(a) stringify_(a)
#define stringify_(a) #a

@ -725,4 +725,8 @@ MonsterStrategy
# Minimum Distance the Stone Elemental will always perform a dive
Auto Dive Range = 1200
}
Do Nothing
{
}
}

@ -786,17 +786,17 @@ Monsters
Invulnerable = True
MoveSpd = 0%
# Due to the Stone Elemental's base sprite size being 36x36, 220% is actually 146.666666667% size when factoring in a 50% larger sprite.
Size = 100%
Collision Radius = 59
# The Pillar is supposed to be 350 radius.
Size = 350%
Collision Radius = 8
Lifetime = 5s
XP = 0
Strategy = Run Towards
Strategy = Do Nothing
#Size of each animation frame
SheetFrameSize = 168,528
SheetFrameSize = 24,96
# Setting this to true means every four rows indicates one animation, the ordering of the directions is: NORTH, EAST, SOUTH, WEST
4-Way Spritesheet = False
@ -806,7 +806,7 @@ Monsters
# Frame Count, Frame Speed (s), Frame Cycling (Repeat,OneShot,PingPong,Reverse)
# Animations must be defined in the same order as they are in their sprite sheets
# The First Four animations must represent a standing, walking, attack, and death animation. Their names are up to the creator.
IDLE = 1, 0.6, Repeat
IDLE = 4, 0.4, OneShot
WALK = 1, 0.2, Repeat
STAND BEHIND ME = 1, 0.2, OneShot
DEATH = 1, 0.15, OneShot

@ -45,32 +45,34 @@ Credits
LINE[42]="ERA OF FANTASY - GRASSLANDS"
LINE[43]="X: @Namatnieks"
LINE[44]=" "
LINE[45]="*** Minifantasy - Tiny Overworld v1.0 ***"
LINE[46]="Minifantasy is an original idea by Krishna Palacio"
LINE[47]=" "
LINE[48]="Public Domain Font Authors"
LINE[49]="c64esque by andraaspar"
LINE[50]="Habbo by Omni"
LINE[51]="Unknown by Anonymous"
LINE[52]=" "
LINE[53]="Nb Pixel Font Bundle"
LINE[54]="Nb Pixel Font Bundle 2"
LINE[55]=" "
LINE[56]=" "
LINE[57]="Game License"
LINE[58]="~~~~~~~~~~~~~~~~"
LINE[59]="License (OLC-3)"
LINE[60]="~~~~~~~~~~~~~~~"
LINE[61]=" "
LINE[62]="Copyright ` 2024 Sig Productions <niconiconii@lestoria.net>"
LINE[45]="Fantastic Pillar by InThePixel"
LINE[46]=" "
LINE[47]="*** Minifantasy - Tiny Overworld v1.0 ***"
LINE[48]="Minifantasy is an original idea by Krishna Palacio"
LINE[49]=" "
LINE[50]="Public Domain Font Authors"
LINE[51]="c64esque by andraaspar"
LINE[52]="Habbo by Omni"
LINE[53]="Unknown by Anonymous"
LINE[54]=" "
LINE[55]="Nb Pixel Font Bundle"
LINE[56]="Nb Pixel Font Bundle 2"
LINE[57]=" "
LINE[58]=" "
LINE[59]="Game License"
LINE[60]="~~~~~~~~~~~~~~~~"
LINE[61]="License (OLC-3)"
LINE[62]="~~~~~~~~~~~~~~~"
LINE[63]=" "
LINE[64]="Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:"
LINE[64]="Copyright ` 2024 Sig Productions <niconiconii@lestoria.net>"
LINE[65]=" "
LINE[66]="1. Redistributions or derivations of source code must retain the above copyright notice, this list of conditions and the following disclaimer."
LINE[66]="Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:"
LINE[67]=" "
LINE[68]="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."
LINE[68]="1. Redistributions or derivations of source code must retain the above copyright notice, this list of conditions and the following disclaimer."
LINE[69]=" "
LINE[70]="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."
LINE[70]="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."
LINE[71]=" "
LINE[72]="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."
LINE[72]="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."
LINE[73]=" "
LINE[74]="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."
}
Loading…
Cancel
Save