@ -26,6 +26,7 @@ std::vector<Monster>MONSTER_LIST;
std : : vector < MonsterSpawner > SPAWNER_LIST ;
std : : vector < std : : shared_ptr < DamageNumber > > DAMAGENUMBER_LIST ;
std : : vector < std : : unique_ptr < Bullet > > BULLET_LIST ;
safemap < std : : string , Renderable > GFX ;
safemap < std : : string , MapName > LEVEL_NAMES ;
utils : : datafile DATA ;
Crawler * game ;
@ -62,6 +63,8 @@ Crawler::Crawler()
std : : string MONSTERSTRATEGIES_CONFIG = CONFIG_PATH + " monsterstrategies_config " _S ;
utils : : datafile : : Read ( DATA , MONSTERSTRATEGIES_CONFIG ) ;
DEBUG_PATHFINDING = " debug_pathfinding " _I ;
for ( std : : string & cl : DATA . GetProperty ( " class_list " ) . GetValues ( ) ) {
std : : cout < < cl < < std : : endl ;
utils : : datafile : : Read ( DATA , CONFIG_PATH + " class_directory " _S + cl + " .txt " ) ;
@ -70,7 +73,6 @@ Crawler::Crawler()
}
bool Crawler : : OnUserCreate ( ) {
InitializeLevels ( ) ;
player = std : : make_unique < Warrior > ( ) ;
@ -82,41 +84,18 @@ bool Crawler::OnUserCreate(){
camera . SetWorldBoundary ( { 0 , 0 } , WORLD_SIZE * 24 ) ;
camera . EnableWorldBoundary ( false ) ;
# undef LoadImage //Dumb Windows.
auto LoadImage = [ & ] ( Renderable & r , std : : string key ) {
r . Load ( GetString ( " GFX_Prefix " ) + GetString ( key ) ) ;
} ;
# define LOADIMG(name) LoadImage(name,"Images."#name);
//Graphics
LOADIMG ( GFX_Warrior_Sheet )
LOADIMG ( GFX_Circle )
LOADIMG ( GFX_Effect_GroundSlam_Back )
LOADIMG ( GFX_Effect_GroundSlam_Front )
LOADIMG ( GFX_Heart )
LOADIMG ( GFX_BLOCK_BUBBLE )
LOADIMG ( GFX_Ranger_Sheet )
LOADIMG ( GFX_Wizard_Sheet )
LOADIMG ( GFX_Battlecry_Effect )
LOADIMG ( GFX_Mana )
LOADIMG ( GFX_SonicSlash )
LOADIMG ( GFX_BulletCircle )
LOADIMG ( GFX_BulletCircleOutline )
LOADIMG ( GFX_EnergyBolt )
LOADIMG ( GFX_EnergyParticle )
LOADIMG ( GFX_Splash_Effect )
LOADIMG ( GFX_LightningBolt )
LOADIMG ( GFX_LightningBoltParticle1 )
LOADIMG ( GFX_LightningBoltParticle2 )
LOADIMG ( GFX_LightningBoltParticle3 )
LOADIMG ( GFX_LightningBoltParticle4 )
LOADIMG ( GFX_ChainLightning )
LOADIMG ( GFX_LightningSplash )
LOADIMG ( GFX_Meteor )
LOADIMG ( GFX_Arrow )
LOADIMG ( GFX_Laser )
LOADIMG ( GFX_ChargedArrow )
LOADIMG ( GFX_RangeIndicator )
for ( auto & val : DATA [ " Images " ] . GetKeys ( ) ) {
std : : string key = val . first ;
std : : string imgFile = DATA [ " Images " ] [ key ] . GetString ( ) ;
std : : cout < < " Loading image " + imgFile + " ... " < < std : : endl ;
GFX [ imgFile ] ;
if ( GFX [ imgFile ] . Load ( " GFX_Prefix " _S + imgFile ) ! = rcode : : OK ) {
std : : cout < < " WARNING! Failed to load " + imgFile + " ! " ;
throw ;
}
}
GFX . SetInitialized ( ) ;
std : : cout < < GFX . size ( ) < < " images have been loaded. " < < std : : endl ;
Monster : : InitializeStrategies ( ) ;
//Animations
@ -130,18 +109,22 @@ bool Crawler::OnUserCreate(){
InitializeClasses ( ) ;
ChangePlayerClass ( WARRIOR ) ;
Warrior : : ability4 = Ranger : : ability1 ; //Class ability swapping demonstration.
return true ;
}
bool Crawler : : OnUserUpdate ( float fElapsedTime ) {
fElapsedTime = std : : clamp ( fElapsedTime , 0.f , 1 / 60.f ) ; //HACK fix. We can't have a negative time. Although using a more precise system clock should make this never occur. Also make sure if the game is too slow we advance by only 1/60th of a second.
fElapsedTime = std : : clamp ( fElapsedTime , 0.f , 1 / 30.f ) ; //HACK fix. We can't have a negative time. Although using a more precise system clock should make this never occur. Also make sure if the game is too slow we advance by only 1/30th of a second.
levelTime + = fElapsedTime ;
HandleUserInput ( fElapsedTime ) ;
UpdateEffects ( fElapsedTime ) ;
player - > Update ( fElapsedTime ) ;
for ( Monster & m : MONSTER_LIST ) {
m . Update ( fElapsedTime ) ;
}
for ( Monster & m : monstersToBeSpawned ) {
MONSTER_LIST . push_back ( m ) ;
}
monstersToBeSpawned . clear ( ) ;
UpdateBullets ( fElapsedTime ) ;
UpdateCamera ( fElapsedTime ) ;
RenderWorld ( fElapsedTime ) ;
@ -212,8 +195,8 @@ void Crawler::HandleUserInput(float fElapsedTime){
int truncatedPlayerY = int ( player - > GetY ( ) ) / 24 ;
int tileID = layer . tiles [ truncatedPlayerY ] [ truncatedPlayerX ] ;
TilesheetData dat = GetTileSheet ( GetCurrentLevel ( ) , tileID ) ;
if ( dat . tileset . staircaseTiles . find ( tileID ) ! = dat . tileset . staircaseTiles . end ( ) ) {
return dat . tileset . staircaseTiles [ tileID ] . data [ " value " ] ;
if ( dat . tileset - > staircaseTiles . find ( tileID ) ! = dat . tileset - > staircaseTiles . end ( ) ) {
return dat . tileset - > staircaseTiles [ tileID ] . data [ " value " ] ;
}
}
return std : : string ( " NONE " ) ;
@ -399,6 +382,7 @@ void Crawler::UpdateEffects(float fElapsedTime){
std : : erase_if ( EMITTER_LIST , [ ] ( std : : unique_ptr < Emitter > & e ) { return e - > dead ; } ) ;
std : : erase_if ( backgroundEffects , [ ] ( std : : unique_ptr < Effect > & e ) { return e - > dead ; } ) ;
std : : erase_if ( foregroundEffects , [ ] ( std : : unique_ptr < Effect > & e ) { return e - > dead ; } ) ;
std : : erase_if ( DAMAGENUMBER_LIST , [ ] ( std : : shared_ptr < DamageNumber > & n ) { return n - > lifeTime > 1 ; } ) ;
for ( auto it = foregroundEffectsToBeInserted . begin ( ) ; it ! = foregroundEffectsToBeInserted . end ( ) ; + + it ) {
foregroundEffects . push_back ( std : : move ( * it ) ) ;
@ -417,13 +401,10 @@ void Crawler::UpdateBullets(float fElapsedTime){
b - > animation . UpdateState ( b - > internal_animState , fElapsedTime ) ;
if ( ! b - > deactivated ) {
float totalDistance = ( b - > vel * fElapsedTime ) . mag ( ) ;
vf2d moveStep = b - > vel * fElapsedTime ;
if ( ( b - > vel * fElapsedTime ) . mag ( ) > 1 ) {
moveStep = ( b - > vel * fElapsedTime ) . norm ( ) ;
}
while ( totalDistance > 0 ) {
totalDistance = std : : max ( 0.f , totalDistance - 1 ) ;
b - > pos + = moveStep ;
int iterations = std : : max ( 1.f , ( b - > vel * fElapsedTime ) . mag ( ) ) ;
int totalIterations = iterations ;
vf2d finalBulletPos = b - > pos + b - > vel * fElapsedTime ;
const auto CollisionCheck = [ & ] ( ) {
if ( b - > friendly ) {
for ( Monster & m : MONSTER_LIST ) {
if ( geom2d : : overlaps ( geom2d : : circle ( m . GetPos ( ) , 12 * m . GetSizeMult ( ) ) , geom2d : : circle ( b - > pos , b - > radius ) ) ) {
@ -431,7 +412,7 @@ void Crawler::UpdateBullets(float fElapsedTime){
if ( ! b - > hitsMultiple ) {
if ( b - > MonsterHit ( m ) ) {
b - > dead = true ;
continu e;
return fals e;
}
}
b - > hitList [ & m ] = true ;
@ -443,13 +424,26 @@ void Crawler::UpdateBullets(float fElapsedTime){
if ( player - > Hurt ( b - > damage , b - > OnUpperLevel ( ) , 0 ) ) {
if ( b - > PlayerHit ( player . get ( ) ) ) {
b - > dead = true ;
continu e;
return fals e;
}
}
}
}
return true ;
} ;
while ( iterations > 0 ) {
iterations - - ;
b - > pos + = ( b - > vel * fElapsedTime ) / float ( totalIterations ) ;
if ( ! CollisionCheck ( ) ) {
goto nextBullet ;
}
}
} else {
b - > pos = finalBulletPos ;
if ( ! CollisionCheck ( ) ) {
goto nextBullet ;
}
} else {
b - > pos + = b - > vel * fElapsedTime ;
}
if ( b - > pos . x + b - > radius < view . GetWorldTL ( ) . x - WINDOW_SIZE . x | | b - > pos . x - b - > radius > view . GetWorldBR ( ) . x + WINDOW_SIZE . x | | b - > pos . y + b - > radius < view . GetWorldTL ( ) . y - WINDOW_SIZE . y | | b - > pos . y - b - > radius > view . GetWorldBR ( ) . y + WINDOW_SIZE . y ) {
@ -461,6 +455,8 @@ void Crawler::UpdateBullets(float fElapsedTime){
b - > dead = true ;
continue ;
}
nextBullet :
int a ;
}
outsideBulletLoop :
std : : erase_if ( BULLET_LIST , [ ] ( std : : unique_ptr < Bullet > & b ) { return b - > dead ; } ) ;
@ -473,7 +469,18 @@ void Crawler::HurtEnemies(vf2d pos,float radius,int damage,bool upperLevel,float
}
}
void Crawler : : PopulateRenderLists ( std : : vector < Monster * > & monstersBeforeLower , std : : vector < Monster * > & monstersBeforeUpper , std : : vector < Monster * > & monstersAfterLower , std : : vector < Monster * > & monstersAfterUpper , std : : vector < Bullet * > & bulletsLower , std : : vector < Bullet * > & bulletsUpper , std : : vector < Effect * > & backgroundEffectsLower , std : : vector < Effect * > & backgroundEffectsUpper , std : : vector < Effect * > & foregroundEffectsLower , std : : vector < Effect * > & foregroundEffectsUpper ) {
void Crawler : : PopulateRenderLists ( ) {
monstersBeforeLower . clear ( ) ;
monstersAfterLower . clear ( ) ;
monstersBeforeUpper . clear ( ) ;
monstersAfterUpper . clear ( ) ;
bulletsLower . clear ( ) ;
bulletsUpper . clear ( ) ;
backgroundEffectsLower . clear ( ) ;
backgroundEffectsUpper . clear ( ) ;
foregroundEffectsLower . clear ( ) ;
foregroundEffectsUpper . clear ( ) ;
Player * pl = GetPlayer ( ) ;
for ( auto it = MONSTER_LIST . begin ( ) ; it ! = MONSTER_LIST . end ( ) ; + + it ) {
Monster & m = * it ;
@ -521,49 +528,157 @@ void Crawler::PopulateRenderLists(std::vector<Monster*>&monstersBeforeLower,std:
std : : sort ( monstersAfterLower . begin ( ) , monstersAfterLower . end ( ) , [ ] ( Monster * m1 , Monster * m2 ) { return m1 - > GetPos ( ) . y < m2 - > GetPos ( ) . y ; } ) ;
}
void Crawler : : RenderTile ( vi2d pos , TilesheetData tileSheet , int tileSheetIndex , vi2d tileSheetPos ) {
if ( tileSheet . tileset - > animationData . count ( tileSheetIndex ) ) {
int animationDuration_ms = tileSheet . tileset - > animationData [ tileSheetIndex ] . size ( ) * " animation_tile_precision " _I ;
int animatedIndex = tileSheet . tileset - > animationData [ tileSheetIndex ] [ int ( fmod ( levelTime * 1000 , animationDuration_ms ) / " animation_tile_precision " _I ) ] ;
int tileSheetWidth = tileSheet . tileset - > tileset - > Sprite ( ) - > width / 24 ;
int tileSheetX = animatedIndex % tileSheetWidth ;
int tileSheetY = animatedIndex / tileSheetWidth ;
view . DrawPartialDecal ( pos * 24 , { 24 , 24 } , tileSheet . tileset - > tileset - > Decal ( ) , vi2d { tileSheetX , tileSheetY } * 24 , { 24 , 24 } ) ;
} else {
view . DrawPartialDecal ( pos * 24 , { 24 , 24 } , tileSheet . tileset - > tileset - > Decal ( ) , tileSheetPos * 24 , { 24 , 24 } ) ;
}
}
void Crawler : : RenderTile ( TileRenderData & tileSheet , Pixel col ) {
if ( tileSheet . tileSheet . tileset - > animationData . count ( tileSheet . tileID % 1000000 ) ) {
int animationDuration_ms = tileSheet . tileSheet . tileset - > animationData [ tileSheet . tileID % 1000000 ] . size ( ) * " animation_tile_precision " _I ;
int animatedIndex = tileSheet . tileSheet . tileset - > animationData [ tileSheet . tileID % 1000000 ] [ int ( fmod ( levelTime * 1000 , animationDuration_ms ) / " animation_tile_precision " _I ) ] ;
int tileSheetWidth = tileSheet . tileSheet . tileset - > tileset - > Sprite ( ) - > width / 24 ;
int tileSheetX = animatedIndex % tileSheetWidth ;
int tileSheetY = animatedIndex / tileSheetWidth ;
view . DrawPartialDecal ( tileSheet . pos , { 24 , 24 } , tileSheet . tileSheet . tileset - > tileset - > Decal ( ) , vi2d { tileSheetX , tileSheetY } , { 24 , 24 } , col ) ;
} else {
view . DrawPartialDecal ( tileSheet . pos , { 24 , 24 } , tileSheet . tileSheet . tileset - > tileset - > Decal ( ) , tileSheet . tileSheetPos , { 24 , 24 } , col ) ;
}
}
void Crawler : : RenderWorld ( float fElapsedTime ) {
Clear ( { 100 , 180 , 100 } ) ;
Clear ( BLANK ) ;
LayerTag * bridgeLayer = nullptr ;
bool bridgeLayerFade = false ;
Player * pl = GetPlayer ( ) ;
PopulateRenderLists ( ) ;
auto RenderPlayer = [ & ] ( vf2d pos , vf2d scale ) {
vf2d playerScale = vf2d ( player - > GetSizeMult ( ) , player - > GetSizeMult ( ) ) ;
int count = 0 ;
for ( vf2d & pos : player - > ghostPositions ) {
view . DrawPartialRotatedDecal ( pos , player - > GetFrame ( ) . GetSourceImage ( ) - > Decal ( ) , player - > GetSpinAngle ( ) , { 12 , 12 } , player - > GetFrame ( ) . GetSourceRect ( ) . pos , player - > GetFrame ( ) . GetSourceRect ( ) . size , playerScale , { 0 , 0 , 0 , uint8_t ( float ( count ) / player - > RETREAT_GHOST_FRAMES * 255 ) } ) ;
count + + ;
}
if ( player - > teleportAnimationTimer > 0 ) {
playerScale . x = 120 * abs ( pow ( player - > teleportAnimationTimer - 0.175 , 3 ) ) ;
pos = player - > teleportStartPosition . lerp ( player - > teleportTarget , ( 0.35 - player - > teleportAnimationTimer ) / 0.35 ) ;
}
view . DrawPartialRotatedDecal ( 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 , player - > GetBuffs ( BuffType : : ATTACK_UP ) . size ( ) > 0 ? Pixel { 255 , uint8_t ( 255 * abs ( sin ( 1.4 * player - > GetBuffs ( BuffType : : ATTACK_UP ) [ 0 ] . duration ) ) ) , uint8_t ( 255 * abs ( sin ( 1.4 * player - > GetBuffs ( BuffType : : ATTACK_UP ) [ 0 ] . duration ) ) ) } : WHITE ) ;
} ;
enum class RenderMode {
REFLECTIVE_TILES ,
NORMAL_TILES ,
EMPTY_TILES ,
} ;
reflectionUpdateTimer - = fElapsedTime ;
if ( reflectionUpdateTimer < = 0 ) {
reflectionStepTime + = " water_reflection_time_step " _F ;
reflectionUpdateTimer = " water_reflection_update_time " _F ;
}
# pragma region Basic Tile Layer Rendering
for ( RenderMode mode = RenderMode : : REFLECTIVE_TILES ; mode < = RenderMode : : EMPTY_TILES ; mode = RenderMode ( int ( mode ) + 1 ) ) {
if ( mode = = RenderMode : : NORMAL_TILES ) {
SetDecalMode ( DecalMode : : ADDITIVE ) ;
float reflectionHeight = ( float ( player - > GetFrame ( ) . GetSourceRect ( ) . size . y ) - 8 ) * player - > GetSizeMult ( ) ;
float reflectionBottom = player - > GetPos ( ) . y + reflectionHeight ;
float cutOff = reflectionBottom - WORLD_SIZE . y * 24 ;
float multiplierX = 0.9 ;
multiplierX * = ( 1 - abs ( sin ( reflectionStepTime ) ) * " water_reflection_scale_factor " _F ) ;
multiplierX * = ( 1 - abs ( cos ( 1.5 * 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 } ) ;
for ( Monster & m : MONSTER_LIST ) {
m . DrawReflection ( reflectionRatioX , multiplierX ) ;
}
SetDecalMode ( DecalMode : : NORMAL ) ;
}
for ( int x = view . GetTopLeftTile ( ) . x / 24 - 1 ; x < = view . GetBottomRightTile ( ) . x / 24 ; x + + ) {
for ( int y = view . GetTopLeftTile ( ) . y / 24 - 1 ; y < = view . GetBottomRightTile ( ) . y / 24 ; y + + ) {
if ( x > = 0 & & x < WORLD_SIZE . x & & y > = 0 & & y < WORLD_SIZE . y ) {
for ( LayerTag & layer : MAP_DATA [ currentLevel ] . LayerData ) {
if ( IsBridgeLayer ( layer ) ) {
bridgeLayer = & layer ;
if ( ! bridgeLayerFade & & ! player - > upperLevel ) {
switch ( mode ) {
case RenderMode : : NORMAL_TILES : {
for ( LayerTag & layer : MAP_DATA [ currentLevel ] . LayerData ) {
if ( IsBridgeLayer ( layer ) ) {
bridgeLayer = & layer ;
if ( ! bridgeLayerFade & & ! player - > upperLevel ) {
int tileID = layer . tiles [ y ] [ x ] - 1 ;
if ( tileID ! = - 1 ) {
int playerXTruncated = int ( player - > GetPos ( ) . x ) / 24 ;
int playerYTruncated = int ( player - > GetPos ( ) . y ) / 24 ;
if ( playerXTruncated = = x & & playerYTruncated = = y ) {
bridgeLayerFade = true ;
}
}
}
continue ;
}
int tileID = layer . tiles [ y ] [ x ] - 1 ;
if ( tileID ! = - 1 ) {
int playerXTruncated = int ( player - > GetPos ( ) . x ) / 24 ;
int playerYTruncated = int ( player - > GetPos ( ) . y ) / 24 ;
if ( playerXTruncated = = x & & playerYTruncated = = y ) {
bridgeLayerFade = true ;
TilesheetData tileSheet = GetTileSheet ( currentLevel , tileID ) ;
int tileSheetWidth = tileSheet . tileset - > tileset - > Sprite ( ) - > width / 24 ;
int tileSheetHeight = tileSheet . tileset - > tileset - > Sprite ( ) - > height / 24 ;
int tileSheetIndex = tileID - ( tileSheet . firstgid - 1 ) ;
int tileSheetX = tileSheetIndex % tileSheetWidth ;
int tileSheetY = tileSheetIndex / tileSheetWidth ;
if ( ! IsForegroundTile ( tileSheet , tileSheetIndex ) & & ! IsUpperForegroundTile ( tileSheetIndex ) & & ! IsReflectiveTile ( tileSheet , tileSheetIndex ) ) {
if ( layer . tag . data [ " class " ] ! = " CollisionOnly " ) { visibleTiles . erase ( { x , y } ) ; }
RenderTile ( { x , y } , tileSheet , tileSheetIndex , { tileSheetX , tileSheetY } ) ;
}
if ( " debug_collision_boxes " _I ) {
if ( tileSheet . tileset - > collision . find ( tileSheetIndex ) ! = tileSheet . tileset - > collision . end ( ) ) {
geom2d : : rect < int > collision = tileSheet . tileset - > collision [ tileSheetIndex ] . collision ;
view . FillRectDecal ( vi2d { x , y } * 24 + collision . pos , collision . size , { 0 , 0 , 0 , 128 } ) ;
view . DrawRectDecal ( vi2d { x , y } * 24 + collision . pos , collision . size , GREY ) ;
}
}
}
}
continue ;
}
int tileID = layer . tiles [ y ] [ x ] - 1 ;
if ( tileID ! = - 1 ) {
TilesheetData tileSheet = GetTileSheet ( currentLevel , tileID ) ;
int tileSheetWidth = tileSheet . tileset . tileset - > Sprite ( ) - > width / 24 ;
int tileSheetHeight = tileSheet . tileset . tileset - > Sprite ( ) - > height / 24 ;
int tileSheetIndex = tileID - ( tileSheet . firstgid - 1 ) ;
int tileSheetX = tileSheetIndex % tileSheetWidth ;
int tileSheetY = tileSheetIndex / tileSheetWidth ;
if ( ! IsForegroundTile ( tileSheet , tileSheetIndex ) & & ! IsUpperForegroundTile ( tileSheet , tileSheetIndex ) ) {
view . DrawPartialDecal ( vi2d { x , y } * 24 , { 24 , 24 } , tileSheet . tileset . tileset - > Decal ( ) , vi2d { tileSheetX , tileSheetY } * 24 , { 24 , 24 } ) ;
}
if ( " debug_collision_boxes " _I ) {
if ( tileSheet . tileset . collision . find ( tileSheetIndex ) ! = tileSheet . tileset . collision . end ( ) ) {
geom2d : : rect < int > collision = tileSheet . tileset . collision [ tileSheetIndex ] . collision ;
view . FillRectDecal ( vi2d { x , y } * 24 + collision . pos , collision . size , { 0 , 0 , 0 , 128 } ) ;
view . DrawRectDecal ( vi2d { x , y } * 24 + collision . pos , collision . size , GREY ) ;
} break ;
case RenderMode : : REFLECTIVE_TILES : {
visibleTiles . insert ( { x , y } ) ;
for ( LayerTag & layer : MAP_DATA [ currentLevel ] . LayerData ) {
int tileID = layer . tiles [ y ] [ x ] - 1 ;
if ( tileID ! = - 1 ) {
TilesheetData tileSheet = GetTileSheet ( currentLevel , tileID ) ;
int tileSheetWidth = tileSheet . tileset - > tileset - > Sprite ( ) - > width / 24 ;
int tileSheetHeight = tileSheet . tileset - > tileset - > Sprite ( ) - > height / 24 ;
int tileSheetIndex = tileID - ( tileSheet . firstgid - 1 ) ;
int tileSheetX = tileSheetIndex % tileSheetWidth ;
int tileSheetY = tileSheetIndex / tileSheetWidth ;
if ( IsReflectiveTile ( tileSheet , tileSheetIndex ) ) {
if ( layer . tag . data [ " class " ] ! = " CollisionOnly " ) { visibleTiles . erase ( { x , y } ) ; }
RenderTile ( { x , y } , tileSheet , tileSheetIndex , { tileSheetX , tileSheetY } ) ;
}
if ( " debug_collision_boxes " _I ) {
if ( tileSheet . tileset - > collision . find ( tileSheetIndex ) ! = tileSheet . tileset - > collision . end ( ) ) {
geom2d : : rect < int > collision = tileSheet . tileset - > collision [ tileSheetIndex ] . collision ;
view . FillRectDecal ( vi2d { x , y } * 24 + collision . pos , collision . size , { 0 , 0 , 0 , 128 } ) ;
view . DrawRectDecal ( vi2d { x , y } * 24 + collision . pos , collision . size , GREY ) ;
}
}
}
}
}
} break ;
case RenderMode : : EMPTY_TILES : {
if ( visibleTiles . count ( { x , y } ) ) {
view . FillRectDecal ( vi2d { x , y } * 24 , { 24 , 24 } , { 100 , 180 , 100 } ) ;
}
} break ;
}
}
}
}
@ -572,18 +687,17 @@ void Crawler::RenderWorld(float fElapsedTime){
} else {
bridgeFadeFactor = std : : max ( bridgeFadeFactor - fElapsedTime , 0.f ) ;
}
}
# pragma endregion
//DrawDecal({0,0},MAP_TILESETS["assets/maps/"+MAP_DATA[LEVEL1].TilesetData[1].data["source"]]->Decal());
std : : vector < Monster * > monstersBeforeLower , monstersAfterLower , monstersBeforeUpper , monstersAfterUpper ;
std : : vector < Bullet * > bulletsLower , bulletsUpper ;
std : : vector < Effect * > backgroundEffectsLower , backgroundEffectsUpper , foregroundEffectsLower , foregroundEffectsUpper ;
Player * pl = GetPlayer ( ) ;
PopulateRenderLists ( monstersBeforeLower , monstersBeforeUpper , monstersAfterLower , monstersAfterUpper , bulletsLower , bulletsUpper , backgroundEffectsLower , backgroundEffectsUpper , foregroundEffectsLower , foregroundEffectsUpper ) ;
for ( Monster & m : MONSTER_LIST ) {
m . strategyDraw ( this ) ;
}
if ( player - > GetZ ( ) > 0 ) {
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 . Decal ( ) , shadowScale , BLACK ) ;
view . DrawDecal ( player - > GetPos ( ) - vf2d { 3 , 3 } * shadowScale / 2 + vf2d { 0 , 6 * player - > GetSizeMult ( ) } , GFX [ " circle.png " ] . Decal ( ) , shadowScale , BLACK ) ;
}
for ( Effect * e : backgroundEffectsLower ) {
e - > Draw ( ) ;
@ -591,28 +705,11 @@ void Crawler::RenderWorld(float fElapsedTime){
for ( Monster * m : monstersBeforeLower ) {
m - > Draw ( ) ;
}
vf2d playerScale = vf2d ( player - > GetSizeMult ( ) , player - > GetSizeMult ( ) ) ;
vf2d playerPosition = player - > GetPos ( ) ;
auto RenderPlayer = [ & ] ( ) {
int count = 0 ;
for ( vf2d & pos : player - > ghostPositions ) {
view . DrawPartialRotatedDecal ( pos , player - > GetFrame ( ) . GetSourceImage ( ) - > Decal ( ) , player - > GetSpinAngle ( ) , { 12 , 12 } , player - > GetFrame ( ) . GetSourceRect ( ) . pos , player - > GetFrame ( ) . GetSourceRect ( ) . size , playerScale , { 0 , 0 , 0 , uint8_t ( float ( count ) / player - > RETREAT_GHOST_FRAMES * 255 ) } ) ;
count + + ;
}
if ( player - > teleportAnimationTimer > 0 ) {
playerScale . x = 120 * abs ( pow ( player - > teleportAnimationTimer - 0.175 , 3 ) ) ;
playerPosition = player - > teleportStartPosition . lerp ( player - > teleportTarget , ( 0.35 - player - > teleportAnimationTimer ) / 0.35 ) ;
view . DrawPartialRotatedDecal ( playerPosition + vf2d { 0 , - player - > GetZ ( ) } , player - > GetFrame ( ) . GetSourceImage ( ) - > Decal ( ) , player - > GetSpinAngle ( ) , { 12 , 12 } , player - > GetFrame ( ) . GetSourceRect ( ) . pos , player - > GetFrame ( ) . GetSourceRect ( ) . size , playerScale , player - > GetBuffs ( BuffType : : ATTACK_UP ) . size ( ) > 0 ? Pixel { 255 , uint8_t ( 255 * abs ( sin ( 1.4 * player - > GetBuffs ( BuffType : : ATTACK_UP ) [ 0 ] . duration ) ) ) , uint8_t ( 255 * abs ( sin ( 1.4 * player - > GetBuffs ( BuffType : : ATTACK_UP ) [ 0 ] . duration ) ) ) } : WHITE ) ;
} else {
view . DrawPartialRotatedDecal ( playerPosition + vf2d { 0 , - player - > GetZ ( ) } , player - > GetFrame ( ) . GetSourceImage ( ) - > Decal ( ) , player - > GetSpinAngle ( ) , { 12 , 12 } , player - > GetFrame ( ) . GetSourceRect ( ) . pos , player - > GetFrame ( ) . GetSourceRect ( ) . size , playerScale , player - > GetBuffs ( BuffType : : ATTACK_UP ) . size ( ) > 0 ? Pixel { 255 , uint8_t ( 255 * abs ( sin ( 1.4 * player - > GetBuffs ( BuffType : : ATTACK_UP ) [ 0 ] . duration ) ) ) , uint8_t ( 255 * abs ( sin ( 1.4 * player - > GetBuffs ( BuffType : : ATTACK_UP ) [ 0 ] . duration ) ) ) } : WHITE ) ;
}
} ;
//define end
if ( ! player - > upperLevel ) {
RenderPlayer ( ) ;
RenderPlayer ( player - > GetPos ( ) , { 1 , 1 } ) ;
}
if ( player - > GetState ( ) = = State : : BLOCK ) {
view . DrawDecal ( player - > GetPos ( ) - vf2d { 12 , 12 } , GFX_BLOCK_BUBBLE . Decal ( ) ) ;
view . DrawDecal ( player - > GetPos ( ) - vf2d { 12 , 12 } , GFX [ " block.png " ] . Decal ( ) ) ;
}
for ( Monster * m : monstersAfterLower ) {
m - > Draw ( ) ;
@ -628,15 +725,15 @@ void Crawler::RenderWorld(float fElapsedTime){
float precastSize = GetPlayer ( ) - > castPrepAbility - > precastInfo . size ;
float precastRange = GetPlayer ( ) - > castPrepAbility - > precastInfo . range ;
vf2d scale = vf2d { precastSize , precastSize } * 2 / 3.f ;
vf2d centerPoint = GetWorldMousePos ( ) - vf2d { game - > GFX_Circle . Sprite ( ) - > width * scale . x / 2 , game - > GFX_Circle . Sprite ( ) - > height * scale . y / 2 } ;
vf2d centerPoint = GetWorldMousePos ( ) - vf2d { GFX [ " circle.png " ] . Sprite ( ) - > width * scale . x / 2 , GFX [ " circle.png " ] . Sprite ( ) - > height * scale . y / 2 } ;
float distance = sqrt ( pow ( player - > GetX ( ) - GetWorldMousePos ( ) . x , 2 ) + pow ( player - > GetY ( ) - GetWorldMousePos ( ) . y , 2 ) ) ;
if ( distance > precastRange ) { //Clamp the distance.
vf2d pointToCursor = { GetWorldMousePos ( ) . x - player - > GetX ( ) , GetWorldMousePos ( ) . y - player - > GetY ( ) } ;
pointToCursor = pointToCursor . norm ( ) * precastRange ;
vf2d centerPoint = player - > GetPos ( ) + pointToCursor - vf2d { game - > GFX_Circle . Sprite ( ) - > width * scale . x / 2 , game - > GFX_Circle . Sprite ( ) - > height * scale . y / 2 } ;
view . DrawDecal ( centerPoint , GFX_Circle . Decal ( ) , scale , { 255 , 0 , 0 , 96 } ) ;
vf2d centerPoint = player - > GetPos ( ) + pointToCursor - vf2d { GFX [ " circle.png " ] . Sprite ( ) - > width * scale . x / 2 , GFX [ " circle.png " ] . Sprite ( ) - > height * scale . y / 2 } ;
view . DrawDecal ( centerPoint , GFX [ " circle.png " ] . Decal ( ) , scale , { 255 , 0 , 0 , 96 } ) ;
} else {
view . DrawDecal ( centerPoint , GFX_Circle . Decal ( ) , scale , { 255 , 0 , 0 , 96 } ) ;
view . DrawDecal ( centerPoint , GFX [ " circle.png " ] . Decal ( ) , scale , { 255 , 0 , 0 , 96 } ) ;
}
}
} ;
@ -654,7 +751,7 @@ void Crawler::RenderWorld(float fElapsedTime){
group . fadeFactor = std : : max ( group . fadeFactor - fElapsedTime , 0.f ) ;
}
for ( TileRenderData & tile : group . GetTiles ( ) ) {
view . DrawPartialDecal ( tile . pos , { 24 , 24 } , tile . tileset , tile . tileSheetPos , { 24 , 24 } , { 255 , 255 , 255 , uint8_t ( 255 - group . fadeFactor / TileGroup : : FADE_TIME * TileGroup : : FADE_AMT ) } ) ;
RenderTile ( tile , { 255 , 255 , 255 , uint8_t ( 255 - group . fadeFactor / TileGroup : : FADE_TIME * TileGroup : : FADE_AMT ) } ) ;
}
}
}
@ -667,12 +764,12 @@ void Crawler::RenderWorld(float fElapsedTime){
int tileID = bridgeLayer - > tiles [ y ] [ x ] - 1 ;
if ( tileID ! = - 1 ) {
TilesheetData tileSheet = GetTileSheet ( currentLevel , tileID ) ;
int tileSheetWidth = tileSheet . tileset . tileset - > Sprite ( ) - > width / 24 ;
int tileSheetHeight = tileSheet . tileset . tileset - > Sprite ( ) - > height / 24 ;
int tileSheetWidth = tileSheet . tileset - > tileset - > Sprite ( ) - > width / 24 ;
int tileSheetHeight = tileSheet . tileset - > tileset - > Sprite ( ) - > height / 24 ;
int tileSheetIndex = tileID - ( tileSheet . firstgid - 1 ) ;
int tileSheetX = tileSheetIndex % tileSheetWidth ;
int tileSheetY = tileSheetIndex / tileSheetWidth ;
view . DrawPartialDecal ( vi2d { x , y } * 24 , { 24 , 24 } , tileSheet . tileset . tileset - > Decal ( ) , vi2d { tileSheetX , tileSheetY } * 24 , { 24 , 24 } , { 255 , 255 , 255 , uint8_t ( 255 - bridgeFadeFactor / TileGroup : : FADE_TIME * TileGroup : : FADE_AMT ) } ) ;
view . DrawPartialDecal ( vi2d { x , y } * 24 , { 24 , 24 } , tileSheet . tileset - > tileset - > Decal ( ) , vi2d { tileSheetX , tileSheetY } * 24 , { 24 , 24 } , { 255 , 255 , 255 , uint8_t ( 255 - bridgeFadeFactor / TileGroup : : FADE_TIME * TileGroup : : FADE_AMT ) } ) ;
# ifdef DEBUG_COLLISIONS
if ( tileSheet . tileset . collision . find ( tileSheetIndex ) ! = tileSheet . tileset . collision . end ( ) ) {
geom2d : : rect < int > collision = tileSheet . tileset . collision [ tileSheetIndex ] . collision ;
@ -693,7 +790,7 @@ void Crawler::RenderWorld(float fElapsedTime){
m - > Draw ( ) ;
}
if ( player - > upperLevel ) {
RenderPlayer ( ) ;
RenderPlayer ( player - > GetPos ( ) , { 1 , 1 } ) ;
}
for ( Monster * m : monstersAfterUpper ) {
m - > Draw ( ) ;
@ -717,7 +814,7 @@ void Crawler::RenderWorld(float fElapsedTime){
group . fadeFactor = std : : max ( group . fadeFactor - fElapsedTime , 0.f ) ;
}
for ( TileRenderData & tile : group . GetTiles ( ) ) {
view . DrawPartialDecal ( tile . pos , { 24 , 24 } , tile . tileset , tile . tileSheetPos , { 24 , 24 } , { 255 , 255 , 255 , uint8_t ( 255 - group . fadeFactor / TileGroup : : FADE_TIME * TileGroup : : FADE_AMT ) } ) ;
RenderTile ( tile , { 255 , 255 , 255 , uint8_t ( 255 - group . fadeFactor / TileGroup : : FADE_TIME * TileGroup : : FADE_AMT ) } ) ;
}
}
# pragma endregion
@ -727,21 +824,22 @@ void Crawler::RenderWorld(float fElapsedTime){
dn - > pauseTime - = fElapsedTime ;
} else {
dn - > lifeTime + = fElapsedTime ;
if ( dn - > lifeTime > 1 ) {
it = DAMAGENUMBER_LIST . erase ( it ) ;
if ( it = = DAMAGENUMBER_LIST . end ( ) ) {
break ;
}
} else {
if ( dn - > lifeTime < = 1 ) {
if ( dn - > lifeTime < DamageNumber : : MOVE_UP_TIME ) {
dn - > pos . y - = 20 * fElapsedTime ;
}
}
}
std : : string text = std : : to_string ( dn - > damage ) ;
view . DrawStringPropDecal ( dn - > pos - GetTextSizeProp ( text ) / 2 , text , DARK_RED ) ;
}
if ( DEBUG_PATHFINDING ) {
std : : vector < vf2d > pathing = game - > pathfinder . Solve_AStar ( player . get ( ) - > GetPos ( ) , GetWorldMousePos ( ) , 8 , player . get ( ) - > OnUpperLevel ( ) ) ;
for ( vf2d & square : pathing ) {
view . FillRectDecal ( square * 24 , { 24 , 24 } , DARK_GREEN ) ;
}
}
}
Player * Crawler : : GetPlayer ( ) {
@ -798,8 +896,8 @@ void Crawler::RenderHud(){
DrawShadowStringPropDecal ( vf2d { ScreenWidth ( ) / 2.f - GetTextSizeProp ( castText ) . x * 2 / 2 , ScreenHeight ( ) - 64.f } , castText , WHITE , BLACK , { 2 , 3 } , 2.f ) ;
}
DrawDecal ( { 2 , 2 } , GFX_Heart . Decal ( ) ) ;
DrawDecal ( { 2 , 20 } , GFX_Mana . Decal ( ) ) ;
DrawDecal ( { 2 , 2 } , GFX [ " heart.png " ] . Decal ( ) ) ;
DrawDecal ( { 2 , 20 } , GFX [ " mana.png " ] . Decal ( ) ) ;
std : : string text = player - > GetHealth ( ) > 0 ? std : : to_string ( player - > GetHealth ( ) ) : " X " ;
std : : string text_mana = std : : to_string ( player - > GetMana ( ) ) ;
DrawShadowStringPropDecal ( { 20 , 3 } , text , WHITE , BLACK , { 2 , 2 } ) ;
@ -862,6 +960,9 @@ void Crawler::InitializeLevel(std::string mapFile,MapName map){
MAP_TILESETS [ " assets/maps/ " + baseSourceDir ] . upperForegroundTiles = tileset . GetData ( ) . UpperForegroundTileData ;
MAP_TILESETS [ " assets/maps/ " + baseSourceDir ] . collision = tileset . GetData ( ) . CollisionData ;
MAP_TILESETS [ " assets/maps/ " + baseSourceDir ] . staircaseTiles = tileset . GetData ( ) . StaircaseData ;
MAP_TILESETS [ " assets/maps/ " + baseSourceDir ] . animationData = tileset . GetData ( ) . AnimationData ;
MAP_TILESETS [ " assets/maps/ " + baseSourceDir ] . reflectiveData = tileset . GetData ( ) . ReflectiveData ;
std : : cout < < " assets/maps/ " + baseSourceDir < < " Animation Data Size: " < < MAP_TILESETS [ " assets/maps/ " + baseSourceDir ] . animationData . size ( ) < < std : : endl ;
r - > Load ( " assets/maps/ " + tileset . GetData ( ) . ImageData . data [ " source " ] ) ;
}
}
@ -872,103 +973,148 @@ void Crawler::LoadLevel(MapName map){
foregroundTileGroups . clear ( ) ;
currentLevel = map ;
WORLD_SIZE = { MAP_DATA [ map ] . MapData . width , MAP_DATA [ map ] . MapData . height } ;
levelTime = 0 ;
for ( auto key : MAP_DATA [ map ] . SpawnerData ) {
SpawnerTag & spawnData = MAP_DATA [ map ] . SpawnerData [ key . first ] ;
std : : vector < std : : pair < int , vf2d > > monster_list ;
# pragma region Monster Spawn Data Setup
for ( auto key : MAP_DATA [ map ] . SpawnerData ) {
SpawnerTag & spawnData = MAP_DATA [ map ] . SpawnerData [ key . first ] ;
std : : vector < std : : pair < int , vf2d > > monster_list ;
vf2d spawnerRadius = vf2d { spawnData . ObjectData . GetFloat ( " width " ) , spawnData . ObjectData . GetFloat ( " height " ) } / 2 ;
for ( XMLTag & monster : spawnData . monsters ) {
int monsterTypeID = monster . GetInteger ( " value " ) - 1 ;
monster_list . push_back ( { monsterTypeID , { monster . GetInteger ( " x " ) - spawnData . ObjectData . GetFloat ( " x " ) , monster . GetInteger ( " y " ) - spawnData . ObjectData . GetFloat ( " y " ) } } ) ;
vf2d spawnerRadius = vf2d { spawnData . ObjectData . GetFloat ( " width " ) , spawnData . ObjectData . GetFloat ( " height " ) } / 2 ;
for ( XMLTag & monster : spawnData . monsters ) {
int monsterTypeID = monster . GetInteger ( " value " ) - 1 ;
monster_list . push_back ( { monsterTypeID , { monster . GetInteger ( " x " ) - spawnData . ObjectData . GetFloat ( " x " ) , monster . GetInteger ( " y " ) - spawnData . ObjectData . GetFloat ( " y " ) } } ) ;
}
SPAWNER_LIST . push_back ( MonsterSpawner { { spawnData . ObjectData . GetFloat ( " x " ) , spawnData . ObjectData . GetFloat ( " y " ) } , spawnerRadius * 2 , monster_list , spawnData . upperLevel } ) ;
}
SPAWNER_LIST . push_back ( MonsterSpawner { { spawnData . ObjectData . GetFloat ( " x " ) , spawnData . ObjectData . GetFloat ( " y " ) } , spawnerRadius * 2 , monster_list , spawnData . upperLevel } ) ;
}
# pragma endregion
# pragma region Identify Upper Foreground Tiles
auto GetUpperZones = [ & ] ( ) {
for ( auto & zoneSet : MAP_DATA [ map ] . ZoneData ) {
if ( zoneSet . first = = " UpperZone " ) { //We are interested in all upper zones.
return zoneSet . second ;
}
}
return std : : vector < geom2d : : rect < int > > { } ;
} ;
for ( geom2d : : rect < int > & zone : GetUpperZones ( ) ) {
int zoneX = zone . pos . x / 24 ; //snap to grid
int zoneY = zone . pos . y / 24 ;
int zoneW = zone . right ( ) . start . x / 24 - zoneX ;
int zoneH = zone . bottom ( ) . start . y / 24 - zoneY ;
for ( int x = zoneX ; x < zoneX + zoneW ; x + + ) {
for ( int y = zoneY ; y < zoneY + zoneH ; y + + ) {
for ( LayerTag & layer : MAP_DATA [ map ] . LayerData ) {
int tile = layer . tiles [ y ] [ x ] - 1 ;
TilesheetData tileSheet = GetTileSheet ( currentLevel , tile ) ;
int tileSheetIndex = tile - ( tileSheet . firstgid - 1 ) ;
if ( IsForegroundTile ( tileSheet , tileSheetIndex ) ) {
layer . tiles [ y ] [ x ] + = 1000000 ;
}
}
}
}
}
# pragma endregion
std : : set < vi2d > foregroundTilesAdded , upperForegroundTilesAdded ;
for ( int x = 0 ; x < WORLD_SIZE . x ; x + + ) {
for ( int y = 0 ; y < WORLD_SIZE . y ; y + + ) {
for ( LayerTag & layer : MAP_DATA [ currentLevel ] . LayerData ) {
int tileID = layer . tiles [ y ] [ x ] - 1 ;
if ( tileID ! = - 1 ) {
TilesheetData tileSheet = GetTileSheet ( currentLevel , tileID ) ;
int tileSheetWidth = tileSheet . tileset . tileset - > Sprite ( ) - > width / 24 ;
int tileSheetHeight = tileSheet . tileset . tileset - > Sprite ( ) - > height / 24 ;
int tileSheetIndex = tileID - ( tileSheet . firstgid - 1 ) ;
int tileSheetX = tileSheetIndex % tileSheetWidth ;
int tileSheetY = tileSheetIndex / tileSheetWidth ;
# pragma region TileGroupShenanigans
auto SetupTileGroups = [ & ] ( std : : function < bool ( TilesheetData , int ) > IsForeground , TileRenderData tile , std : : set < vi2d > & foregroundTilesIncluded , std : : vector < TileGroup > & groups ) {
int layerID = layer . tag . GetInteger ( " id " ) ;
if ( IsForeground ( tileSheet , tileSheetIndex ) & & foregroundTilesIncluded . find ( { x , y } ) = = foregroundTilesIncluded . end ( ) ) {
std : : queue < vi2d > tileGroupChecks ;
TileGroup group ;
foregroundTilesIncluded . insert ( { x , y } ) ;
group . originatingLayer = layerID ;
group . InsertTile ( tile ) ;
if ( x > 0 ) tileGroupChecks . push ( { x - 1 , y } ) ;
if ( x < WORLD_SIZE . x - 1 ) tileGroupChecks . push ( { x + 1 , y } ) ;
if ( y > 0 ) tileGroupChecks . push ( { x , y - 1 } ) ;
if ( y < WORLD_SIZE . y - 1 ) tileGroupChecks . push ( { x , y + 1 } ) ;
auto IterateThroughOtherLayers = [ & ] ( vi2d pos ) {
for ( LayerTag & layer2 : MAP_DATA [ currentLevel ] . LayerData ) {
if ( & layer = = & layer2 ) continue ;
int tileID = layer2 . tiles [ pos . y ] [ pos . x ] - 1 ;
TilesheetData tileSheet = GetTileSheet ( currentLevel , tileID ) ;
int tileSheetWidth = tileSheet . tileset . tileset - > Sprite ( ) - > width / 24 ;
int tileSheetHeight = tileSheet . tileset . tileset - > Sprite ( ) - > height / 24 ;
int tileSheetIndex = tileID - ( tileSheet . firstgid - 1 ) ;
int tileSheetX = tileSheetIndex % tileSheetWidth ;
int tileSheetY = tileSheetIndex / tileSheetWidth ;
TileRenderData tile = { tileSheet . tileset . tileset - > Decal ( ) , vi2d { pos . x , pos . y } * 24 , vi2d { tileSheetX , tileSheetY } * 24 } ;
if ( IsForeground ( tileSheet , tileSheetIndex ) ) {
foregroundTilesIncluded . insert ( { pos . x , pos . y } ) ;
group . InsertTile ( tile ) ;
# pragma region Foreground and Upper Foreground Tile Fade Group Setup
std : : set < vi2d > foregroundTilesAdded , upperForegroundTilesAdded ;
for ( int x = 0 ; x < WORLD_SIZE . x ; x + + ) {
for ( int y = 0 ; y < WORLD_SIZE . y ; y + + ) {
int layerID = 0 ;
for ( LayerTag & layer : MAP_DATA [ currentLevel ] . LayerData ) {
int tileID = layer . tiles [ y ] [ x ] - 1 ;
if ( tileID ! = - 1 ) {
TilesheetData tileSheet = GetTileSheet ( currentLevel , tileID ) ;
int tileSheetWidth = tileSheet . tileset - > tileset - > Sprite ( ) - > width / 24 ;
int tileSheetHeight = tileSheet . tileset - > tileset - > Sprite ( ) - > height / 24 ;
int tileSheetIndex = tileID - ( tileSheet . firstgid - 1 ) ;
int realTileSheetIndex = ( tileID % 1000000 ) - ( tileSheet . firstgid - 1 ) ;
int tileSheetX = realTileSheetIndex % tileSheetWidth ;
int tileSheetY = realTileSheetIndex / tileSheetWidth ;
# pragma region TileGroupShenanigans
auto SetupTileGroups = [ & ] ( std : : function < bool ( TilesheetData , int ) > IsForeground , TileRenderData tile , std : : set < vi2d > & foregroundTilesIncluded , std : : vector < TileGroup > & groups ) {
if ( foregroundTilesIncluded . find ( { x , y } ) = = foregroundTilesIncluded . end ( ) & & IsForeground ( tileSheet , tileSheetIndex ) ) {
std : : queue < vi2d > tileGroupChecks ;
TileGroup group ;
foregroundTilesIncluded . insert ( { x , y } ) ;
group . InsertTile ( tile ) ;
if ( x > 0 & & foregroundTilesIncluded . find ( vi2d { x , y } + vi2d { - 1 , 0 } ) = = foregroundTilesIncluded . end ( ) ) tileGroupChecks . push ( { x - 1 , y } ) ;
if ( x < WORLD_SIZE . x - 1 & & foregroundTilesIncluded . find ( vi2d { x , y } + vi2d { 1 , 0 } ) = = foregroundTilesIncluded . end ( ) ) tileGroupChecks . push ( { x + 1 , y } ) ;
if ( y > 0 & & foregroundTilesIncluded . find ( vi2d { x , y } + vi2d { 0 , - 1 } ) = = foregroundTilesIncluded . end ( ) ) tileGroupChecks . push ( { x , y - 1 } ) ;
if ( y < WORLD_SIZE . y - 1 & & foregroundTilesIncluded . find ( vi2d { x , y } + vi2d { 0 , 1 } ) = = foregroundTilesIncluded . end ( ) ) tileGroupChecks . push ( { x , y + 1 } ) ;
auto IterateThroughOtherLayers = [ & ] ( vi2d pos , bool loopAll = false ) {
int layer2ID = 0 ;
bool hadForeground = false ;
for ( LayerTag & layer2 : MAP_DATA [ currentLevel ] . LayerData ) {
if ( ! loopAll & & & layer = = & layer2 ) { layer2ID + + ; continue ; } ;
int tileID = layer2 . tiles [ pos . y ] [ pos . x ] - 1 ;
TilesheetData tileSheet = GetTileSheet ( currentLevel , tileID % 1000000 ) ;
int tileSheetWidth = tileSheet . tileset - > tileset - > Sprite ( ) - > width / 24 ;
int tileSheetHeight = tileSheet . tileset - > tileset - > Sprite ( ) - > height / 24 ;
int tileSheetIndex = tileID - ( tileSheet . firstgid - 1 ) ;
int realTileSheetIndex = ( tileID % 1000000 ) - ( tileSheet . firstgid - 1 ) ;
int tileSheetX = realTileSheetIndex % tileSheetWidth ;
int tileSheetY = realTileSheetIndex / tileSheetWidth ;
TileRenderData tile = { tileSheet , vi2d { pos . x , pos . y } * 24 , vi2d { tileSheetX , tileSheetY } * 24 , realTileSheetIndex , layer2ID } ;
if ( IsForeground ( tileSheet , tileSheetIndex ) ) {
foregroundTilesIncluded . insert ( { pos . x , pos . y } ) ;
group . InsertTile ( tile ) ;
hadForeground = true ;
}
layer2ID + + ;
}
return hadForeground ;
} ;
IterateThroughOtherLayers ( { x , y } ) ;
while ( ! tileGroupChecks . empty ( ) ) {
vi2d & pos = tileGroupChecks . front ( ) ;
if ( IterateThroughOtherLayers ( pos , true ) ) {
foregroundTilesIncluded . insert ( { pos . x , pos . y } ) ; //Regardless of if we found a foreground tile or not, we need to add this to not get stuck in an infinite loop.
vi2d targetPos = pos + vi2d { - 1 , 0 } ;
if ( pos . x > 0 & & foregroundTilesIncluded . find ( targetPos ) = = foregroundTilesIncluded . end ( ) ) { tileGroupChecks . push ( targetPos ) ; foregroundTilesIncluded . insert ( targetPos ) ; }
targetPos = pos + vi2d { 1 , 0 } ;
if ( pos . x < WORLD_SIZE . x - 1 & & foregroundTilesIncluded . find ( targetPos ) = = foregroundTilesIncluded . end ( ) ) { tileGroupChecks . push ( targetPos ) ; foregroundTilesIncluded . insert ( targetPos ) ; }
targetPos = pos + vi2d { 0 , - 1 } ;
if ( pos . y > 0 & & foregroundTilesIncluded . find ( targetPos ) = = foregroundTilesIncluded . end ( ) ) { tileGroupChecks . push ( targetPos ) ; foregroundTilesIncluded . insert ( targetPos ) ; }
targetPos = pos + vi2d { 0 , 1 } ;
if ( pos . y < WORLD_SIZE . y - 1 & & foregroundTilesIncluded . find ( targetPos ) = = foregroundTilesIncluded . end ( ) ) { tileGroupChecks . push ( targetPos ) ; foregroundTilesIncluded . insert ( targetPos ) ; }
}
tileGroupChecks . pop ( ) ;
}
} ;
IterateThroughOtherLayers ( { x , y } ) ;
while ( ! tileGroupChecks . empty ( ) ) {
vi2d & pos = tileGroupChecks . front ( ) ;
tileGroupChecks . pop ( ) ;
int tileID = layer . tiles [ pos . y ] [ pos . x ] - 1 ;
TilesheetData tileSheet = GetTileSheet ( currentLevel , tileID ) ;
int tileSheetWidth = tileSheet . tileset . tileset - > Sprite ( ) - > width / 24 ;
int tileSheetHeight = tileSheet . tileset . tileset - > Sprite ( ) - > height / 24 ;
int tileSheetIndex = tileID - ( tileSheet . firstgid - 1 ) ;
int tileSheetX = tileSheetIndex % tileSheetWidth ;
int tileSheetY = tileSheetIndex / tileSheetWidth ;
TileRenderData tile = { tileSheet . tileset . tileset - > Decal ( ) , pos * 24 , vi2d { tileSheetX , tileSheetY } * 24 } ;
if ( IsForeground ( tileSheet , tileSheetIndex ) & & foregroundTilesIncluded . find ( pos ) = = foregroundTilesIncluded . end ( ) ) {
foregroundTilesIncluded . insert ( pos ) ;
group . InsertTile ( tile ) ;
if ( pos . x > 0 ) tileGroupChecks . push ( pos + vi2d { - 1 , 0 } ) ;
if ( pos . x < WORLD_SIZE . x - 1 ) tileGroupChecks . push ( pos + vi2d { 1 , 0 } ) ;
if ( pos . y > 0 ) tileGroupChecks . push ( pos + vi2d { 0 , - 1 } ) ;
if ( pos . y < WORLD_SIZE . y - 1 ) tileGroupChecks . push ( pos + vi2d { 0 , 1 } ) ;
IterateThroughOtherLayers ( pos ) ;
}
groups . push_back ( group ) ;
}
groups . push_back ( group ) ;
}
} ;
TileRenderData tile = { tileSheet . tileset . tileset - > Decal ( ) , vi2d { x , y } * 24 , vi2d { tileSheetX , tileSheetY } * 24 } ;
SetupTileGroups ( [ & ] ( TilesheetData sheet , int tileID ) { return IsForegroundTile ( sheet , tileID ) ; } , tile , foregroundTilesAdded , foregroundTileGroups ) ;
SetupTileGroups ( [ & ] ( TilesheetData sheet , int tileID ) { return IsUpperForegroundTile ( sheet , tileID ) ; } , tile , upperForegroundTilesAdded , upperForegroundTileGroups ) ;
# pragma endregion
} ;
TileRenderData tile = { tileSheet , vi2d { x , y } * 24 , vi2d { tileSheetX , tileSheetY } * 24 , tileID , layerID } ;
SetupTileGroups ( [ & ] ( TilesheetData sheet , int tileID ) { return IsForegroundTile ( sheet , tileID ) ; } , tile , foregroundTilesAdded , foregroundTileGroups ) ;
SetupTileGroups ( [ & ] ( TilesheetData sheet , int tileID ) { return IsUpperForegroundTile ( tileID ) ; } , tile , upperForegroundTilesAdded , upperForegroundTileGroups ) ;
# pragma endregion
}
layerID + + ;
}
}
}
}
for ( TileGroup & group : foregroundTileGroups ) {
std : : sort ( group . GetTiles ( ) . begin ( ) , group . GetTiles ( ) . end ( ) , [ ] ( TileRenderData & t1 , TileRenderData & t2 ) { return t1 . layerID < t2 . layerID ; } ) ;
}
for ( TileGroup & group : upperForegroundTileGroups ) {
std : : sort ( group . GetTiles ( ) . begin ( ) , group . GetTiles ( ) . end ( ) , [ ] ( TileRenderData & t1 , TileRenderData & t2 ) { return t1 . layerID < t2 . layerID ; } ) ;
}
# pragma endregion
int counter = 0 ;
bridgeLayerIndex = - 1 ;
for ( LayerTag & layer : MAP_DATA [ map ] . LayerData ) {
if ( IsBridgeLayer ( layer ) ) {
bridgeLayerIndex = counter ;
# pragma region Bridge Layer Setup
int counter = 0 ;
bridgeLayerIndex = - 1 ;
for ( LayerTag & layer : MAP_DATA [ map ] . LayerData ) {
if ( IsBridgeLayer ( layer ) ) {
bridgeLayerIndex = counter ;
}
counter + + ;
}
counter + + ;
}
# pragma endregion
player - > upperLevel = false ; //Assume player starts on lower level.
player - > SetPos ( MAP_DATA [ map ] . MapData . playerSpawnLocation ) ;
@ -987,12 +1133,12 @@ vi2d Crawler::GetWorldSize(){
return WORLD_SIZE ;
}
bool Crawler : : IsUpperForegroundTile ( TilesheetData sheet , int tileID ) {
return sheet . tileset . upperForegroundTiles . find ( tileID ) ! = sheet . tileset . upperForegroundTiles . end ( ) ;
bool Crawler : : IsUpperForegroundTile ( int tileID ) {
return tileID > = 1000000 ;
}
bool Crawler : : IsForegroundTile ( TilesheetData sheet , int tileID ) {
return sheet . tileset . foregroundTiles . find ( tileID ) ! = sheet . tileset . foregroundTiles . end ( ) ;
return sheet . tileset - > foregroundTiles . find ( tileID ) ! = sheet . tileset - > foregroundTiles . end ( ) ;
}
TilesheetData Crawler : : GetTileSheet ( MapName map , int tileID ) {
@ -1000,18 +1146,18 @@ TilesheetData Crawler::GetTileSheet(MapName map,int tileID){
if ( tileData . size ( ) = = 1 ) {
size_t slashMarkerSourceDir = tileData [ 0 ] . data [ " source " ] . find_last_of ( ' / ' ) ;
std : : string baseSourceDir = tileData [ 0 ] . data [ " source " ] . substr ( slashMarkerSourceDir + 1 ) ;
return { MAP_TILESETS [ " assets/maps/ " + baseSourceDir ] , 1 } ;
return { & MAP_TILESETS [ " assets/maps/ " + baseSourceDir ] , 1 } ;
} else {
for ( int i = 1 ; i < tileData . size ( ) ; i + + ) {
if ( tileID < stoi ( tileData [ i ] . data [ " firstgid " ] ) ) {
if ( tileID % 1000000 < stoi ( tileData [ i ] . data [ " firstgid " ] ) - 1 ) {
size_t slashMarkerSourceDir = tileData [ i - 1 ] . data [ " source " ] . find_last_of ( ' / ' ) ;
std : : string baseSourceDir = tileData [ i - 1 ] . data [ " source " ] . substr ( slashMarkerSourceDir + 1 ) ;
return { MAP_TILESETS [ " assets/maps/ " + baseSourceDir ] , stoi ( tileData [ i - 1 ] . data [ " firstgid " ] ) } ;
return { & MAP_TILESETS [ " assets/maps/ " + baseSourceDir ] , stoi ( tileData [ i - 1 ] . data [ " firstgid " ] ) } ;
}
}
size_t slashMarkerSourceDir = tileData [ tileData . size ( ) - 1 ] . data [ " source " ] . find_last_of ( ' / ' ) ;
std : : string baseSourceDir = tileData [ tileData . size ( ) - 1 ] . data [ " source " ] . substr ( slashMarkerSourceDir + 1 ) ;
return { MAP_TILESETS [ " assets/maps/ " + baseSourceDir ] , stoi ( tileData [ tileData . size ( ) - 1 ] . data [ " firstgid " ] ) } ;
return { & MAP_TILESETS [ " assets/maps/ " + baseSourceDir ] , stoi ( tileData [ tileData . size ( ) - 1 ] . data [ " firstgid " ] ) } ;
}
}
@ -1032,7 +1178,7 @@ geom2d::rect<int>Crawler::GetTileCollision(MapName map,vf2d pos,bool upperLevel)
if ( ! upperLevel ) { //We are looking for lower bridge collisions.
for ( geom2d : : rect < int > & zone : MAP_DATA [ map ] . ZoneData [ " LowerBridgeCollision " ] ) {
if ( geom2d : : contains ( zone , pos ) ) {
return { { 0 , 0 } , { 3 2, 3 2} } ;
return { { 0 , 0 } , { 24 , 24 } } ;
}
}
}
@ -1041,24 +1187,34 @@ geom2d::rect<int>Crawler::GetTileCollision(MapName map,vf2d pos,bool upperLevel)
if ( upperLevel & & bridgeLayerIndex ! = - 1 ) {
int tileID = MAP_DATA [ map ] . LayerData [ bridgeLayerIndex ] . tiles [ int ( pos . y ) / 24 ] [ int ( pos . x ) / 24 ] - 1 ;
if ( tileID ! = - 1 ) {
if ( GetTileSheet ( map , tileID ) . tileset . collision . find ( tileID - GetTileSheet ( map , tileID ) . firstgid + 1 ) ! = GetTileSheet ( map , tileID ) . tileset . collision . end ( ) ) {
return GetTileSheet ( map , tileID ) . tileset . collision [ tileID - GetTileSheet ( map , tileID ) . firstgid + 1 ] . collision ;
if ( GetTileSheet ( map , tileID % 1000000 ) . tileset - > collision . find ( tileID % 1000000 - GetTileSheet ( map , tileID % 1000000 ) . firstgid + 1 ) ! = GetTileSheet ( map , tileID % 1000000 ) . tileset - > collision . end ( ) ) {
return GetTileSheet ( map , tileID % 1000000 ) . tileset - > collision [ tileID % 1000000 - GetTileSheet ( map , tileID % 1000000 ) . firstgid + 1 ] . collision ;
}
return NO_COLLISION ;
}
}
int counter = 0 ;
geom2d : : rect < int > foundRect = NO_COLLISION ;
for ( LayerTag & layer : MAP_DATA [ map ] . LayerData ) {
auto HasNoClass = [ & ] ( ) { return layer . tag . data . find ( " class " ) = = layer . tag . data . end ( ) ; } ;
if ( HasNoClass ( ) & & counter ! = bridgeLayerIndex ) {
//auto HasNoClass=[&](){return layer.tag.data.find("class")==layer.tag.data.end();};
if ( counter ! = bridgeLayerIndex ) {
int tileID = layer . tiles [ int ( pos . y ) / 24 ] [ int ( pos . x ) / 24 ] - 1 ;
if ( tileID ! = - 1 & & GetTileSheet ( map , tileID ) . tileset . collision . find ( tileID - GetTileSheet ( map , tileID ) . firstgid + 1 ) ! = GetTileSheet ( map , tileID ) . tileset . collision . end ( ) ) {
return GetTileSheet ( map , tileID ) . tileset . collision [ tileID - GetTileSheet ( map , tileID ) . firstgid + 1 ] . collision ;
if ( tileID ! = - 1 & & GetTileSheet ( map , tileID % 1000000 ) . tileset - > collision . find ( tileID % 1000000 - GetTileSheet ( map , tileID % 1000000 ) . firstgid + 1 ) ! = GetTileSheet ( map , tileID % 1000000 ) . tileset - > collision . end ( ) ) {
geom2d : : rect < int > collisionRect = GetTileSheet ( map , tileID % 1000000 ) . tileset - > collision [ tileID % 1000000 - GetTileSheet ( map , tileID % 1000000 ) . firstgid + 1 ] . collision ;
if ( foundRect . pos = = NO_COLLISION . pos & & foundRect . size = = NO_COLLISION . size ) {
foundRect = collisionRect ;
} else {
//When we find another rectangle in the same square, we expand it to consume the area, whichever tile creates a larger surface or the combination of the two.
foundRect . pos . x = std : : min ( foundRect . pos . x , collisionRect . pos . x ) ;
foundRect . pos . y = std : : min ( foundRect . pos . y , collisionRect . pos . y ) ;
foundRect . size . x = std : : max ( foundRect . size . x , collisionRect . size . x ) ;
foundRect . size . y = std : : max ( foundRect . size . y , collisionRect . size . y ) ;
}
}
}
counter + + ;
}
return NO_COLLISION ;
return foundRect ;
}
MapName Crawler : : GetCurrentLevel ( ) {
@ -1143,9 +1299,8 @@ datafiledoubledata Crawler::GetDoubleList(std::string key){
int main ( )
{
std : : cout < < " I change this " < < std : : endl ;
Crawler demo ;
if ( demo . Construct ( WINDOW_SIZE . x , WINDOW_SIZE . y , 4 , 4 ) )
if ( demo . Construct ( WINDOW_SIZE . x , WINDOW_SIZE . y , 4 , 4 , false ) )
demo . Start ( ) ;
return 0 ;
@ -1215,6 +1370,15 @@ void Crawler::OutputDebugInfo(const char*key,std::size_t len){
}
}
bool Crawler : : IsReflectiveTile ( TilesheetData tileSheet , int tileID ) {
return tileSheet . tileset - > reflectiveData . find ( tileID ) ! = tileSheet . tileset - > reflectiveData . end ( ) ;
}
bool Crawler : : OnUserDestroy ( ) {
GFX . Reset ( ) ;
return true ;
}
void Crawler : : InitializeLevels ( ) {
# define INITLEVEL(map) \
InitializeLevel ( " map_path " _S + " Levels. " # map # # _S , map ) ; \
@ -1226,4 +1390,8 @@ void Crawler::InitializeLevels(){
INITLEVEL ( CAMPAIGN_1_2 ) ;
LEVEL_NAMES . SetInitialized ( ) ;
}
void Crawler : : SpawnMonster ( vf2d pos , MonsterData * data , bool upperLevel ) {
monstersToBeSpawned . push_back ( Monster ( pos , * data , upperLevel ) ) ;
}