# 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"
# include "Animation.h"
# include "config.h"
# include "DEFINES.h"
# include "safemap.h"
# include "Item.h"
INCLUDE_DATA
INCLUDE_STRATEGY_DATA
INCLUDE_ANIMATION_DATA
INCLUDE_ITEM_DATA
std : : map < std : : string , MonsterData > MONSTER_DATA ;
MonsterData : : MonsterData ( )
: atk ( 0 ) , collisionDmg ( 0 ) , hp ( 0 ) , moveSpd ( 0 ) , size ( 0 ) , strategy ( " Run Towards " ) { }
MonsterData : : MonsterData ( std : : string name , std : : string displayName , int hp , int atk , const uint32_t xp , std : : vector < MonsterDropData > drops , float moveSpd , float size , std : : string strategy , int collisionDmg ) :
name ( name ) , displayName ( displayName ) , hp ( hp ) , atk ( atk ) , xp ( xp ) , moveSpd ( moveSpd ) , size ( size ) , strategy ( strategy ) , dropData ( drops ) , collisionDmg ( collisionDmg ) , collisionRadius ( 8.f * this - > size ) { }
void MonsterData : : InitializeMonsterData ( ) {
for ( auto & [ key , size ] : DATA [ " Monsters " ] . GetKeys ( ) ) {
std : : string MonsterName = key ;
std : : string MonsterImgName = MonsterName ;
std : : string MonsterDisplayName = MonsterName ;
if ( MONSTER_DATA . count ( key ) ) {
ERR ( " WARNING! A monster with the name " < < key < < " already exists in the database! Duplicates are not allowed. " )
}
std : : vector < std : : string > animations ;
bool hasFourWaySpriteSheet = false ;
if ( DATA [ " Monsters " ] [ MonsterName ] . HasProperty ( " Base Image Name " ) ) {
MonsterImgName = DATA [ " Monsters " ] [ MonsterName ] [ " Base Image Name " ] . GetString ( ) ;
}
if ( ! MonsterData : : imgs . count ( MonsterImgName ) ) {
MonsterData : : imgs [ MonsterImgName ] = NEW Renderable ( ) ;
const rcode imgLoadResult = MonsterData : : imgs [ MonsterImgName ] - > Load ( " assets/monsters/commercial_assets/ " + MonsterImgName + " .png " ) ;
if ( imgLoadResult ! = OK ) ERR ( std : : format ( " WARNING! Image loading for Monster {} failed with result {} " , MonsterImgName , int ( imgLoadResult ) ) ) ;
}
EventName hurtSound = " " ;
EventName deathSound = " " ;
EventName walkSound = " " ;
if ( DATA [ " Monsters " ] [ MonsterName ] . HasProperty ( " Hurt Sound " ) ) {
hurtSound = DATA [ " Monsters " ] [ MonsterName ] [ " Hurt Sound " ] . GetString ( ) ;
}
if ( DATA [ " Monsters " ] [ MonsterName ] . HasProperty ( " Death Sound " ) ) {
deathSound = DATA [ " Monsters " ] [ MonsterName ] [ " Death Sound " ] . GetString ( ) ;
}
if ( DATA [ " Monsters " ] [ MonsterName ] . HasProperty ( " Walk Sound " ) ) {
walkSound = DATA [ " Monsters " ] [ MonsterName ] [ " Walk Sound " ] . GetString ( ) ;
}
auto CreateHorizontalAnimationSequence = [ & ] ( Renderable & img , int frameCount , vf2d size , std : : string state , int row , AnimationData data = { } ) {
if ( ANIMATION_DATA . count ( state ) ) {
LOG ( std : : format ( " Animation sequence for {} with state {} at row {} already exists. Skipping. " , MonsterName , state , row ) ) ;
return ;
}
Animate2D : : FrameSequence anim ( data . frameDuration , data . style ) ;
for ( int i = 0 ; i < frameCount ; i + + ) {
anim . AddFrame ( { & img , { { int ( i * size . x ) , int ( row * size . y ) } , size } } ) ;
}
ANIMATION_DATA [ state ] = anim ;
} ;
if ( ! DATA [ " Monsters " ] [ MonsterName ] . HasProperty ( " Animations " ) ) ERR ( std : : format ( " WARNING! Could not find any animations to load for monster {}! Please check the Monsters.txt configuration file! " , MonsterName ) ) ;
if ( DATA [ " Monsters " ] [ MonsterName ] [ " Animations " ] . GetKeys ( ) . size ( ) < 4 ) ERR ( std : : format ( " WARNING! Monster {} does not have at least 4 animations. The animations should be defined in this order: a standing, walking, attack, and death animation " , MonsterName ) ) ;
for ( size_t animationRow = 0 ; auto & [ animationName , data ] : DATA [ " Monsters " ] [ MonsterName ] [ " Animations " ] . GetOrderedKeys ( ) ) {
Animate2D : : Style style = Animate2D : : Style : : Repeat ;
if ( data . GetString ( 2 ) = = " Repeat " ) {
style = Animate2D : : Style : : Repeat ;
} else
if ( data . GetString ( 2 ) = = " OneShot " ) {
style = Animate2D : : Style : : OneShot ;
} else
if ( data . GetString ( 2 ) = = " PingPong " ) {
style = Animate2D : : Style : : PingPong ;
} else
if ( data . GetString ( 2 ) = = " Reverse " ) {
style = Animate2D : : Style : : Reverse ;
} else
if ( data . GetString ( 2 ) = = " ReverseOneShot " ) {
style = Animate2D : : Style : : ReverseOneShot ;
} else {
ERR ( std : : format ( " WARNING! Invalid Animation Style specified: {} " , int ( style ) ) ) ;
}
int frameCount = data . GetInt ( 0 ) ;
vf2d frameSize = vf2d { float ( DATA [ " Monsters " ] [ MonsterName ] [ " SheetFrameSize " ] . GetInt ( 0 ) ) , float ( DATA [ " Monsters " ] [ MonsterName ] [ " SheetFrameSize " ] . GetInt ( 1 ) ) } ;
if ( ! DATA [ " Monsters " ] [ MonsterName ] . HasProperty ( " 4-Way Spritesheet " ) ) ERR ( std : : format ( " WARNING! Monster {} does not have the property '4-Way Spritesheet' set " , MonsterName ) ) ;
if ( DATA [ " Monsters " ] [ MonsterName ] [ " 4-Way Spritesheet " ] . GetBool ( ) ) {
hasFourWaySpriteSheet = true ;
for ( int direction = 0 ; direction < 4 ; direction + + ) {
CreateHorizontalAnimationSequence ( * MonsterData : : imgs [ MonsterImgName ] , frameCount , frameSize , std : : format ( " {}_{}_{} " , MonsterName , animationName , direction ) , animationRow * 4 + direction , AnimationData { float ( data . GetReal ( 1 ) ) , style } ) ;
animations . push_back ( std : : format ( " {}_{} " , animationName , direction ) ) ;
}
} else {
CreateHorizontalAnimationSequence ( * MonsterData : : imgs [ MonsterImgName ] , frameCount , frameSize , std : : format ( " {}_{} " , MonsterName , animationName ) , animationRow , AnimationData { float ( data . GetReal ( 1 ) ) , style } ) ;
animations . push_back ( animationName ) ;
}
animationRow + + ;
}
std : : vector < MonsterDropData > drops ;
//Add drop items to monster data from the config.
int dropDataCounter = 0 ;
while ( DATA [ " Monsters " ] [ MonsterName ] . HasProperty ( " DROP[ " + std : : to_string ( dropDataCounter ) + " ] " ) ) {
datafile drop = DATA [ " Monsters " ] [ MonsterName ] [ " DROP[ " + std : : to_string ( dropDataCounter ) + " ] " ] ;
if ( ! ITEM_DATA . count ( drop . GetString ( 0 ) ) ) {
ERR ( " Could not add drop " < < drop . GetString ( 0 ) < < " to " < < MonsterName < < " 's drop table! Item does not exist! " ) ;
}
drops . push_back ( MonsterDropData { drop . GetString ( 0 ) , float ( drop . GetReal ( 1 ) ) , drop . GetInt ( 2 ) , drop . GetInt ( 3 ) } ) ;
dropDataCounter + + ;
}
const std : : string & strategyName = DATA [ " Monsters " ] [ MonsterName ] [ " Strategy " ] . GetString ( ) ;
if ( ! STRATEGY_DATA . count ( strategyName ) ) {
ERR ( " WARNING! Strategy for " < < MonsterName < < " does not exist in strategy database! " ) ;
}
if ( DATA [ " Monsters " ] [ MonsterName ] . HasProperty ( " Display Name " ) ) MonsterDisplayName = DATA [ " Monsters " ] [ MonsterName ] [ " Display Name " ] . GetString ( ) ;
MonsterData monster (
MonsterName ,
MonsterDisplayName ,
DATA [ " Monsters " ] [ MonsterName ] [ " Health " ] . GetInt ( ) ,
DATA [ " Monsters " ] [ MonsterName ] [ " Attack " ] . GetInt ( ) ,
DATA [ " Monsters " ] [ MonsterName ] [ " XP " ] . GetInt ( ) ,
drops ,
float ( DATA [ " Monsters " ] [ MonsterName ] [ " MoveSpd " ] . GetReal ( ) ) ,
float ( DATA [ " Monsters " ] [ MonsterName ] [ " Size " ] . GetReal ( ) ) / 100 ,
strategyName ,
DATA [ " Monsters " ] [ MonsterName ] [ " CollisionDmg " ] . GetInt ( )
) ;
if ( DATA [ " Monsters " ] [ MonsterName ] . HasProperty ( " Immovable " ) ) {
monster . immovable = DATA [ " Monsters " ] [ MonsterName ] [ " Immovable " ] . GetBool ( ) ;
if ( DATA [ " Monsters " ] [ MonsterName ] . HasProperty ( " Fadeout " ) ) monster . fadeout = DATA [ " Monsters " ] [ MonsterName ] [ " Fadeout " ] . GetBool ( ) ;
else monster . fadeout = true ;
}
if ( DATA [ " Monsters " ] [ MonsterName ] . HasProperty ( " Fadeout " ) ) monster . fadeout = DATA [ " Monsters " ] [ MonsterName ] [ " Fadeout " ] . GetBool ( ) ;
if ( DATA [ " Monsters " ] [ MonsterName ] . HasProperty ( " No Facing " ) ) monster . noFacing = DATA [ " Monsters " ] [ MonsterName ] [ " No Facing " ] . GetBool ( ) ;
if ( DATA [ " Monsters " ] [ MonsterName ] . HasProperty ( " Ignore Collisions " ) ) monster . ignoresCollision = DATA [ " Monsters " ] [ MonsterName ] [ " Ignore Collisions " ] . GetBool ( ) ;
if ( DATA [ " Monsters " ] [ MonsterName ] . HasProperty ( " Mounted Animation " ) ) monster . mountedAnimName = DATA [ " Monsters " ] [ MonsterName ] [ " Mounted Animation " ] . GetString ( ) ;
if ( DATA [ " Monsters " ] [ MonsterName ] . HasProperty ( " Mounted Animation Offset " ) ) {
if ( DATA [ " Monsters " ] [ MonsterName ] [ " Mounted Animation Offset " ] . GetValueCount ( ) = = 2 ) monster . mountedAnimationOffset = { DATA [ " Monsters " ] [ MonsterName ] [ " Mounted Animation Offset " ] . GetReal ( 0 ) , DATA [ " Monsters " ] [ MonsterName ] [ " Mounted Animation Offset " ] . GetReal ( 1 ) } ;
else ERR ( std : : format ( " WARNING! Monster {} containing a mounted animation offset has {} for reading in a vector, when vectors are supposed to only have two values! Please check the \" Mounted Animation Offset \" configuration value for {} " , MonsterName , DATA [ " Monsters " ] [ MonsterName ] [ " Mounted Animation Offset " ] . GetValueCount ( ) , MonsterName ) ) ;
}
if ( DATA [ " Monsters " ] [ MonsterName ] . HasProperty ( " Invulnerable " ) ) monster . invulnerable = DATA [ " Monsters " ] [ MonsterName ] [ " Invulnerable " ] . GetBool ( ) ;
if ( DATA [ " Monsters " ] [ MonsterName ] . HasProperty ( " Lifetime " ) ) monster . lifetime = DATA [ " Monsters " ] [ MonsterName ] [ " Lifetime " ] . GetReal ( ) ;
monster . collisionRadius = 8 * ( std : : min ( DATA [ " Monsters " ] [ MonsterName ] [ " SheetFrameSize " ] . GetInt ( 0 ) , DATA [ " Monsters " ] [ MonsterName ] [ " SheetFrameSize " ] . GetInt ( 1 ) ) / 24.f ) ;
if ( DATA [ " Monsters " ] [ MonsterName ] . HasProperty ( " Collision Radius " ) ) monster . collisionRadius = DATA [ " Monsters " ] [ MonsterName ] [ " Collision Radius " ] . GetReal ( ) ;
if ( DATA [ " Monsters " ] [ MonsterName ] . HasProperty ( " ShowBossIndicator " ) ) monster . hasArrowIndicator = DATA [ " Monsters " ] [ MonsterName ] [ " ShowBossIndicator " ] . GetBool ( ) ;
if ( DATA [ " Monsters " ] [ MonsterName ] . HasProperty ( " Rectangle Collision " ) ) {
const datafile & rectData { DATA [ " Monsters " ] [ MonsterName ] [ " Rectangle Collision " ] } ;
monster . rectCollision = { { rectData . GetReal ( 0 ) , rectData . GetReal ( 1 ) } , { rectData . GetReal ( 2 ) , rectData . GetReal ( 3 ) } } ;
}
if ( hasFourWaySpriteSheet ) monster . SetUsesFourWaySprites ( ) ;
for ( size_t animationRow = 0 ; const std : : string & animationName : animations ) {
if ( ! monster . animations . insert ( animationName ) . second ) ERR ( std : : format ( " WARNING! The Animation {} for Monster {} already exists! Animations should have unique names! " , animationName , MonsterName ) ) ;
if ( monster . HasFourWaySprites ( ) ) {
switch ( animationRow ) {
case 0 * 4 : monster . idleAnimation = animationName . substr ( 0 , animationName . length ( ) - 2 ) ; break ;
case 1 * 4 : monster . jumpAnimation = animationName . substr ( 0 , animationName . length ( ) - 2 ) ; break ;
case 2 * 4 : monster . shootAnimation = animationName . substr ( 0 , animationName . length ( ) - 2 ) ; break ;
case 3 * 4 : monster . deathAnimation = animationName . substr ( 0 , animationName . length ( ) - 2 ) ; break ;
}
} else {
switch ( animationRow ) {
case 0 : monster . idleAnimation = animationName ; break ;
case 1 : monster . jumpAnimation = animationName ; break ;
case 2 : monster . shootAnimation = animationName ; break ;
case 3 : monster . deathAnimation = animationName ; break ;
}
}
animationRow + + ;
}
monster . hurtSound = hurtSound ;
monster . deathSound = deathSound ;
monster . walkSound = walkSound ;
MONSTER_DATA [ MonsterName ] = monster ;
}
}
void MonsterData : : InitializeNPCData ( ) {
for ( auto & [ key , dataSize ] : DATA [ " NPCs " ] . GetKeys ( ) ) {
std : : string NPCName = key ;
if ( MONSTER_DATA . count ( key ) ) {
ERR ( " WARNING! A monster with the name " < < key < < " already exists in the database! Duplicates are not allowed. " )
}
std : : vector < std : : string > animations ;
MonsterData : : imgs [ NPCName ] = NEW Renderable ( ) ;
const rcode imgLoadResult = MonsterData : : imgs [ NPCName ] - > Load ( " assets/npcs/ " + NPCName + " .png " ) ;
if ( imgLoadResult ! = OK ) ERR ( std : : format ( " WARNING! Image loading for NPC {} failed with result {} " , NPCName , int ( imgLoadResult ) ) ) ;
EventName hurtSound = " " ;
EventName deathSound = " " ;
EventName walkSound = " " ;
int health = 100 ;
int attack = 0 ;
int xp = 0 ;
float moveSpd = 100.f ;
float size = 100.f ;
int collisionDmg = 0 ;
if ( DATA [ " NPCs " ] [ NPCName ] . HasProperty ( " Health " ) ) health = DATA [ " NPCs " ] [ NPCName ] [ " Health " ] . GetInt ( ) ;
if ( DATA [ " NPCs " ] [ NPCName ] . HasProperty ( " Attack " ) ) attack = DATA [ " NPCs " ] [ NPCName ] [ " Attack " ] . GetInt ( ) ;
if ( DATA [ " NPCs " ] [ NPCName ] . HasProperty ( " XP " ) ) xp = DATA [ " NPCs " ] [ NPCName ] [ " XP " ] . GetInt ( ) ;
if ( DATA [ " NPCs " ] [ NPCName ] . HasProperty ( " MoveSpd " ) ) moveSpd = DATA [ " NPCs " ] [ NPCName ] [ " MoveSpd " ] . GetReal ( ) ;
if ( DATA [ " NPCs " ] [ NPCName ] . HasProperty ( " Size " ) ) moveSpd = DATA [ " NPCs " ] [ NPCName ] [ " Size " ] . GetReal ( ) ;
if ( DATA [ " NPCs " ] [ NPCName ] . HasProperty ( " CollisionDmg " ) ) collisionDmg = DATA [ " NPCs " ] [ NPCName ] [ " CollisionDmg " ] . GetInt ( ) ;
if ( DATA [ " NPCs " ] [ NPCName ] . HasProperty ( " Hurt Sound " ) ) {
hurtSound = DATA [ " NPCs " ] [ NPCName ] [ " Hurt Sound " ] . GetString ( ) ;
}
if ( DATA [ " NPCs " ] [ NPCName ] . HasProperty ( " Death Sound " ) ) {
deathSound = DATA [ " NPCs " ] [ NPCName ] [ " Death Sound " ] . GetString ( ) ;
}
if ( DATA [ " NPCs " ] [ NPCName ] . HasProperty ( " Walk Sound " ) ) {
walkSound = DATA [ " NPCs " ] [ NPCName ] [ " Walk Sound " ] . GetString ( ) ;
}
auto CreateHorizontalAnimationSequence = [ & ] ( Renderable & img , int frameCount , vf2d size , std : : string state , int row , AnimationData data = { } ) {
Animate2D : : FrameSequence anim ( data . frameDuration , data . style ) ;
for ( int i = 0 ; i < frameCount ; i + + ) {
anim . AddFrame ( { & img , { { int ( i * size . x ) , int ( row * size . y ) } , size } } ) ;
}
ANIMATION_DATA [ state ] = anim ;
} ;
if ( ! DATA [ " NPCs " ] [ NPCName ] . HasProperty ( " Animations " ) ) ERR ( std : : format ( " WARNING! Could not find any animations to load for monster {}! Please check the Monsters.txt configuration file! " , NPCName ) ) ;
if ( DATA [ " NPCs " ] [ NPCName ] [ " Animations " ] . GetKeys ( ) . size ( ) < 4 ) ERR ( std : : format ( " WARNING! Monster {} does not have at least 4 animations. The animations should be defined in this order: a standing, walking, attack, and death animation " , NPCName ) ) ;
for ( size_t animationRow = 0 ; auto & [ animationName , data ] : DATA [ " NPCs " ] [ NPCName ] [ " Animations " ] . GetOrderedKeys ( ) ) {
Animate2D : : Style style = Animate2D : : Style : : Repeat ;
if ( data . GetString ( 2 ) = = " Repeat " ) {
style = Animate2D : : Style : : Repeat ;
} else
if ( data . GetString ( 2 ) = = " OneShot " ) {
style = Animate2D : : Style : : OneShot ;
} else
if ( data . GetString ( 2 ) = = " PingPong " ) {
style = Animate2D : : Style : : PingPong ;
} else
if ( data . GetString ( 2 ) = = " Reverse " ) {
style = Animate2D : : Style : : Reverse ;
} else
if ( data . GetString ( 2 ) = = " ReverseOneShot " ) {
style = Animate2D : : Style : : ReverseOneShot ;
} else {
ERR ( std : : format ( " WARNING! Invalid Animation Style specified: {} " , int ( style ) ) ) ;
}
int frameCount = data . GetInt ( 0 ) ;
vf2d frameSize = vf2d { float ( DATA [ " NPCs " ] [ NPCName ] [ " SheetFrameSize " ] . GetInt ( 0 ) ) , float ( DATA [ " NPCs " ] [ NPCName ] [ " SheetFrameSize " ] . GetInt ( 1 ) ) } ;
CreateHorizontalAnimationSequence ( * MonsterData : : imgs [ NPCName ] , frameCount , frameSize , std : : format ( " {}_{} " , NPCName , animationName ) , animationRow , AnimationData { float ( data . GetReal ( 1 ) ) , style } ) ;
animations . push_back ( animationName ) ;
animationRow + + ;
}
std : : vector < MonsterDropData > drops ;
//Add drop items to monster data from the config.
int dropDataCounter = 0 ;
while ( DATA [ " NPCs " ] [ NPCName ] . HasProperty ( " DROP[ " + std : : to_string ( dropDataCounter ) + " ] " ) ) {
datafile drop = DATA [ " NPCs " ] [ NPCName ] [ " DROP[ " + std : : to_string ( dropDataCounter ) + " ] " ] ;
if ( ! ITEM_DATA . count ( drop . GetString ( 0 ) ) ) {
ERR ( " Could not add drop " < < drop . GetString ( 0 ) < < " to " < < NPCName < < " 's drop table! Item does not exist! " ) ;
}
drops . push_back ( MonsterDropData { drop . GetString ( 0 ) , float ( drop . GetReal ( 1 ) ) , drop . GetInt ( 2 ) , drop . GetInt ( 3 ) } ) ;
dropDataCounter + + ;
}
const std : : string & strategyName = DATA [ " NPCs " ] [ NPCName ] [ " Strategy " ] . GetString ( ) ;
if ( ! STRATEGY_DATA . count ( strategyName ) ) {
ERR ( " WARNING! Strategy for " < < NPCName < < " does not exist in strategy database! " ) ;
}
MonsterData monster ( NPCName , NPCName , health , attack , xp , drops , moveSpd , size / 100 , strategyName , collisionDmg ) ;
for ( size_t animationRow = 0 ; const std : : string & animationName : animations ) {
if ( ! monster . animations . insert ( animationName ) . second ) ERR ( std : : format ( " WARNING! The Animation {} for Monster {} already exists! Animations should have unique names! " , animationName , NPCName ) ) ;
switch ( animationRow ) {
case 0 : monster . idleAnimation = animationName ; break ;
case 1 : monster . jumpAnimation = animationName ; break ;
case 2 : monster . shootAnimation = animationName ; break ;
case 3 : monster . deathAnimation = animationName ; break ;
}
animationRow + + ;
}
monster . hurtSound = hurtSound ;
monster . deathSound = deathSound ;
monster . walkSound = walkSound ;
monster . isNPC = true ; //If we read any data from this config file, it's definitely considered an NPC.
MONSTER_DATA [ NPCName ] = monster ;
}
}
int MonsterData : : GetHealth ( ) {
return hp ;
}
int MonsterData : : GetAttack ( ) {
return atk ;
}
float MonsterData : : GetMoveSpdMult ( ) {
return moveSpd ;
}
float MonsterData : : GetSizeMult ( ) const {
return size ;
}
int MonsterData : : GetCollisionDmg ( ) {
return collisionDmg ;
}
const std : : string & MonsterData : : GetAIStrategy ( ) const {
return strategy ;
}
const std : : string & MonsterData : : GetInternalName ( ) const {
return name ;
}
const std : : string & MonsterData : : GetDisplayName ( ) const {
return displayName ;
}
const std : : string MonsterData : : GetIdleAnimation ( const Direction & dir ) const {
if ( HasFourWaySprites ( ) ) return std : : format ( " {}_{} " , idleAnimation , int ( dir ) ) ;
else return idleAnimation ;
}
const std : : string MonsterData : : GetJumpAnimation ( const Direction & dir ) const {
if ( HasFourWaySprites ( ) ) return std : : format ( " {}_{} " , jumpAnimation , int ( dir ) ) ;
else return jumpAnimation ;
}
const std : : string MonsterData : : GetShootAnimation ( const Direction & dir ) const {
if ( HasFourWaySprites ( ) ) return std : : format ( " {}_{} " , shootAnimation , int ( dir ) ) ;
else return shootAnimation ;
}
const std : : string MonsterData : : GetDeathAnimation ( const Direction & dir ) const {
if ( HasFourWaySprites ( ) ) return std : : format ( " {}_{} " , deathAnimation , int ( dir ) ) ;
else return deathAnimation ;
}
const std : : vector < MonsterDropData > & MonsterData : : GetDropData ( ) {
return dropData ;
}
const EventName & MonsterData : : GetHurtSound ( ) {
return hurtSound ;
}
const EventName & MonsterData : : GetDeathSound ( ) {
return deathSound ;
}
const EventName & MonsterData : : GetWalkSound ( ) {
return walkSound ;
}
const bool MonsterData : : HasFourWaySprites ( ) const {
return fourWayDirectionalSprites ;
}
void MonsterData : : SetUsesFourWaySprites ( ) {
fourWayDirectionalSprites = true ;
}
const std : : string MonsterData : : GetDefaultIdleAnimation ( ) const {
return GetIdleAnimation ( Direction : : SOUTH ) ;
}
const std : : string MonsterData : : GetDefaultJumpAnimation ( ) const {
return GetJumpAnimation ( Direction : : SOUTH ) ;
}
const std : : string MonsterData : : GetDefaultShootAnimation ( ) const {
return GetShootAnimation ( Direction : : SOUTH ) ;
}
const std : : string MonsterData : : GetDefaultDeathAnimation ( ) const {
return GetDeathAnimation ( Direction : : SOUTH ) ;
}
const bool MonsterData : : HasMountedAnimation ( ) const {
return mountedAnimName . has_value ( ) ;
}
const std : : optional < const std : : string > MonsterData : : GetMountedAnimation ( ) const {
if ( ! HasMountedAnimation ( ) ) ERR ( " WARNING! Trying to get a mounted animation for a monster that doesn't have a mounted animation to begin with! " ) ;
return mountedAnimName . value ( ) ;
}
const vf2d & MonsterData : : GetMountedAnimationOffset ( ) const {
if ( ! HasMountedAnimation ( ) ) ERR ( " WARNING! Trying to get a mounted animation offset for a monster that doesn't have a mounted animation to begin with! " ) ;
return mountedAnimationOffset ;
}
const bool MonsterData : : IgnoresTerrainCollision ( ) const {
return ignoresCollision ;
}
const bool MonsterData : : Immovable ( ) const {
return immovable ;
}
const bool MonsterData : : Invulnerable ( ) const {
return invulnerable ;
}
const std : : optional < float > MonsterData : : GetLifetime ( ) const {
return lifetime ;
}
const float MonsterData : : GetCollisionRadius ( ) const {
return collisionRadius * 0.6f ;
}
const bool MonsterData : : HasArrowIndicator ( ) const {
return hasArrowIndicator ;
}
const std : : optional < geom2d : : rect < float > > & MonsterData : : GetRectangleCollision ( ) const {
return rectCollision ;
}
const bool MonsterData : : FadeoutWhenStandingBehind ( ) const {
return fadeout ;
}
const bool MonsterData : : FaceTarget ( ) const {
return ! noFacing ;
}