@ -94,7 +94,7 @@ bool _DEBUG_MAP_LOAD_INFO = false;
//360x240
//360x240
vi2d WINDOW_SIZE = { 24 * 15 , 24 * 10 } ;
vi2d WINDOW_SIZE = { 24 * 15 , 24 * 10 } ;
safemap < std : : string , Animate2D : : FrameSequence > ANIMATION_DATA ;
safemap < std : : string , Animate2D : : FrameSequence > ANIMATION_DATA ;
std : : vector < std : : unique _ptr< Monster > > MONSTER_LIST ;
std : : vector < std : : shared _ptr< Monster > > MONSTER_LIST ;
std : : unordered_map < MonsterSpawnerID , MonsterSpawner > SPAWNER_LIST ;
std : : unordered_map < MonsterSpawnerID , MonsterSpawner > SPAWNER_LIST ;
std : : vector < std : : shared_ptr < DamageNumber > > DAMAGENUMBER_LIST ;
std : : vector < std : : shared_ptr < DamageNumber > > DAMAGENUMBER_LIST ;
std : : vector < std : : unique_ptr < IBullet > > BULLET_LIST ;
std : : vector < std : : unique_ptr < IBullet > > BULLET_LIST ;
@ -735,7 +735,7 @@ const HurtList AiL::Hurt(vf2d pos,float radius,int damage,bool upperLevel,float
const bool CheckForPlayerCollisions = hurtTargets & HurtType : : PLAYER ;
const bool CheckForPlayerCollisions = hurtTargets & HurtType : : PLAYER ;
if ( CheckForMonsterCollisions ) {
if ( CheckForMonsterCollisions ) {
for ( std : : unique _ptr< Monster > & m : MONSTER_LIST ) {
for ( std : : shared _ptr< Monster > & m : MONSTER_LIST ) {
const bool InRange = geom2d : : overlaps ( geom2d : : circle ( pos , radius ) , geom2d : : circle ( m - > GetPos ( ) , 12 * m - > GetSizeMult ( ) ) ) ;
const bool InRange = geom2d : : overlaps ( geom2d : : circle ( pos , radius ) , geom2d : : circle ( m - > GetPos ( ) , 12 * m - > GetSizeMult ( ) ) ) ;
if ( InRange ) {
if ( InRange ) {
HurtReturnValue returnVal = m - > Hurt ( damage , upperLevel , z , hurtFlags ) ;
HurtReturnValue returnVal = m - > Hurt ( damage , upperLevel , z , hurtFlags ) ;
@ -757,7 +757,7 @@ const HurtList AiL::HurtMonsterType(vf2d pos,float radius,int damage,bool upperL
if ( ! MONSTER_DATA . count ( std : : string ( monsterName ) ) ) ERR ( std : : format ( " WARNING! Cannot check for monster type name {}! Does not exist! " , monsterName ) ) ;
if ( ! MONSTER_DATA . count ( std : : string ( monsterName ) ) ) ERR ( std : : format ( " WARNING! Cannot check for monster type name {}! Does not exist! " , monsterName ) ) ;
HurtList hitList ;
HurtList hitList ;
for ( std : : unique _ptr< Monster > & m : MONSTER_LIST ) {
for ( std : : shared _ptr< Monster > & m : MONSTER_LIST ) {
const bool InRange = geom2d : : overlaps ( geom2d : : circle ( pos , radius ) , geom2d : : circle ( m - > GetPos ( ) , m - > GetCollisionRadius ( ) ) ) ;
const bool InRange = geom2d : : overlaps ( geom2d : : circle ( pos , radius ) , geom2d : : circle ( m - > GetPos ( ) , m - > GetCollisionRadius ( ) ) ) ;
if ( m - > GetName ( ) = = monsterName & & InRange ) {
if ( m - > GetName ( ) = = monsterName & & InRange ) {
HurtReturnValue returnVal = m - > Hurt ( damage , upperLevel , z , hurtFlags ) ;
HurtReturnValue returnVal = m - > Hurt ( damage , upperLevel , z , hurtFlags ) ;
@ -774,7 +774,7 @@ const HurtList AiL::HurtConeNotHit(vf2d pos,float radius,float angle,float sweep
const bool CheckForPlayerCollisions = hurtTargets & HurtType : : PLAYER ;
const bool CheckForPlayerCollisions = hurtTargets & HurtType : : PLAYER ;
if ( CheckForMonsterCollisions ) {
if ( CheckForMonsterCollisions ) {
for ( std : : unique _ptr< Monster > & m : MONSTER_LIST ) {
for ( std : : shared _ptr< Monster > & m : MONSTER_LIST ) {
if ( ! hitList . count ( & * m ) & & geom2d : : overlaps ( geom2d : : circle ( pos , radius ) , geom2d : : circle ( m - > GetPos ( ) , 12 * m - > GetSizeMult ( ) ) ) ) {
if ( ! hitList . count ( & * m ) & & geom2d : : overlaps ( geom2d : : circle ( pos , radius ) , geom2d : : circle ( m - > GetPos ( ) , 12 * m - > GetSizeMult ( ) ) ) ) {
float angleToMonster = geom2d : : line < float > { pos , m - > GetPos ( ) } . vector ( ) . polar ( ) . y ;
float angleToMonster = geom2d : : line < float > { pos , m - > GetPos ( ) } . vector ( ) . polar ( ) . y ;
float angleDiff = util : : angle_difference ( angleToMonster , angle ) ;
float angleDiff = util : : angle_difference ( angleToMonster , angle ) ;
@ -806,7 +806,7 @@ const HurtList AiL::HurtNotHit(vf2d pos,float radius,int damage,HitList&hitList,
const bool CheckForPlayerCollisions = hurtTargets & HurtType : : PLAYER ;
const bool CheckForPlayerCollisions = hurtTargets & HurtType : : PLAYER ;
if ( CheckForMonsterCollisions ) {
if ( CheckForMonsterCollisions ) {
for ( std : : unique _ptr< Monster > & m : MONSTER_LIST ) {
for ( std : : shared _ptr< Monster > & m : MONSTER_LIST ) {
if ( ! hitList . count ( & * m ) & & geom2d : : overlaps ( geom2d : : circle ( pos , radius ) , geom2d : : circle ( m - > GetPos ( ) , 12 * m - > GetSizeMult ( ) ) ) ) {
if ( ! hitList . count ( & * m ) & & geom2d : : overlaps ( geom2d : : circle ( pos , radius ) , geom2d : : circle ( m - > GetPos ( ) , 12 * m - > GetSizeMult ( ) ) ) ) {
HurtReturnValue returnVal = m - > Hurt ( damage , upperLevel , z , hurtFlags ) ;
HurtReturnValue returnVal = m - > Hurt ( damage , upperLevel , z , hurtFlags ) ;
affectedList . push_back ( { & * m , returnVal } ) ;
affectedList . push_back ( { & * m , returnVal } ) ;
@ -828,7 +828,7 @@ void AiL::ProximityKnockback(const vf2d pos,const float radius,const float knock
const bool CheckForMonsterCollisions = knockbackTargets & HurtType : : MONSTER ;
const bool CheckForMonsterCollisions = knockbackTargets & HurtType : : MONSTER ;
const bool CheckForPlayerCollisions = knockbackTargets & HurtType : : PLAYER ;
const bool CheckForPlayerCollisions = knockbackTargets & HurtType : : PLAYER ;
if ( CheckForMonsterCollisions ) {
if ( CheckForMonsterCollisions ) {
for ( std : : unique _ptr< Monster > & m : MONSTER_LIST ) {
for ( std : : shared _ptr< Monster > & m : MONSTER_LIST ) {
if ( geom2d : : overlaps ( geom2d : : circle ( pos , radius ) , geom2d : : circle ( m - > GetPos ( ) , 12 * m - > GetSizeMult ( ) ) ) ) {
if ( geom2d : : overlaps ( geom2d : : circle ( pos , radius ) , geom2d : : circle ( m - > GetPos ( ) , 12 * m - > GetSizeMult ( ) ) ) ) {
m - > ProximityKnockback ( pos , knockbackAmt ) ;
m - > ProximityKnockback ( pos , knockbackAmt ) ;
}
}
@ -881,7 +881,7 @@ void AiL::PopulateRenderLists(){
Player * pl = GetPlayer ( ) ;
Player * pl = GetPlayer ( ) ;
pl - > rendered = false ;
pl - > rendered = false ;
std : : sort ( MONSTER_LIST . begin ( ) , MONSTER_LIST . end ( ) , [ ] ( std : : unique _ptr< Monster > & m1 , std : : unique _ptr< Monster > & m2 ) { return m1 - > GetPos ( ) . y < m2 - > GetPos ( ) . y ; } ) ;
std : : sort ( MONSTER_LIST . begin ( ) , MONSTER_LIST . end ( ) , [ ] ( std : : shared _ptr< Monster > & m1 , std : : shared _ptr< Monster > & m2 ) { return m1 - > GetPos ( ) . y < m2 - > GetPos ( ) . y ; } ) ;
std : : sort ( ItemDrop : : drops . begin ( ) , ItemDrop : : drops . end ( ) , [ ] ( ItemDrop & id1 , ItemDrop & id2 ) { return id1 . GetPos ( ) . y < id2 . GetPos ( ) . y ; } ) ;
std : : sort ( ItemDrop : : drops . begin ( ) , ItemDrop : : drops . end ( ) , [ ] ( ItemDrop & id1 , ItemDrop & id2 ) { return id1 . GetPos ( ) . y < id2 . GetPos ( ) . y ; } ) ;
std : : sort ( BULLET_LIST . begin ( ) , BULLET_LIST . end ( ) , [ ] ( std : : unique_ptr < IBullet > & b1 , std : : unique_ptr < IBullet > & b2 ) { return b1 - > pos . y < b2 - > pos . y ; } ) ;
std : : sort ( BULLET_LIST . begin ( ) , BULLET_LIST . end ( ) , [ ] ( std : : unique_ptr < IBullet > & b1 , std : : unique_ptr < IBullet > & b2 ) { return b1 - > pos . y < b2 - > pos . y ; } ) ;
std : : sort ( foregroundEffects . begin ( ) , foregroundEffects . end ( ) , [ ] ( std : : unique_ptr < Effect > & e1 , std : : unique_ptr < Effect > & e2 ) { return e1 - > pos . y < e2 - > pos . y ; } ) ;
std : : sort ( foregroundEffects . begin ( ) , foregroundEffects . end ( ) , [ ] ( std : : unique_ptr < Effect > & e1 , std : : unique_ptr < Effect > & e2 ) { return e1 - > pos . y < e2 - > pos . y ; } ) ;
@ -1035,8 +1035,6 @@ void AiL::RenderWorld(float fElapsedTime){
if ( attackBuffs . size ( ) > 0 ) playerCol = { 255 , uint8_t ( 255 * abs ( sin ( 1.4f * attackBuffs [ 0 ] . duration ) ) ) , uint8_t ( 255 * abs ( sin ( 1.4f * attackBuffs [ 0 ] . duration ) ) ) } ;
if ( attackBuffs . size ( ) > 0 ) playerCol = { 255 , uint8_t ( 255 * abs ( sin ( 1.4f * attackBuffs [ 0 ] . duration ) ) ) , uint8_t ( 255 * abs ( sin ( 1.4f * attackBuffs [ 0 ] . duration ) ) ) } ;
else if ( adrenalineRushBuffs . size ( ) > 0 ) playerCol = { uint8_t ( 255 * abs ( sin ( 6.f * adrenalineRushBuffs [ 0 ] . duration ) ) ) , 255 , uint8_t ( 255 * abs ( sin ( 6.f * adrenalineRushBuffs [ 0 ] . duration ) ) ) } ;
else if ( adrenalineRushBuffs . size ( ) > 0 ) playerCol = { uint8_t ( 255 * abs ( sin ( 6.f * adrenalineRushBuffs [ 0 ] . duration ) ) ) , 255 , uint8_t ( 255 * abs ( sin ( 6.f * adrenalineRushBuffs [ 0 ] . duration ) ) ) } ;
else if ( movespeedBuffs . size ( ) > 0 ) playerCol = { uint8_t ( 255 * abs ( sin ( 2.f * movespeedBuffs [ 0 ] . duration ) ) ) , 255 , uint8_t ( 255 * abs ( sin ( 2.f * movespeedBuffs [ 0 ] . duration ) ) ) } ;
else if ( movespeedBuffs . size ( ) > 0 ) playerCol = { uint8_t ( 255 * abs ( sin ( 2.f * movespeedBuffs [ 0 ] . duration ) ) ) , 255 , uint8_t ( 255 * abs ( sin ( 2.f * movespeedBuffs [ 0 ] . duration ) ) ) } ;
if ( player - > IsUsingAdditiveBlending ( ) ) SetDecalMode ( DecalMode : : ADDITIVE ) ;
else SetDecalMode ( DecalMode : : NORMAL ) ;
view . DrawPartialSquishedRotatedDecal ( pos + vf2d { 0 , - player - > GetZ ( ) * ( std : : signbit ( scale . y ) ? - 1 : 1 ) } , player - > GetFrame ( ) . GetSourceImage ( ) - > Decal ( ) , player - > GetSpinAngle ( ) , { 12 , 12 } , player - > GetFrame ( ) . GetSourceRect ( ) . pos , player - > GetFrame ( ) . GetSourceRect ( ) . size , playerScale * scale , { 1.f , player - > ySquishFactor } , playerCol ) ;
view . DrawPartialSquishedRotatedDecal ( pos + vf2d { 0 , - player - > GetZ ( ) * ( std : : signbit ( scale . y ) ? - 1 : 1 ) } , player - > GetFrame ( ) . GetSourceImage ( ) - > Decal ( ) , player - > GetSpinAngle ( ) , { 12 , 12 } , player - > GetFrame ( ) . GetSourceRect ( ) . pos , player - > GetFrame ( ) . GetSourceRect ( ) . size , playerScale * scale , { 1.f , player - > ySquishFactor } , playerCol ) ;
SetDecalMode ( DecalMode : : NORMAL ) ;
SetDecalMode ( DecalMode : : NORMAL ) ;
if ( player - > GetState ( ) = = State : : BLOCK ) {
if ( player - > GetState ( ) = = State : : BLOCK ) {
@ -1104,7 +1102,7 @@ void AiL::RenderWorld(float fElapsedTime){
multiplierX * = ( 1 - abs ( cos ( 1.5f * reflectionStepTime ) ) * " water_reflection_scale_factor " _F ) ;
multiplierX * = ( 1 - abs ( cos ( 1.5f * reflectionStepTime ) ) * " water_reflection_scale_factor " _F ) ;
float reflectionRatioX = abs ( sin ( reflectionStepTime ) ) * " water_reflection_scale_factor " _F ;
float reflectionRatioX = abs ( sin ( reflectionStepTime ) ) * " water_reflection_scale_factor " _F ;
RenderPlayer ( player - > GetPos ( ) + vf2d { reflectionRatioX * player - > GetFrame ( ) . GetSourceRect ( ) . size . x , float ( player - > GetFrame ( ) . GetSourceRect ( ) . size . y ) - 8 } * player - > GetSizeMult ( ) , { multiplierX , - 1 } ) ;
RenderPlayer ( player - > GetPos ( ) + vf2d { reflectionRatioX * player - > GetFrame ( ) . GetSourceRect ( ) . size . x , float ( player - > GetFrame ( ) . GetSourceRect ( ) . size . y ) - 8 } * player - > GetSizeMult ( ) , { multiplierX , - 1 } ) ;
for ( std : : unique _ptr< Monster > & m : MONSTER_LIST ) {
for ( std : : shared _ptr< Monster > & m : MONSTER_LIST ) {
m - > DrawReflection ( reflectionRatioX , multiplierX ) ;
m - > DrawReflection ( reflectionRatioX , multiplierX ) ;
}
}
SetDecalMode ( DecalMode : : NORMAL ) ;
SetDecalMode ( DecalMode : : NORMAL ) ;
@ -1373,6 +1371,8 @@ void AiL::RenderWorld(float fElapsedTime){
vf2d shadowScale = vf2d { 8 * player - > GetSizeMult ( ) / 3.f , 1 } / std : : max ( 1.f , player - > GetZ ( ) / 24 ) ;
vf2d shadowScale = vf2d { 8 * player - > GetSizeMult ( ) / 3.f , 1 } / std : : max ( 1.f , player - > GetZ ( ) / 24 ) ;
view . DrawDecal ( player - > GetPos ( ) - vf2d { 3 , 3 } * shadowScale / 2 + vf2d { 0 , 6 * player - > GetSizeMult ( ) } , GFX [ " circle.png " ] . Decal ( ) , shadowScale , BLACK ) ;
view . DrawDecal ( player - > GetPos ( ) - vf2d { 3 , 3 } * shadowScale / 2 + vf2d { 0 , 6 * player - > GetSizeMult ( ) } , GFX [ " circle.png " ] . Decal ( ) , shadowScale , BLACK ) ;
}
}
if ( player - > IsUsingAdditiveBlending ( ) ) SetDecalMode ( DecalMode : : ADDITIVE ) ;
else SetDecalMode ( DecalMode : : NORMAL ) ;
RenderPlayer ( player - > GetPos ( ) , { 1 , 1 } ) ;
RenderPlayer ( player - > GetPos ( ) , { 1 , 1 } ) ;
}
}
while ( monstersAfterLowerIt ! = monstersAfterLower . end ( ) ) {
while ( monstersAfterLowerIt ! = monstersAfterLower . end ( ) ) {
@ -1810,7 +1810,7 @@ void AiL::RenderWorld(float fElapsedTime){
}
}
# pragma endregion
# pragma endregion
for ( std : : unique _ptr< Monster > & m : MONSTER_LIST ) {
for ( std : : shared _ptr< Monster > & m : MONSTER_LIST ) {
m - > strategyDrawOverlay ( this , * m , MONSTER_DATA [ m - > GetName ( ) ] . GetAIStrategy ( ) ) ;
m - > strategyDrawOverlay ( this , * m , MONSTER_DATA [ m - > GetName ( ) ] . GetAIStrategy ( ) ) ;
}
}
@ -4225,7 +4225,7 @@ rcode AiL::LoadResource(Renderable&renderable,std::string_view imgPath,bool filt
}
}
void AiL : : UpdateMonsters ( ) {
void AiL : : UpdateMonsters ( ) {
for ( std : : unique _ptr< Monster > & m : MONSTER_LIST ) {
for ( std : : shared _ptr< Monster > & m : MONSTER_LIST ) {
if ( m - > markedForDeletion ) {
if ( m - > markedForDeletion ) {
AMonsterIsMarkedForDeletion ( ) ;
AMonsterIsMarkedForDeletion ( ) ;
continue ;
continue ;
@ -4234,13 +4234,10 @@ void AiL::UpdateMonsters(){
}
}
for ( Monster & m : game - > monstersToBeSpawned ) {
for ( Monster & m : game - > monstersToBeSpawned ) {
size_t prevCapacity = MONSTER_LIST . capacity ( ) ;
size_t prevCapacity = MONSTER_LIST . capacity ( ) ;
MONSTER_LIST . push _back( std : : make_unique < Monster > ( m ) ) ;
MONSTER_LIST . emplace _back( std : : make_shared < 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 ( 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 ) {
if ( aMonsterIsMarkedForDeletion ) std : : erase_if ( MONSTER_LIST , [ & ] ( const std : : shared_ptr < Monster > & m ) { return m - > markedForDeletion ; } ) ;
if ( m - > markedForDeletion ) std : : erase_if ( lockOnTargets , [ & ] ( std : : tuple < Monster * , StackCount , MarkTime > markData ) { return std : : get < 0 > ( markData ) = = & * m ; } ) ; //Marked targets may have dangling pointers, remove them before removing the monsters for good.
return m - > markedForDeletion ;
} ) ;
aMonsterIsMarkedForDeletion = false ;
aMonsterIsMarkedForDeletion = false ;
game - > monstersToBeSpawned . clear ( ) ;
game - > monstersToBeSpawned . clear ( ) ;
}
}
@ -4300,11 +4297,13 @@ void AiL::GlobalGameUpdates(){
lastLockOnTargetTime = std : : max ( 0.f , lastLockOnTargetTime - GetElapsedTime ( ) ) ;
lastLockOnTargetTime = std : : max ( 0.f , lastLockOnTargetTime - GetElapsedTime ( ) ) ;
if ( lastLockOnTargetTime < = 0.f ) {
if ( lastLockOnTargetTime < = 0.f ) {
const auto & [ monster , stackCount , time ] = lockOnTargets . front ( ) ;
const auto & [ monster , stackCount , time ] = lockOnTargets . front ( ) ;
monster - > AddBuff ( BuffType : : TRAPPER_MARK , time , stackCount ) ;
if ( ! monster . expired ( ) ) {
SoundEffect : : PlaySFX ( " Lock On " , monster - > GetPos ( ) ) ;
monster . lock ( ) - > AddBuff ( BuffType : : TRAPPER_MARK , time , stackCount ) ;
lockOnTargets . erase ( lockOnTargets . begin ( ) ) ;
SoundEffect : : PlaySFX ( " Lock On " , monster . lock ( ) - > GetPos ( ) ) ;
lastLockOnTargetTime = 0.2f ;
lastLockOnTargetTime = 0.2f ;
}
}
lockOnTargets . erase ( lockOnTargets . begin ( ) ) ;
}
}
}
# pragma endregion
# pragma endregion
@ -4435,6 +4434,6 @@ const std::map<std::string,TilesetData>&AiL::GetTilesets()const{
return MAP_TILESETS ;
return MAP_TILESETS ;
}
}
void AiL : : AddToMarkedTargetList ( std : : tuple < Monster * , StackCount , MarkTime > markData ) {
void AiL : : AddToMarkedTargetList ( std : : tuple < std : : weak_ptr < Monster > , StackCount , MarkTime > markData ) {
lockOnTargets . emplace_back ( markData ) ;
lockOnTargets . emplace_back ( markData ) ;
}
}