Remove the random message

pull/28/head
sigonasr2, Sig, Sigo 2 years ago
commit 5bc449fb7a
  1. 4
      Crawler/Ability.cpp
  2. 3
      Crawler/Ability.h
  3. 131
      Crawler/Animation.cpp
  4. 6
      Crawler/Arrow.cpp
  5. 5
      Crawler/Bullet.cpp
  6. 2
      Crawler/C++/scripts/md5
  7. 6
      Crawler/C++/scripts/web.sh
  8. 4
      Crawler/ChargedArrow.cpp
  9. 665
      Crawler/ClassDiagram2.cd
  10. BIN
      Crawler/ClassDiagram2.png
  11. BIN
      Crawler/Crawler
  12. 618
      Crawler/Crawler.cpp
  13. 32
      Crawler/Crawler.h
  14. 59
      Crawler/Crawler.tiled-project
  15. 2
      Crawler/Crawler.vcxproj
  16. 4
      Crawler/Crawler.vcxproj.filters
  17. 4
      Crawler/DEFINES.h
  18. 10
      Crawler/Effect.cpp
  19. 8
      Crawler/Effect.h
  20. 8
      Crawler/EnergyBolt.cpp
  21. 19
      Crawler/FallingDebris.h
  22. 10
      Crawler/FireBolt.cpp
  23. 16
      Crawler/LightningBolt.cpp
  24. 4
      Crawler/LightningBoltEmitter.cpp
  25. 2
      Crawler/Map.cpp
  26. 13
      Crawler/Map.h
  27. 14
      Crawler/Meteor.cpp
  28. 23
      Crawler/Monster.cpp
  29. 3
      Crawler/Monster.h
  30. 2
      Crawler/MonsterAttribute.h
  31. 2
      Crawler/MonsterData.cpp
  32. 1
      Crawler/Pathfinding.cpp
  33. 28
      Crawler/Player.cpp
  34. 18
      Crawler/Player.h
  35. 14
      Crawler/PulsatingFire.cpp
  36. 102
      Crawler/SlimeKing.cpp
  37. 26
      Crawler/TMXParser.h
  38. 25
      Crawler/TSXParser.h
  39. 9
      Crawler/Turret.cpp
  40. 2
      Crawler/Version.h
  41. 4
      Crawler/Warrior.cpp
  42. 7
      Crawler/Wizard.cpp
  43. BIN
      Crawler/assets/Campaigns/1_1_v2.png
  44. 1253
      Crawler/assets/Campaigns/1_1_v2.tmx
  45. 10
      Crawler/assets/config/MonsterStrategies.txt
  46. 4
      Crawler/assets/config/Monsters.txt
  47. 11
      Crawler/assets/config/classes/Ranger.txt
  48. 8
      Crawler/assets/config/classes/Thief.txt
  49. 8
      Crawler/assets/config/classes/Trapper.txt
  50. 10
      Crawler/assets/config/classes/Warrior.txt
  51. 8
      Crawler/assets/config/classes/Witch.txt
  52. 10
      Crawler/assets/config/classes/Wizard.txt
  53. 17
      Crawler/assets/config/configuration.txt
  54. 36
      Crawler/assets/config/gfx/gfx.txt
  55. BIN
      Crawler/assets/fire_ring0.png
  56. BIN
      Crawler/assets/fire_ring1.png
  57. BIN
      Crawler/assets/fire_ring2.png
  58. BIN
      Crawler/assets/fire_ring3.png
  59. BIN
      Crawler/assets/fire_ring4.png
  60. 124
      Crawler/assets/maps/24x24_Waterfall.tsx
  61. 1437
      Crawler/assets/maps/Decorations_c1_No_Shadow24x24.tsx
  62. 3124
      Crawler/assets/maps/Tile_Presets.tmx
  63. 4645
      Crawler/assets/maps/Tilesheet_No_Shadow24x24.tsx
  64. BIN
      Crawler/assets/monsters/Slime King - Cast.png
  65. BIN
      Crawler/assets/nico-warrior.png
  66. BIN
      Crawler/assets/nico-warrior.xcf
  67. 2
      Crawler/buildtemplate.html
  68. 2
      Crawler/olcPGEX_TransformedView.h
  69. 4
      Crawler/olcPixelGameEngine.h
  70. 19
      Crawler/olcUTIL_DataFile.h
  71. 16364
      Crawler/pge.data
  72. 2
      Crawler/pge.js
  73. BIN
      Crawler/pge.wasm
  74. 1
      Crawler/pixelGameEngine.cpp
  75. 75
      Crawler/play.html
  76. 17
      Crawler/safemap.h
  77. 5
      Crawler/sig
  78. 4
      Crawler/utils.cpp
  79. 2
      Crawler/utils.h
  80. BIN
      x64/Release/Crawler.exe

@ -10,5 +10,5 @@ PrecastData::PrecastData(float castTime,float range,float size)
}; };
Ability::Ability(){}; Ability::Ability(){};
Ability::Ability(std::string name,float cooldownTime,int manaCost,Pixel barColor1,Pixel barColor2,PrecastData precastInfo) Ability::Ability(std::string name,float cooldownTime,int manaCost,Pixel barColor1,Pixel barColor2,PrecastData precastInfo,bool canCancelCast)
:name(name),cooldown(0),COOLDOWN_TIME(cooldownTime),manaCost(manaCost),barColor1(barColor1),barColor2(barColor2),precastInfo(precastInfo){} :name(name),cooldown(0),COOLDOWN_TIME(cooldownTime),manaCost(manaCost),barColor1(barColor1),barColor2(barColor2),precastInfo(precastInfo),canCancelCast(canCancelCast){}

@ -23,7 +23,8 @@ struct Ability{
int manaCost=0; int manaCost=0;
Pixel barColor1,barColor2; Pixel barColor1,barColor2;
PrecastData precastInfo; PrecastData precastInfo;
bool canCancelCast=false;
std::function<bool(Player*,vf2d)>action=[](Player*,vf2d){return false;}; std::function<bool(Player*,vf2d)>action=[](Player*,vf2d){return false;};
Ability(); Ability();
Ability(std::string name,float cooldownTime,int manaCost,Pixel barColor1=VERY_DARK_RED,Pixel barColor2=DARK_RED,PrecastData precastInfo={}); Ability(std::string name,float cooldownTime,int manaCost,Pixel barColor1=VERY_DARK_RED,Pixel barColor2=DARK_RED,PrecastData precastInfo={},bool canCancelCast=false);
}; };

@ -6,21 +6,22 @@
INCLUDE_game INCLUDE_game
INCLUDE_ANIMATION_DATA INCLUDE_ANIMATION_DATA
INCLUDE_DATA INCLUDE_DATA
INCLUDE_GFX
void sig::Animation::InitializeAnimations(){ void sig::Animation::InitializeAnimations(){
auto CreateStillAnimation=[&](Renderable&img,vf2d size,std::string state,AnimationData data={}){ auto CreateStillAnimation=[&](std::string imgName,vf2d size,AnimationData data={}){
Animate2D::FrameSequence anim(data.frameDuration,data.style); Animate2D::FrameSequence anim(data.frameDuration,data.style);
anim.AddFrame({&img,{{0,0},size}}); anim.AddFrame({&GFX[imgName],{{0,0},size}});
ANIMATION_DATA[state]=anim; ANIMATION_DATA[imgName]=anim;
}; };
auto CreateHorizontalAnimationSequence=[&](Renderable&img,int frameCount,vf2d size,std::string state,AnimationData data={}){ auto CreateHorizontalAnimationSequence=[&](std::string imgName,int frameCount,vf2d size,AnimationData data={}){
Animate2D::FrameSequence anim(data.frameDuration,data.style); Animate2D::FrameSequence anim(data.frameDuration,data.style);
for(int i=0;i<frameCount;i++){ for(int i=0;i<frameCount;i++){
anim.AddFrame({&img,{{int(i*size.x),0},size}}); anim.AddFrame({&GFX[imgName],{{int(i*size.x),0},size}});
} }
ANIMATION_DATA[state]=anim; ANIMATION_DATA[imgName]=anim;
}; };
auto SetupClassWalkIdleAnimations=[&](Renderable&sheet,std::string className){ auto SetupClassWalkIdleAnimations=[&](Renderable&sheet,std::string className){
@ -63,24 +64,24 @@ void sig::Animation::InitializeAnimations(){
}; };
//Warrior animations. //Warrior animations.
SetupClassWalkIdleAnimations(game->GFX_Warrior_Sheet,"WARRIOR"); SetupClassWalkIdleAnimations(GFX["nico-warrior.png"],"WARRIOR");
Animate2D::FrameSequence pl_warrior_swing_s(0.05),pl_warrior_swing_n(0.05),pl_warrior_swing_e(0.05),pl_warrior_swing_w(0.05); Animate2D::FrameSequence pl_warrior_swing_s(0.05),pl_warrior_swing_n(0.05),pl_warrior_swing_e(0.05),pl_warrior_swing_w(0.05);
Animate2D::FrameSequence pl_warrior_sonic_swing_s(0.1,Animate2D::Style::OneShot),pl_warrior_sonic_swing_n(0.1,Animate2D::Style::OneShot),pl_warrior_sonic_swing_e(0.1,Animate2D::Style::OneShot),pl_warrior_sonic_swing_w(0.1,Animate2D::Style::OneShot); Animate2D::FrameSequence pl_warrior_sonic_swing_s(0.1,Animate2D::Style::OneShot),pl_warrior_sonic_swing_n(0.1,Animate2D::Style::OneShot),pl_warrior_sonic_swing_e(0.1,Animate2D::Style::OneShot),pl_warrior_sonic_swing_w(0.1,Animate2D::Style::OneShot);
for (int i=0;i<4;i++){ for (int i=0;i<4;i++){
pl_warrior_swing_s.AddFrame({&game->GFX_Warrior_Sheet,{vi2d{4+i,0}*24,{24,24}}}); pl_warrior_swing_s.AddFrame({&GFX["nico-warrior.png"],{vi2d{4+i,0}*24,{24,24}}});
pl_warrior_sonic_swing_s.AddFrame({&game->GFX_Warrior_Sheet,{vi2d{4+i,4}*24,{24,24}}}); pl_warrior_sonic_swing_s.AddFrame({&GFX["nico-warrior.png"],{vi2d{4+i,4}*24,{24,24}}});
} }
for (int i=0;i<4;i++){ for (int i=0;i<4;i++){
pl_warrior_swing_n.AddFrame({&game->GFX_Warrior_Sheet,{vi2d{4+i,1}*24,{24,24}}}); pl_warrior_swing_n.AddFrame({&GFX["nico-warrior.png"],{vi2d{4+i,1}*24,{24,24}}});
pl_warrior_sonic_swing_n.AddFrame({&game->GFX_Warrior_Sheet,{vi2d{4+i,5}*24,{24,24}}}); pl_warrior_sonic_swing_n.AddFrame({&GFX["nico-warrior.png"],{vi2d{4+i,5}*24,{24,24}}});
} }
for (int i=0;i<4;i++){ for (int i=0;i<4;i++){
pl_warrior_swing_w.AddFrame({&game->GFX_Warrior_Sheet,{vi2d{4+i,2}*24,{24,24}}}); pl_warrior_swing_w.AddFrame({&GFX["nico-warrior.png"],{vi2d{4+i,2}*24,{24,24}}});
pl_warrior_sonic_swing_w.AddFrame({&game->GFX_Warrior_Sheet,{vi2d{4+i,6}*24,{24,24}}}); pl_warrior_sonic_swing_w.AddFrame({&GFX["nico-warrior.png"],{vi2d{4+i,6}*24,{24,24}}});
} }
for (int i=0;i<4;i++){ for (int i=0;i<4;i++){
pl_warrior_swing_e.AddFrame({&game->GFX_Warrior_Sheet,{vi2d{4+i,3}*24,{24,24}}}); pl_warrior_swing_e.AddFrame({&GFX["nico-warrior.png"],{vi2d{4+i,3}*24,{24,24}}});
pl_warrior_sonic_swing_e.AddFrame({&game->GFX_Warrior_Sheet,{vi2d{4+i,7}*24,{24,24}}}); pl_warrior_sonic_swing_e.AddFrame({&GFX["nico-warrior.png"],{vi2d{4+i,7}*24,{24,24}}});
} }
ANIMATION_DATA["WARRIOR_SWINGSWORD_N"]=pl_warrior_swing_n; ANIMATION_DATA["WARRIOR_SWINGSWORD_N"]=pl_warrior_swing_n;
ANIMATION_DATA["WARRIOR_SWINGSWORD_E"]=pl_warrior_swing_e; ANIMATION_DATA["WARRIOR_SWINGSWORD_E"]=pl_warrior_swing_e;
@ -92,13 +93,13 @@ void sig::Animation::InitializeAnimations(){
ANIMATION_DATA["WARRIOR_SWINGSONICSWORD_W"]=pl_warrior_sonic_swing_w; ANIMATION_DATA["WARRIOR_SWINGSONICSWORD_W"]=pl_warrior_sonic_swing_w;
//Ranger animations //Ranger animations
SetupClassWalkIdleAnimations(game->GFX_Ranger_Sheet,"RANGER"); SetupClassWalkIdleAnimations(GFX["nico-ranger.png"],"RANGER");
Animate2D::FrameSequence pl_ranger_shoot_s,pl_ranger_shoot_n,pl_ranger_shoot_e,pl_ranger_shoot_w; Animate2D::FrameSequence pl_ranger_shoot_s,pl_ranger_shoot_n,pl_ranger_shoot_e,pl_ranger_shoot_w;
for(int i=0;i<3;i++){ for(int i=0;i<3;i++){
pl_ranger_shoot_s.AddFrame({&game->GFX_Ranger_Sheet,{vi2d{3+i,0}*24,{24,24}}}); pl_ranger_shoot_s.AddFrame({&GFX["nico-ranger.png"],{vi2d{3+i,0}*24,{24,24}}});
pl_ranger_shoot_n.AddFrame({&game->GFX_Ranger_Sheet,{vi2d{3+i,1}*24,{24,24}}}); pl_ranger_shoot_n.AddFrame({&GFX["nico-ranger.png"],{vi2d{3+i,1}*24,{24,24}}});
pl_ranger_shoot_e.AddFrame({&game->GFX_Ranger_Sheet,{vi2d{3+i,3}*24,{24,24}}}); pl_ranger_shoot_e.AddFrame({&GFX["nico-ranger.png"],{vi2d{3+i,3}*24,{24,24}}});
pl_ranger_shoot_w.AddFrame({&game->GFX_Ranger_Sheet,{vi2d{3+i,2}*24,{24,24}}}); pl_ranger_shoot_w.AddFrame({&GFX["nico-ranger.png"],{vi2d{3+i,2}*24,{24,24}}});
} }
ANIMATION_DATA["RANGER_SHOOT_S"]=pl_ranger_shoot_s; ANIMATION_DATA["RANGER_SHOOT_S"]=pl_ranger_shoot_s;
ANIMATION_DATA["RANGER_SHOOT_N"]=pl_ranger_shoot_n; ANIMATION_DATA["RANGER_SHOOT_N"]=pl_ranger_shoot_n;
@ -106,107 +107,119 @@ void sig::Animation::InitializeAnimations(){
ANIMATION_DATA["RANGER_SHOOT_W"]=pl_ranger_shoot_w; ANIMATION_DATA["RANGER_SHOOT_W"]=pl_ranger_shoot_w;
//Wizard animations //Wizard animations
SetupClassWalkIdleAnimations(game->GFX_Wizard_Sheet,"WIZARD"); SetupClassWalkIdleAnimations(GFX["nico-wizard.png"],"WIZARD");
Animate2D::FrameSequence pl_wizard_idle_attack_s; Animate2D::FrameSequence pl_wizard_idle_attack_s;
pl_wizard_idle_attack_s.AddFrame({&game->GFX_Wizard_Sheet,{vi2d{4,0}*24,{24,24}}}); pl_wizard_idle_attack_s.AddFrame({&GFX["nico-wizard.png"],{vi2d{4,0}*24,{24,24}}});
ANIMATION_DATA["WIZARD_IDLE_ATTACK_S"]=pl_wizard_idle_attack_s; ANIMATION_DATA["WIZARD_IDLE_ATTACK_S"]=pl_wizard_idle_attack_s;
Animate2D::FrameSequence pl_wizard_idle_attack_e; Animate2D::FrameSequence pl_wizard_idle_attack_e;
pl_wizard_idle_attack_e.AddFrame({&game->GFX_Wizard_Sheet,{vi2d{4,3}*24,{24,24}}}); pl_wizard_idle_attack_e.AddFrame({&GFX["nico-wizard.png"],{vi2d{4,3}*24,{24,24}}});
ANIMATION_DATA["WIZARD_IDLE_ATTACK_E"]=pl_wizard_idle_attack_e; ANIMATION_DATA["WIZARD_IDLE_ATTACK_E"]=pl_wizard_idle_attack_e;
Animate2D::FrameSequence pl_wizard_idle_attack_w; Animate2D::FrameSequence pl_wizard_idle_attack_w;
pl_wizard_idle_attack_w.AddFrame({&game->GFX_Wizard_Sheet,{vi2d{4,2}*24,{24,24}}}); pl_wizard_idle_attack_w.AddFrame({&GFX["nico-wizard.png"],{vi2d{4,2}*24,{24,24}}});
ANIMATION_DATA["WIZARD_IDLE_ATTACK_W"]=pl_wizard_idle_attack_w; ANIMATION_DATA["WIZARD_IDLE_ATTACK_W"]=pl_wizard_idle_attack_w;
Animate2D::FrameSequence pl_wizard_idle_attack_n; Animate2D::FrameSequence pl_wizard_idle_attack_n;
pl_wizard_idle_attack_n.AddFrame({&game->GFX_Wizard_Sheet,{vi2d{4,1}*24,{24,24}}}); pl_wizard_idle_attack_n.AddFrame({&GFX["nico-wizard.png"],{vi2d{4,1}*24,{24,24}}});
ANIMATION_DATA["WIZARD_IDLE_ATTACK_N"]=pl_wizard_idle_attack_n; ANIMATION_DATA["WIZARD_IDLE_ATTACK_N"]=pl_wizard_idle_attack_n;
Animate2D::FrameSequence pl_wizard_attack_s(0.2); Animate2D::FrameSequence pl_wizard_attack_s(0.2);
for(int i=0;i<3;i++){ for(int i=0;i<3;i++){
pl_wizard_attack_s.AddFrame({&game->GFX_Wizard_Sheet,{vi2d{4+i,0}*24,{24,24}}}); pl_wizard_attack_s.AddFrame({&GFX["nico-wizard.png"],{vi2d{4+i,0}*24,{24,24}}});
if(i==1){ if(i==1){
pl_wizard_attack_s.AddFrame({&game->GFX_Wizard_Sheet,{vi2d{4,0}*24,{24,24}}}); pl_wizard_attack_s.AddFrame({&GFX["nico-wizard.png"],{vi2d{4,0}*24,{24,24}}});
} }
} }
ANIMATION_DATA["WIZARD_ATTACK_S"]=pl_wizard_attack_s; ANIMATION_DATA["WIZARD_ATTACK_S"]=pl_wizard_attack_s;
Animate2D::FrameSequence pl_wizard_attack_e(0.2); Animate2D::FrameSequence pl_wizard_attack_e(0.2);
for(int i=0;i<3;i++){ for(int i=0;i<3;i++){
pl_wizard_attack_e.AddFrame({&game->GFX_Wizard_Sheet,{vi2d{4+i,3}*24,{24,24}}}); pl_wizard_attack_e.AddFrame({&GFX["nico-wizard.png"],{vi2d{4+i,3}*24,{24,24}}});
if(i==1){ if(i==1){
pl_wizard_attack_e.AddFrame({&game->GFX_Wizard_Sheet,{vi2d{4,3}*24,{24,24}}}); pl_wizard_attack_e.AddFrame({&GFX["nico-wizard.png"],{vi2d{4,3}*24,{24,24}}});
} }
} }
ANIMATION_DATA["WIZARD_ATTACK_E"]=pl_wizard_attack_e; ANIMATION_DATA["WIZARD_ATTACK_E"]=pl_wizard_attack_e;
Animate2D::FrameSequence pl_wizard_attack_w(0.2); Animate2D::FrameSequence pl_wizard_attack_w(0.2);
for(int i=0;i<3;i++){ for(int i=0;i<3;i++){
pl_wizard_attack_w.AddFrame({&game->GFX_Wizard_Sheet,{vi2d{4+i,2}*24,{24,24}}}); pl_wizard_attack_w.AddFrame({&GFX["nico-wizard.png"],{vi2d{4+i,2}*24,{24,24}}});
if(i==1){ if(i==1){
pl_wizard_attack_w.AddFrame({&game->GFX_Wizard_Sheet,{vi2d{4,2}*24,{24,24}}}); pl_wizard_attack_w.AddFrame({&GFX["nico-wizard.png"],{vi2d{4,2}*24,{24,24}}});
} }
} }
ANIMATION_DATA["WIZARD_ATTACK_W"]=pl_wizard_attack_w; ANIMATION_DATA["WIZARD_ATTACK_W"]=pl_wizard_attack_w;
Animate2D::FrameSequence pl_wizard_attack_n(0.2); Animate2D::FrameSequence pl_wizard_attack_n(0.2);
for(int i=0;i<3;i++){ for(int i=0;i<3;i++){
pl_wizard_attack_n.AddFrame({&game->GFX_Wizard_Sheet,{vi2d{4+i,1}*24,{24,24}}}); pl_wizard_attack_n.AddFrame({&GFX["nico-wizard.png"],{vi2d{4+i,1}*24,{24,24}}});
if(i==1){ if(i==1){
pl_wizard_attack_n.AddFrame({&game->GFX_Wizard_Sheet,{vi2d{4,1}*24,{24,24}}}); pl_wizard_attack_n.AddFrame({&GFX["nico-wizard.png"],{vi2d{4,1}*24,{24,24}}});
} }
} }
ANIMATION_DATA["WIZARD_ATTACK_N"]=pl_wizard_attack_n; ANIMATION_DATA["WIZARD_ATTACK_N"]=pl_wizard_attack_n;
Animate2D::FrameSequence pl_wizard_cast_s(0.1); Animate2D::FrameSequence pl_wizard_cast_s(0.1);
for(int i=0;i<2;i++){ for(int i=0;i<2;i++){
pl_wizard_cast_s.AddFrame({&game->GFX_Wizard_Sheet,{vi2d{7+i,0}*24,{24,24}}}); pl_wizard_cast_s.AddFrame({&GFX["nico-wizard.png"],{vi2d{7+i,0}*24,{24,24}}});
} }
ANIMATION_DATA["WIZARD_CAST_S"]=pl_wizard_cast_s; ANIMATION_DATA["WIZARD_CAST_S"]=pl_wizard_cast_s;
Animate2D::FrameSequence pl_wizard_cast_e(0.1); Animate2D::FrameSequence pl_wizard_cast_e(0.1);
for(int i=0;i<2;i++){ for(int i=0;i<2;i++){
pl_wizard_cast_e.AddFrame({&game->GFX_Wizard_Sheet,{vi2d{7+i,3}*24,{24,24}}}); pl_wizard_cast_e.AddFrame({&GFX["nico-wizard.png"],{vi2d{7+i,3}*24,{24,24}}});
} }
ANIMATION_DATA["WIZARD_CAST_E"]=pl_wizard_cast_e; ANIMATION_DATA["WIZARD_CAST_E"]=pl_wizard_cast_e;
Animate2D::FrameSequence pl_wizard_cast_n(0.1); Animate2D::FrameSequence pl_wizard_cast_n(0.1);
for(int i=0;i<2;i++){ for(int i=0;i<2;i++){
pl_wizard_cast_n.AddFrame({&game->GFX_Wizard_Sheet,{vi2d{7+i,1}*24,{24,24}}}); pl_wizard_cast_n.AddFrame({&GFX["nico-wizard.png"],{vi2d{7+i,1}*24,{24,24}}});
} }
ANIMATION_DATA["WIZARD_CAST_N"]=pl_wizard_cast_n; ANIMATION_DATA["WIZARD_CAST_N"]=pl_wizard_cast_n;
Animate2D::FrameSequence pl_wizard_cast_w(0.1); Animate2D::FrameSequence pl_wizard_cast_w(0.1);
for(int i=0;i<2;i++){ for(int i=0;i<2;i++){
pl_wizard_cast_w.AddFrame({&game->GFX_Wizard_Sheet,{vi2d{7+i,2}*24,{24,24}}}); pl_wizard_cast_w.AddFrame({&GFX["nico-wizard.png"],{vi2d{7+i,2}*24,{24,24}}});
} }
ANIMATION_DATA["WIZARD_CAST_W"]=pl_wizard_cast_w; ANIMATION_DATA["WIZARD_CAST_W"]=pl_wizard_cast_w;
CreateHorizontalAnimationSequence(game->GFX_Effect_GroundSlam_Back,5,{64,64},"GROUND_SLAM_ATTACK_BACK",{0.02,Animate2D::Style::OneShot}); CreateHorizontalAnimationSequence("ground-slam-attack-back.png",5,{64,64},{0.02,Animate2D::Style::OneShot});
CreateHorizontalAnimationSequence(game->GFX_Effect_GroundSlam_Front,5,{64,64},"GROUND_SLAM_ATTACK_FRONT",{0.02,Animate2D::Style::OneShot}); CreateHorizontalAnimationSequence("ground-slam-attack-front.png",5,{64,64},{0.02,Animate2D::Style::OneShot});
CreateHorizontalAnimationSequence(game->GFX_Battlecry_Effect,5,{84,84},"BATTLECRY_EFFECT",{0.02,Animate2D::Style::OneShot}); CreateHorizontalAnimationSequence("battlecry_effect.png",5,{84,84},{0.02,Animate2D::Style::OneShot});
CreateHorizontalAnimationSequence(game->GFX_SonicSlash,4,{60,60},"SONICSLASH",{0.04,Animate2D::Style::OneShot}); CreateHorizontalAnimationSequence("sonicslash.png",4,{60,60},{0.04,Animate2D::Style::OneShot});
CreateStillAnimation(game->GFX_EnergyBolt,{24,24},"ENERGY_BOLT"); CreateStillAnimation("energy_bolt.png",{24,24});
CreateHorizontalAnimationSequence(game->GFX_EnergyParticle,3,{3,3},"ENERGY_PARTICLE"); CreateHorizontalAnimationSequence("energy_particle.png",3,{3,3});
CreateHorizontalAnimationSequence(game->GFX_Splash_Effect,5,{24,24},"SPLASH_EFFECT",{0.05}); CreateHorizontalAnimationSequence("splash_effect.png",5,{24,24},{0.05});
CreateStillAnimation(game->GFX_BulletCircle,{3,3},"DOT_PARTICLE"); CreateStillAnimation("circle.png",{3,3});
CreateHorizontalAnimationSequence(game->GFX_LightningBolt,5,{24,24},"LIGHTNING_BOLT",{0.03,Animate2D::Style::PingPong}); CreateHorizontalAnimationSequence("lightning_bolt.png",5,{24,24},{0.03,Animate2D::Style::PingPong});
CreateStillAnimation(game->GFX_LightningBoltParticle1,{5,5},"LIGHTNING_BOLT_PARTICLE1"); CreateStillAnimation("lightning_bolt_part1.png",{5,5});
CreateStillAnimation(game->GFX_LightningBoltParticle2,{5,5},"LIGHTNING_BOLT_PARTICLE2"); CreateStillAnimation("lightning_bolt_part2.png",{5,5});
CreateStillAnimation(game->GFX_LightningBoltParticle3,{5,5},"LIGHTNING_BOLT_PARTICLE3"); CreateStillAnimation("lightning_bolt_part3.png",{5,5});
CreateStillAnimation(game->GFX_LightningBoltParticle4,{5,5},"LIGHTNING_BOLT_PARTICLE4"); CreateStillAnimation("lightning_bolt_part4.png",{5,5});
CreateStillAnimation(game->GFX_ChainLightning,{1,9},"CHAIN_LIGHTNING"); CreateStillAnimation("chain_lightning.png",{1,9});
CreateHorizontalAnimationSequence(game->GFX_LightningSplash,5,{24,24},"LIGHTNING_SPLASH"); CreateHorizontalAnimationSequence("lightning_splash_effect.png",5,{24,24});
CreateStillAnimation(game->GFX_Meteor,{192,192},"METEOR"); CreateHorizontalAnimationSequence("monsters/Slime King - Cast.png",10,{24,24},{0.04});
CreateStillAnimation("meteor.png",{192,192});
for(int i=0;i<5;i++){ for(int i=0;i<5;i++){
Animate2D::FrameSequence firering; Animate2D::FrameSequence firering;
firering.AddFrame({&game->GFX_LightningSplash,{{i*24,0},{24,24}}}); firering.AddFrame({&GFX["fire_ring"+std::to_string(i)+".png"],{{0,0},{24,24}}});
ANIMATION_DATA["FIRE_RING"+std::to_string(i+1)]=firering; ANIMATION_DATA["fire_ring"+std::to_string(i)+".png"]=firering;
}
CreateStillAnimation("arrow.png",{24,24});
CreateStillAnimation("charged_shot_arrow.png",{48,48});
CreateStillAnimation("laser.png",{5,1});
CreateStillAnimation("range_indicator.png",{24,24});
for(auto&dat:GFX){
std::string imgFile=dat.first;
if(!ANIMATION_DATA.count(imgFile)){
std::cout<<"WARNING! Animation data for "<<imgFile<<" not found! Auto-generating..."<<std::endl;
CreateStillAnimation(imgFile,GFX[imgFile].Sprite()->Size());
std::map<int,int>test;
test.begin();
}
} }
CreateStillAnimation(game->GFX_Arrow,{24,24},"ARROW");
CreateStillAnimation(game->GFX_ChargedArrow,{48,48},"CHARGED_ARROW");
CreateStillAnimation(game->GFX_Laser,{5,1},"LASER");
CreateStillAnimation(game->GFX_RangeIndicator,{24,24},"RANGE_INDICATOR");
} }
void sig::Animation::SetupPlayerAnimations(){ void sig::Animation::SetupPlayerAnimations(){

@ -10,7 +10,7 @@ INCLUDE_game
Arrow::Arrow(vf2d pos,vf2d targetPos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col) Arrow::Arrow(vf2d pos,vf2d targetPos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col)
:finalDistance(geom2d::line(pos,targetPos).length()),acc(PI/2*"Ranger.Auto Attack.ArrowSpd"_F), :finalDistance(geom2d::line(pos,targetPos).length()),acc(PI/2*"Ranger.Auto Attack.ArrowSpd"_F),
Bullet(pos,vel,radius,damage, Bullet(pos,vel,radius,damage,
"ARROW",upperLevel,false,INFINITE,true,friendly,col){} "arrow.png",upperLevel,false,INFINITE,true,friendly,col){}
void Arrow::Update(float fElapsedTime){ void Arrow::Update(float fElapsedTime){
float speed=vel.mag(); float speed=vel.mag();
@ -26,7 +26,7 @@ bool Arrow::PlayerHit(Player*player)
{ {
deactivated=true; deactivated=true;
fadeOutTime=0.2f; fadeOutTime=0.2f;
game->AddEffect(std::make_unique<Effect>(player->GetPos(),0,"SPLASH_EFFECT",upperLevel,player->GetSizeMult(),0.25)); game->AddEffect(std::make_unique<Effect>(player->GetPos(),0,"splash_effect.png",upperLevel,player->GetSizeMult(),0.25));
return false; return false;
} }
@ -34,6 +34,6 @@ bool Arrow::MonsterHit(Monster& monster)
{ {
deactivated=true; deactivated=true;
fadeOutTime=0.2f; fadeOutTime=0.2f;
game->AddEffect(std::make_unique<Effect>(monster.GetPos(),0,"SPLASH_EFFECT",upperLevel,monster.GetSizeMult(),0.25)); game->AddEffect(std::make_unique<Effect>(monster.GetPos(),0,"splash_effect.png",upperLevel,monster.GetSizeMult(),0.25));
return false; return false;
} }

@ -5,6 +5,7 @@
INCLUDE_ANIMATION_DATA INCLUDE_ANIMATION_DATA
INCLUDE_game INCLUDE_game
INCLUDE_GFX
Bullet::Bullet(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col,vf2d scale) Bullet::Bullet(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col,vf2d scale)
:pos(pos),vel(vel),radius(radius),damage(damage),col(col),friendly(friendly),upperLevel(upperLevel),scale(scale){}; :pos(pos),vel(vel),radius(radius),damage(damage),col(col),friendly(friendly),upperLevel(upperLevel),scale(scale){};
@ -36,8 +37,8 @@ void Bullet::Draw(){
if(animated){ if(animated){
game->view.DrawPartialRotatedDecal(pos,GetFrame().GetSourceImage()->Decal(),rotates?atan2(vel.y,vel.x)-PI/2:0,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,scale,fadeOutTime==0?col:Pixel{col.r,col.g,col.b,lerp(col.a,0,1-((fadeOutTime-fadeOutTimer)/fadeOutTime))}); game->view.DrawPartialRotatedDecal(pos,GetFrame().GetSourceImage()->Decal(),rotates?atan2(vel.y,vel.x)-PI/2:0,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,scale,fadeOutTime==0?col:Pixel{col.r,col.g,col.b,lerp(col.a,0,1-((fadeOutTime-fadeOutTimer)/fadeOutTime))});
} else { } else {
game->view.DrawDecal(pos-game->GFX_BulletCircle.Sprite()->Size()*scale/2,game->GFX_BulletCircle.Decal(),scale,fadeOutTime==0?col:Pixel{col.r,col.g,col.b,lerp(col.a,0,1-((fadeOutTime-fadeOutTimer)/fadeOutTime))}); game->view.DrawDecal(pos-GFX["circle.png"].Sprite()->Size()*scale/2,GFX["circle.png"].Decal(),scale,fadeOutTime==0?col:Pixel{col.r,col.g,col.b,lerp(col.a,0,1-((fadeOutTime-fadeOutTimer)/fadeOutTime))});
game->view.DrawDecal(pos-game->GFX_BulletCircle.Sprite()->Size()*scale/2,game->GFX_BulletCircleOutline.Decal(),scale,fadeOutTime==0?WHITE:Pixel{WHITE.r,WHITE.g,WHITE.b,lerp(WHITE.a,0,1-((fadeOutTime-fadeOutTimer)/fadeOutTime))}); game->view.DrawDecal(pos-GFX["circle.png"].Sprite()->Size()*scale/2,GFX["circle_outline.png"].Decal(),scale,fadeOutTime==0?WHITE:Pixel{WHITE.r,WHITE.g,WHITE.b,lerp(WHITE.a,0,1-((fadeOutTime-fadeOutTimer)/fadeOutTime))});
} }
} }

@ -4,4 +4,4 @@ debug.sh:8125f303032b6cbc137223df63d10096 -
lines.sh:3b907786f7fc9204025993016c9080de - lines.sh:3b907786f7fc9204025993016c9080de -
release.sh:b1ce8461a303e8e7aa9ed74259db3873 - release.sh:b1ce8461a303e8e7aa9ed74259db3873 -
temp:d41d8cd98f00b204e9800998ecf8427e - temp:d41d8cd98f00b204e9800998ecf8427e -
web.sh:e196c0bb38ff4cd9428b4a4e56f500a9 - web.sh:cd3b8a99e208244dee7576bc23c0dc80 -

@ -12,12 +12,12 @@ source ../emsdk/emsdk_env.sh
if [ ! -f "pixelGameEngine_wasm.o" ] if [ ! -f "pixelGameEngine_wasm.o" ]
then then
printf "Pixel Game Engine compile object missing. Compiling for the first time..." printf "Pixel Game Engine compile object missing. Compiling for the first time..."
em++ -std=c++20 -O2 -s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=4GB -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_SDL_MIXER=2 -s USE_LIBPNG=1 -c pixelGameEngine.cpp -o pixelGameEngine_wasm.o em++ -std=c++20 -O2 ${EMSCRIPTEN_CUSTOM_PARAMS} -s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=4GB -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_SDL_MIXER=2 -s USE_LIBPNG=1 -c pixelGameEngine.cpp -o pixelGameEngine_wasm.o
fi fi
if [ -d "assets" ]; then if [ -d "assets" ]; then
em++ -std=c++20 -O2 -s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=4GB -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_SDL_MIXER=2 -s USE_LIBPNG=1 $(find . -type f -name "*.cpp" -not -path "./test/*" -not -name "pixelGameEngine.cpp") pixelGameEngine_wasm.o -o ${PROJECT_NAME}.html --preload-file ./assets em++ -std=c++20 -O2 ${EMSCRIPTEN_CUSTOM_PARAMS} -s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=4GB -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_SDL_MIXER=2 -s USE_LIBPNG=1 $(find . -type f -name "*.cpp" -not -path "./test/*" -not -name "pixelGameEngine.cpp") pixelGameEngine_wasm.o -o ${PROJECT_NAME}.html --preload-file ./assets
else else
em++ -std=c++20 -O2 -s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=4GB -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_SDL_MIXER=2 -s USE_LIBPNG=1 $(find . -type f -name "*.cpp" -not -path "./test/*" -not -name "pixelGameEngine.cpp") pixelGameEngine_wasm.o -o ${PROJECT_NAME}.html em++ -std=c++20 -O2 ${EMSCRIPTEN_CUSTOM_PARAMS} -s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=4GB -s MAX_WEBGL_VERSION=2 -s MIN_WEBGL_VERSION=2 -s USE_SDL_MIXER=2 -s USE_LIBPNG=1 $(find . -type f -name "*.cpp" -not -path "./test/*" -not -name "pixelGameEngine.cpp") pixelGameEngine_wasm.o -o ${PROJECT_NAME}.html
fi fi
cp buildtemplate.html ${PROJECT_NAME}.html cp buildtemplate.html ${PROJECT_NAME}.html

@ -10,14 +10,14 @@ INCLUDE_game
ChargedArrow::ChargedArrow(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col) ChargedArrow::ChargedArrow(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col)
:lastLaserPos(pos), :lastLaserPos(pos),
Bullet(pos,vel,radius,damage, Bullet(pos,vel,radius,damage,
"CHARGED_ARROW",upperLevel,true,INFINITE,true,friendly,col){} "charged_shot_arrow.png",upperLevel,true,INFINITE,true,friendly,col){}
void ChargedArrow::Update(float fElapsedTime){ void ChargedArrow::Update(float fElapsedTime){
geom2d::line lineToCurrentPos(geom2d::line(lastLaserPos,pos)); geom2d::line lineToCurrentPos(geom2d::line(lastLaserPos,pos));
float dist=lineToCurrentPos.length(); float dist=lineToCurrentPos.length();
if(dist>=1){ if(dist>=1){
vf2d midpoint(lineToCurrentPos.rpoint(0.5)); vf2d midpoint(lineToCurrentPos.rpoint(0.5));
game->AddEffect(std::make_unique<Effect>(midpoint,0.1,"LASER",upperLevel,vf2d{1,dist},0.3,vf2d{},Pixel{192,128,238},atan2(pos.y-lastLaserPos.y,pos.x-lastLaserPos.x)+PI/2,0,true)); game->AddEffect(std::make_unique<Effect>(midpoint,0.1,"laser.png",upperLevel,vf2d{1,dist},0.3,vf2d{},Pixel{192,128,238},atan2(pos.y-lastLaserPos.y,pos.x-lastLaserPos.x)+PI/2,0,true));
lastLaserPos=pos; lastLaserPos=pos;
} }
} }

@ -0,0 +1,665 @@
<?xml version="1.0" encoding="utf-8"?>
<ClassDiagram MajorVersion="1" MinorVersion="1">
<Class Name="Crawler" Collapsed="true">
<Position X="3.5" Y="13.75" Width="1.5" />
<TypeIdentifier>
<HashCode>OihgwhJkUjgrCYAAVgEdFoQkBECSBhEDncMJIEmEYAg=</HashCode>
<FileName>Crawler.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="Effect" Collapsed="true">
<Position X="13.75" Y="3.5" Width="1.5" />
<TypeIdentifier>
<HashCode>BAAAAAQAQAgEAAAEAIBAAAAAAAAEAAAAAAgAgAAACAA=</HashCode>
<FileName>C:\Program Files (x86)\Windows Kits\10\Include\10.0.22000.0\um\gdipluseffects.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="LightningBoltEmitter" Collapsed="true">
<Position X="6.5" Y="13.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAEAAIAAABAAABAAAAAAAAAAAAAAEAI=</HashCode>
<FileName>Emitter.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::Decal" Collapsed="true">
<Position X="20.75" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAQAAAAAAAAQAAAAAAAAAAAAABAAAAAAUAEAAAAAAgA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::GDIPlusStartup" Collapsed="true">
<Position X="26" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAEBAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::ImageLoader" Collapsed="true">
<Position X="11" Y="9.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAIAAAAAAAAAAAACAAAAAAAAAAIAAgAAAAAAAAAA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::ImageLoader_GDIPlus" Collapsed="true">
<Position X="13.25" Y="10.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAIAAAAAAAAAAAAAAAAIAAAAAAAAAgAAAAAAACAA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::ImageLoader_LibPNG" Collapsed="true">
<Position X="8.75" Y="10.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAABIAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::ImageLoader_STB" Collapsed="true">
<Position X="11" Y="10.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::PGEX" Collapsed="true">
<Position X="0.5" Y="12.5" Width="1.5" />
<TypeIdentifier>
<HashCode>gAAAAAAAABAIAACAAAAgAAAAAAAAAAAAAAAAAAAAgAA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::PixelGameEngine" Collapsed="true">
<Position X="3.5" Y="12.5" Width="1.5" />
<TypeIdentifier>
<HashCode>S5fpQ8sYZfjd1v02mw8U0Ed9QaLH2ByFmPRdWNHpuzs=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::Platform" Collapsed="true">
<Position X="5.25" Y="3.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAIgAAAEAAAABAAAAAAAACAIAAAAAAAAQAEiAAACAA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::Platform_Emscripten" Collapsed="true">
<Position X="9.75" Y="4.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAIgAAAEQACAQAAAAAAhACAIAQAAAAAAYAEiAAAAAA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::Platform_GLUT" Collapsed="true">
<Position X="0.75" Y="4.75" Width="1.5" />
<TypeIdentifier>
<HashCode>gAgIgAAAEAQAAAAAAAAAAACAJAAAQAAAAQAEiAAAAAA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::Platform_Headless" Collapsed="true">
<Position X="3" Y="4.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAIgAAAEAAAAAAAAAAAAACAIAAAAAAAAQAEiAAAAAA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::Platform_Linux" Collapsed="true">
<Position X="5.25" Y="4.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAIgSAAEAAAgAAAAAAAAACAICgAAAAAAUAEiAAAAAA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::Platform_Windows" Collapsed="true">
<Position X="7.5" Y="4.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAIgEAAEAAAABAAAAAAAAOAIAAAAAAAAUAEiAAAAQA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::Renderable" Collapsed="true">
<Position X="17.25" Y="2.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAQAgAAAAAQAAAAAAAAAAAgAAAAAAEAQEAAAAAAAAAA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::Renderer" Collapsed="true">
<Position X="3" Y="9.5" Width="1.5" />
<TypeIdentifier>
<HashCode>SAAgAAAAAIBASAAACAAAAgAAAAAEAIBAAIBAAAEACgA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::Renderer_Headless" Collapsed="true">
<Position X="0.75" Y="10.75" Width="1.5" />
<TypeIdentifier>
<HashCode>SAAAAAAAAIBASAAACAAAAgAAAAAEAIBAAIBAAAEAAgA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::Renderer_OGL10" Collapsed="true">
<Position X="3" Y="10.75" Width="1.5" />
<TypeIdentifier>
<HashCode>SAAAASAAQIBASCAACAAAAgAAAAAGAIBAAMJUAAEAAgA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::Renderer_OGL33" Collapsed="true">
<Position X="5.25" Y="10.75" Width="1.5" />
<TypeIdentifier>
<HashCode>SCghAyFBQIBWSCIAGAAAIgABQAAGBJhBAsJMEEEACgg=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::ResourcePack" Collapsed="true">
<Position X="19" Y="2.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAgAAAAAEAAAIAAIBAIAgAAAAAAAAAAAACgIAIAAA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::Sprite" Collapsed="true">
<Position X="22.5" Y="2.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAABABBAEAAQgAQBQAAAAABAAAAAIAAQAAEAAgAAEAI=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::TileTransformedView" Collapsed="true">
<Position X="0.5" Y="15.25" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAABAAAAAAAEAAAAAEAAAAAAAIAAAAEAIA=</HashCode>
<FileName>olcPGEX_TransformedView.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::TransformedView" Collapsed="true">
<Position X="0.5" Y="13.75" Width="1.5" />
<TypeIdentifier>
<HashCode>ABXBQAQAAFAGAzQACAMCyEQSUAAECDAQAsDE4AAIAog=</HashCode>
<FileName>olcPGEX_TransformedView.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::utils::Camera2D" Collapsed="true">
<Position X="20.75" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>JDQCAAACoCBAAhIBBAAAAAiAAAgAECAAAAIAAXAAARY=</HashCode>
<FileName>olcUTIL_Camera2D.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::utils::datafile" Collapsed="true">
<Position X="22.5" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>EgACAAIAMCAAAAIIAEAABAAgAQEAACAAAAACCAGAAIA=</HashCode>
<FileName>olcUTIL_DataFile.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::utils::datafiledoubledata" Collapsed="true">
<Position X="24.25" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAIAAAAAAAAAAAAAAEAAAAAAEAAAAAAAAQAAAAAAA=</HashCode>
<FileName>olcUTIL_DataFile.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::utils::datafilefloatdata" Collapsed="true">
<Position X="26" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAEAAAAAAECAAAAAAAQAAAAAAA=</HashCode>
<FileName>olcUTIL_DataFile.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::utils::datafileintdata" Collapsed="true">
<Position X="17.25" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAEAAAAAAUAAAAAAAAQAAAAAAA=</HashCode>
<FileName>olcUTIL_DataFile.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::utils::datafilestringdata" Collapsed="true">
<Position X="19" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAgAAAAAAAAAAAAAAAEAAAAAAEAAAAAAAAQAAAAAAA=</HashCode>
<FileName>olcUTIL_DataFile.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::utils::Animate2D::Animation&lt;StatesEnum&gt;" Collapsed="true">
<Position X="19" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAEAAAAAEABAAAgIAAAAAAAAAAAAAAAAAABAAACAA=</HashCode>
<FileName>olcUTIL_Animate2D.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::utils::Animate2D::Frame" Collapsed="true">
<Position X="22.5" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAEAAAEAAAAAIE=</HashCode>
<FileName>olcUTIL_Animate2D.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="olc::utils::Animate2D::FrameSequence" Collapsed="true">
<Position X="24.25" Y="1.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAEAAAACAAAAEAAAAABAAAEAAAAAAAAEAAgBAAAAA=</HashCode>
<FileName>olcUTIL_Animate2D.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="safemap&lt;T, O&gt;" Collapsed="true">
<Position X="20.75" Y="2.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAEAAAABAAEAAAAAAAAAAAAAEAAAAAAAAAAAAAAAA=</HashCode>
<FileName>safemap.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="sig::Animation" Collapsed="true">
<Position X="17.25" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>ACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAA=</HashCode>
<FileName>Animation.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="TMXParser" Collapsed="true">
<Position X="24.25" Y="2.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAEAABYQAAAAAEAAAAACABIAAAKAAAAAAAAAA=</HashCode>
<FileName>TMXParser.h</FileName>
</TypeIdentifier>
</Class>
<Class Name="TSXParser" Collapsed="true">
<Position X="26" Y="2.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAIAAAAEEAAAAAAAAAAAAAAAAAAAAAAAIgAACAAQAAA=</HashCode>
<FileName>TSXParser.h</FileName>
</TypeIdentifier>
</Class>
<Struct Name="Ability" Collapsed="true">
<Position X="17.25" Y="3.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAABAAAAAAAAwACABAAAAAAACAEAAACAAAAAAAAAAA=</HashCode>
<FileName>Ability.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="AnimationData" Collapsed="true">
<Position X="19" Y="3.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAEAAAAAAAAAEAAAAAAAAAAAAAAA=</HashCode>
<FileName>Animation.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="Arrow" Collapsed="true">
<Position X="9.75" Y="7.75" Width="1.5" />
<TypeIdentifier>
<HashCode>CAQAQAAAAAABAAAAAIgAAAAAAAAAAAAAAAgAAAAAAAA=</HashCode>
<FileName>BulletTypes.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="Buff" Collapsed="true">
<Position X="22.5" Y="3.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAIAAAAAAAAAAAAAAAAAAAABCAAAAAAAAAAAAAA=</HashCode>
<FileName>Buff.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="Bullet" Collapsed="true">
<Position X="5.25" Y="6.5" Width="1.5" />
<TypeIdentifier>
<HashCode>CgREEAAACAAAggAAIKgABYACAAAAABAMAEAAgQBQAgA=</HashCode>
<FileName>Bullet.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="CastInfo" Collapsed="true">
<Position X="24.25" Y="3.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAABAAAEAAAAAIAACAAAAAA=</HashCode>
<FileName>Player.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="ChargedArrow" Collapsed="true">
<Position X="0.75" Y="7.75" Width="1.5" />
<TypeIdentifier>
<HashCode>CAQAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAABAAAAAAAE=</HashCode>
<FileName>BulletTypes.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="DamageNumber" Collapsed="true">
<Position X="26" Y="3.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAgAAAAAIAAAwAAAAAAAAIACAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>DamageNumber.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="Emitter" Collapsed="true">
<Position X="6.5" Y="12.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAQAAAgAAAAAAAAAAAAAABAABAAAAACIAAgAAAAAAAA=</HashCode>
<FileName>Emitter.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="EnergyBolt" Collapsed="true">
<Position X="5.25" Y="7.75" Width="1.5" />
<TypeIdentifier>
<HashCode>CAQAAAAACAAAAAAAAAgAAAAAAAAEAAAAAAAAAAAAAAA=</HashCode>
<FileName>BulletTypes.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="FireBolt" Collapsed="true">
<Position X="7.5" Y="7.75" Width="1.5" />
<TypeIdentifier>
<HashCode>CAQAAAAAAAAAAAAAAAgAAAAAAAAEAAAAAAAAAAAQAAA=</HashCode>
<FileName>BulletTypes.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="LayerTag" Collapsed="true">
<Position X="22.5" Y="4.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAACAAAAAAAAAAAAAAAAAAAgAAACAAAAAAAAAAAAA=</HashCode>
<FileName>TMXParser.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="LightningBolt" Collapsed="true">
<Position X="3" Y="7.75" Width="1.5" />
<TypeIdentifier>
<HashCode>CAQAAAAAAAAAAAAAAAgAAAAAAAAkAAAAAAAAAAAAAAA=</HashCode>
<FileName>BulletTypes.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="Map" Collapsed="true">
<Position X="24.25" Y="4.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAQAAAQAAAAQAAACAAAAAAAAAAAAAAAACACAAEAAAAA=</HashCode>
<FileName>TMXParser.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="MapTag" Collapsed="true">
<Position X="26" Y="4.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAIAAAAAAQAQAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>TMXParser.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="Meteor" Collapsed="true">
<Position X="12.5" Y="4.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAQAAAAAAAAAQgAAAAEAAAAAAAAAAAAAAAAAAACAAAA=</HashCode>
<FileName>Effect.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="Monster" Collapsed="true">
<Position X="17.25" Y="5.75" Width="1.5" />
<Compartments>
<Compartment Name="Nested Types" Collapsed="false" />
</Compartments>
<NestedTypes>
<Struct Name="Monster::STRATEGY" Collapsed="true">
<TypeIdentifier>
<NewMemberFileName>Monster.h</NewMemberFileName>
</TypeIdentifier>
</Struct>
</NestedTypes>
<TypeIdentifier>
<HashCode>FSSAFFAEAKB4CxYAIKAOBIgBIYYC8gAEikFMCRCwkgE=</HashCode>
<FileName>Monster.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="MonsterData" Collapsed="true">
<Position X="19" Y="5.75" Width="1.5" />
<TypeIdentifier>
<HashCode>EAAACGAAsABAAQEQAIAAgAAQAAAEECAQgABAAiAQIkA=</HashCode>
<FileName>Monster.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="MonsterSpawner" Collapsed="true">
<Position X="20.75" Y="5.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAIQAAAAAAAAIgIAIgAAAAAAAAAAAgBAgAAgAA=</HashCode>
<FileName>Monster.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="olc::DecalInstance" Collapsed="true">
<Position X="17.25" Y="4.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AgAAAACAAAAAAACAAAAAAIAAAAAQBAAAAAgAAAAAAgA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="olc::HWButton" Collapsed="true">
<Position X="19" Y="4.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAgAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAgA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="olc::LayerDesc" Collapsed="true">
<Position X="20.75" Y="4.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AkAIAAAAAAAAABAABQAACAAAAAABQAAAAAAAAAAAAAA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="olc::Pixel" Collapsed="true">
<Position X="24.25" Y="5.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAIAAAAAAAAAAAAAABAQAAAAAAAAAAAAAgAAAAAAA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="olc::ResourceBuffer" Collapsed="true">
<Position X="17.25" Y="6.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAIAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="olc::utils::Animate2D::AnimationState" Collapsed="true">
<Position X="20.75" Y="3.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAA=</HashCode>
<FileName>olcUTIL_Animate2D.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="Pathfinding" Collapsed="true">
<Position X="22.5" Y="5.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAQAEAAgAAAAAAAAAAAAAQAAAAAAAIAA=</HashCode>
<FileName>Pathfinding.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="Player" Collapsed="true">
<Position X="6.5" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>EO9g1XQE4IJq4TbQBqAlYY0RO0YCNkh05FFEjTtkojQ=</HashCode>
<FileName>Player.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="PrecastData" Collapsed="true">
<Position X="26" Y="5.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAIAAAAAAAEAIAAAAABAAAAAAAAAAAgAAAAAAA=</HashCode>
<FileName>Ability.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="PulsatingFire" Collapsed="true">
<Position X="14.75" Y="4.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAQBAAAAAAAAAgAAAAAAAEAAAAAAAAAAAAAAEAAAAAE=</HashCode>
<FileName>Effect.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="Ranger" Collapsed="true">
<Position X="3.25" Y="1.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAkAwQEAQAAIqQBQAAAEIAQACAAEMgAABAAEAAkgAgA=</HashCode>
<FileName>Player.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="SpawnerTag" Collapsed="true">
<Position X="19" Y="6.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAQAAIAAAAAIAAAAAAAAAAACAAAAAAAAAAAAA=</HashCode>
<FileName>TMXParser.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="Thief" Collapsed="true">
<Position X="7.75" Y="1.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAkAwQEAYAAIoQBQAAAEIAQACAAEMgAABAAEAAkgAgA=</HashCode>
<FileName>Player.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="TileCollisionData" Collapsed="true">
<Position X="20.75" Y="6.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Map.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="TileGroup" Collapsed="true">
<Position X="22.5" Y="6.75" Width="1.5" />
<TypeIdentifier>
<HashCode>CDAAAAAISAgAAAAAAAAAAAAAAgAAACAAAAkAADAAQAA=</HashCode>
<FileName>Map.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="TileRenderData" Collapsed="true">
<Position X="24.25" Y="6.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAEAAAAAAAAAAAAAIAAQAAAAAAAIAAAAAAAAAA=</HashCode>
<FileName>Map.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="Tileset" Collapsed="true">
<Position X="26" Y="6.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAIAAAgAAAAAAgAAAAIAAAQAAAAAAAAAABAAAAAA=</HashCode>
<FileName>TSXParser.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="TilesetData" Collapsed="true">
<Position X="17.25" Y="7.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAgAAAAAAAAAAAAAAAAIAAAAAAAAAAIAAEAQIAAAA=</HashCode>
<FileName>Map.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="TilesheetData" Collapsed="true">
<Position X="19" Y="7.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAIAAAAAAAAAA=</HashCode>
<FileName>Crawler.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="Trapper" Collapsed="true">
<Position X="1" Y="1.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAkAwQEAQAAIoQBQAAAEIAQECAAEMgAABAAEAAkgAgA=</HashCode>
<FileName>Player.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="Warrior" Collapsed="true">
<Position X="12.25" Y="1.75" Width="1.5" />
<TypeIdentifier>
<HashCode>ACkAgQEAQAAIoQBQAAAEAAQACAAEIgAAAAAEAAkAAgA=</HashCode>
<FileName>Player.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="Witch" Collapsed="true">
<Position X="10" Y="1.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAkAwQEAQAAIoQBQAAAEKAQACAAEMgAABAAEAAkgAgA=</HashCode>
<FileName>Player.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="Wizard" Collapsed="true">
<Position X="5.5" Y="1.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAkAwQEAQAAIoQBQAAAEIAQACAAEMgAABAIEAAkgAgA=</HashCode>
<FileName>Player.h</FileName>
</TypeIdentifier>
</Struct>
<Struct Name="XMLTag" Collapsed="true">
<Position X="20.75" Y="7.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AACAACAgACAAAIAAAAAAAAAAAAAAACAAAAAQAAAAQAA=</HashCode>
<FileName>TMXParser.h</FileName>
</TypeIdentifier>
</Struct>
<Enum Name="Attribute" Collapsed="true">
<Position X="17.25" Y="9" Width="1.5" />
<TypeIdentifier>
<HashCode>AQQBgAAAAAoAAIAAAAAAAAIAJAAAAACAAAAAAAAAAAI=</HashCode>
<FileName>MonsterAttribute.h</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="BuffType" Collapsed="true">
<Position X="19" Y="9" Width="1.5" />
<TypeIdentifier>
<HashCode>AAgAIAAAAAAAAAAAAAAAAAAAAEAgAAAAAAAAAAAAAAA=</HashCode>
<FileName>Buff.h</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="Class" Collapsed="true">
<Position X="20.75" Y="9" Width="1.5" />
<TypeIdentifier>
<HashCode>AACAAAAAAAAAAAAAAAgAAAAEAAggAAAAAAAAAAAACAA=</HashCode>
<FileName>Class.h</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="MapName" Collapsed="true">
<Position X="17.25" Y="9.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAABAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Map.h</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="MonsterAnimation" Collapsed="true">
<Position X="19" Y="9.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAEAAAAAAAAgAAACAAAAAAAQAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Monster.h</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="olc::DecalMode" Collapsed="true">
<Position X="22.5" Y="9" Width="1.5" />
<TypeIdentifier>
<HashCode>AAgAAAAAACCAAAAAABAAAIAAAAAAAAAAAAAgAAAABAA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="olc::DecalStructure" Collapsed="true">
<Position X="24.25" Y="9" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAACAAAAAAAAAAAAAIAAAAEQAAAAAAAAAAAAAAA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="olc::Key" Collapsed="true">
<Position X="26" Y="9" Width="1.5" />
<TypeIdentifier>
<HashCode>IgBKPCYRIAQCigCAAQAAwU8kkgMKYJhzAAAAvv//YQE=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="olc::rcode" Collapsed="true">
<Position X="20.75" Y="9.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAgCA=</HashCode>
<FileName>olcPixelGameEngine.h</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="olc::utils::Animate2D::Style" Collapsed="true">
<Position X="24.25" Y="9.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAQAAAAAAAAACAAAAAAAAICAAAAAAA=</HashCode>
<FileName>olcUTIL_Animate2D.h</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="State::State" Collapsed="true">
<Position X="22.5" Y="9.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAABAQCAAgCAACABABEBKAgACAAAABAgAAAAAAAA=</HashCode>
<FileName>State.h</FileName>
</TypeIdentifier>
</Enum>
<Font Name="Segoe UI" Size="9" />
</ClassDiagram>

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

@ -26,6 +26,7 @@ std::vector<Monster>MONSTER_LIST;
std::vector<MonsterSpawner>SPAWNER_LIST; std::vector<MonsterSpawner>SPAWNER_LIST;
std::vector<std::shared_ptr<DamageNumber>>DAMAGENUMBER_LIST; std::vector<std::shared_ptr<DamageNumber>>DAMAGENUMBER_LIST;
std::vector<std::unique_ptr<Bullet>>BULLET_LIST; std::vector<std::unique_ptr<Bullet>>BULLET_LIST;
safemap<std::string,Renderable>GFX;
safemap<std::string,MapName>LEVEL_NAMES; safemap<std::string,MapName>LEVEL_NAMES;
utils::datafile DATA; utils::datafile DATA;
Crawler*game; Crawler*game;
@ -62,6 +63,8 @@ Crawler::Crawler()
std::string MONSTERSTRATEGIES_CONFIG = CONFIG_PATH + "monsterstrategies_config"_S; std::string MONSTERSTRATEGIES_CONFIG = CONFIG_PATH + "monsterstrategies_config"_S;
utils::datafile::Read(DATA,MONSTERSTRATEGIES_CONFIG); utils::datafile::Read(DATA,MONSTERSTRATEGIES_CONFIG);
DEBUG_PATHFINDING="debug_pathfinding"_I;
for(std::string&cl:DATA.GetProperty("class_list").GetValues()){ for(std::string&cl:DATA.GetProperty("class_list").GetValues()){
std::cout<<cl<<std::endl; std::cout<<cl<<std::endl;
utils::datafile::Read(DATA,CONFIG_PATH + "class_directory"_S + cl + ".txt"); utils::datafile::Read(DATA,CONFIG_PATH + "class_directory"_S + cl + ".txt");
@ -70,7 +73,6 @@ Crawler::Crawler()
} }
bool Crawler::OnUserCreate(){ bool Crawler::OnUserCreate(){
InitializeLevels(); InitializeLevels();
player=std::make_unique<Warrior>(); player=std::make_unique<Warrior>();
@ -82,41 +84,18 @@ bool Crawler::OnUserCreate(){
camera.SetWorldBoundary({0,0},WORLD_SIZE*24); camera.SetWorldBoundary({0,0},WORLD_SIZE*24);
camera.EnableWorldBoundary(false); camera.EnableWorldBoundary(false);
#undef LoadImage //Dumb Windows. for(auto&val:DATA["Images"].GetKeys()){
auto LoadImage=[&](Renderable&r,std::string key){ std::string key=val.first;
r.Load(GetString("GFX_Prefix")+GetString(key)); std::string imgFile=DATA["Images"][key].GetString();
}; std::cout<<"Loading image "+imgFile+"..."<<std::endl;
#define LOADIMG(name) LoadImage(name,"Images."#name); GFX[imgFile];
if(GFX[imgFile].Load("GFX_Prefix"_S+imgFile)!=rcode::OK){
//Graphics std::cout<<" WARNING! Failed to load "+imgFile+"!";
LOADIMG(GFX_Warrior_Sheet) throw;
LOADIMG(GFX_Circle) }
LOADIMG(GFX_Effect_GroundSlam_Back) }
LOADIMG(GFX_Effect_GroundSlam_Front) GFX.SetInitialized();
LOADIMG(GFX_Heart) std::cout<<GFX.size()<<" images have been loaded."<<std::endl;
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)
Monster::InitializeStrategies(); Monster::InitializeStrategies();
//Animations //Animations
@ -130,18 +109,22 @@ bool Crawler::OnUserCreate(){
InitializeClasses(); InitializeClasses();
ChangePlayerClass(WARRIOR); ChangePlayerClass(WARRIOR);
Warrior::ability4=Ranger::ability1; //Class ability swapping demonstration. Warrior::ability4=Ranger::ability1; //Class ability swapping demonstration.
return true; return true;
} }
bool Crawler::OnUserUpdate(float fElapsedTime){ 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); HandleUserInput(fElapsedTime);
UpdateEffects(fElapsedTime); UpdateEffects(fElapsedTime);
player->Update(fElapsedTime); player->Update(fElapsedTime);
for(Monster&m:MONSTER_LIST){ for(Monster&m:MONSTER_LIST){
m.Update(fElapsedTime); m.Update(fElapsedTime);
} }
for(Monster&m:monstersToBeSpawned){
MONSTER_LIST.push_back(m);
}
monstersToBeSpawned.clear();
UpdateBullets(fElapsedTime); UpdateBullets(fElapsedTime);
UpdateCamera(fElapsedTime); UpdateCamera(fElapsedTime);
RenderWorld(fElapsedTime); RenderWorld(fElapsedTime);
@ -212,8 +195,8 @@ void Crawler::HandleUserInput(float fElapsedTime){
int truncatedPlayerY=int(player->GetY())/24; int truncatedPlayerY=int(player->GetY())/24;
int tileID=layer.tiles[truncatedPlayerY][truncatedPlayerX]; int tileID=layer.tiles[truncatedPlayerY][truncatedPlayerX];
TilesheetData dat=GetTileSheet(GetCurrentLevel(),tileID); TilesheetData dat=GetTileSheet(GetCurrentLevel(),tileID);
if (dat.tileset.staircaseTiles.find(tileID)!=dat.tileset.staircaseTiles.end()){ if (dat.tileset->staircaseTiles.find(tileID)!=dat.tileset->staircaseTiles.end()){
return dat.tileset.staircaseTiles[tileID].data["value"]; return dat.tileset->staircaseTiles[tileID].data["value"];
} }
} }
return std::string("NONE"); 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(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(backgroundEffects,[](std::unique_ptr<Effect>&e){return e->dead;});
std::erase_if(foregroundEffects,[](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){ for(auto it=foregroundEffectsToBeInserted.begin();it!=foregroundEffectsToBeInserted.end();++it){
foregroundEffects.push_back(std::move(*it)); foregroundEffects.push_back(std::move(*it));
@ -417,13 +401,10 @@ void Crawler::UpdateBullets(float fElapsedTime){
b->animation.UpdateState(b->internal_animState,fElapsedTime); b->animation.UpdateState(b->internal_animState,fElapsedTime);
if(!b->deactivated){ if(!b->deactivated){
float totalDistance=(b->vel*fElapsedTime).mag(); float totalDistance=(b->vel*fElapsedTime).mag();
vf2d moveStep=b->vel*fElapsedTime; int iterations=std::max(1.f,(b->vel*fElapsedTime).mag());
if((b->vel*fElapsedTime).mag()>1){ int totalIterations=iterations;
moveStep=(b->vel*fElapsedTime).norm(); vf2d finalBulletPos=b->pos+b->vel*fElapsedTime;
} const auto CollisionCheck=[&](){
while(totalDistance>0){
totalDistance=std::max(0.f,totalDistance-1);
b->pos+=moveStep;
if(b->friendly){ if(b->friendly){
for(Monster&m:MONSTER_LIST){ for(Monster&m:MONSTER_LIST){
if(geom2d::overlaps(geom2d::circle(m.GetPos(),12*m.GetSizeMult()),geom2d::circle(b->pos,b->radius))){ 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->hitsMultiple){
if(b->MonsterHit(m)){ if(b->MonsterHit(m)){
b->dead=true; b->dead=true;
continue; return false;
} }
} }
b->hitList[&m]=true; b->hitList[&m]=true;
@ -443,13 +424,26 @@ void Crawler::UpdateBullets(float fElapsedTime){
if(player->Hurt(b->damage,b->OnUpperLevel(),0)){ if(player->Hurt(b->damage,b->OnUpperLevel(),0)){
if(b->PlayerHit(player.get())){ if(b->PlayerHit(player.get())){
b->dead=true; b->dead=true;
continue; return false;
} }
} }
} }
} }
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; 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){ 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; b->dead=true;
continue; continue;
} }
nextBullet:
int a;
} }
outsideBulletLoop: outsideBulletLoop:
std::erase_if(BULLET_LIST,[](std::unique_ptr<Bullet>&b){return b->dead;}); 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(); Player*pl=GetPlayer();
for(auto it=MONSTER_LIST.begin();it!=MONSTER_LIST.end();++it){ for(auto it=MONSTER_LIST.begin();it!=MONSTER_LIST.end();++it){
Monster&m=*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;}); 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){ void Crawler::RenderWorld(float fElapsedTime){
Clear({100,180,100}); Clear(BLANK);
LayerTag*bridgeLayer=nullptr; LayerTag*bridgeLayer=nullptr;
bool bridgeLayerFade=false; 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 #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 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++){ 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){ if(x>=0&&x<WORLD_SIZE.x&&y>=0&&y<WORLD_SIZE.y){
for(LayerTag&layer:MAP_DATA[currentLevel].LayerData){ switch(mode){
if(IsBridgeLayer(layer)){ case RenderMode::NORMAL_TILES:{
bridgeLayer=&layer; for(LayerTag&layer:MAP_DATA[currentLevel].LayerData){
if(!bridgeLayerFade&&!player->upperLevel){ 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; int tileID=layer.tiles[y][x]-1;
if(tileID!=-1){ if(tileID!=-1){
int playerXTruncated=int(player->GetPos().x)/24; TilesheetData tileSheet=GetTileSheet(currentLevel,tileID);
int playerYTruncated=int(player->GetPos().y)/24; int tileSheetWidth=tileSheet.tileset->tileset->Sprite()->width/24;
if(playerXTruncated==x&&playerYTruncated==y){ int tileSheetHeight=tileSheet.tileset->tileset->Sprite()->height/24;
bridgeLayerFade=true; 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; }break;
} case RenderMode::REFLECTIVE_TILES:{
int tileID=layer.tiles[y][x]-1; visibleTiles.insert({x,y});
if(tileID!=-1){ for(LayerTag&layer:MAP_DATA[currentLevel].LayerData){
TilesheetData tileSheet=GetTileSheet(currentLevel,tileID); int tileID=layer.tiles[y][x]-1;
int tileSheetWidth=tileSheet.tileset.tileset->Sprite()->width/24; if(tileID!=-1){
int tileSheetHeight=tileSheet.tileset.tileset->Sprite()->height/24; TilesheetData tileSheet=GetTileSheet(currentLevel,tileID);
int tileSheetIndex=tileID-(tileSheet.firstgid-1); int tileSheetWidth=tileSheet.tileset->tileset->Sprite()->width/24;
int tileSheetX=tileSheetIndex%tileSheetWidth; int tileSheetHeight=tileSheet.tileset->tileset->Sprite()->height/24;
int tileSheetY=tileSheetIndex/tileSheetWidth; int tileSheetIndex=tileID-(tileSheet.firstgid-1);
if(!IsForegroundTile(tileSheet,tileSheetIndex)&&!IsUpperForegroundTile(tileSheet,tileSheetIndex)){ int tileSheetX=tileSheetIndex%tileSheetWidth;
view.DrawPartialDecal(vi2d{x,y}*24,{24,24},tileSheet.tileset.tileset->Decal(),vi2d{tileSheetX,tileSheetY}*24,{24,24}); int tileSheetY=tileSheetIndex/tileSheetWidth;
} if(IsReflectiveTile(tileSheet,tileSheetIndex)){
if("debug_collision_boxes"_I){ if(layer.tag.data["class"]!="CollisionOnly"){visibleTiles.erase({x,y});}
if(tileSheet.tileset.collision.find(tileSheetIndex)!=tileSheet.tileset.collision.end()){ RenderTile({x,y},tileSheet,tileSheetIndex,{tileSheetX,tileSheetY});
geom2d::rect<int>collision=tileSheet.tileset.collision[tileSheetIndex].collision; }
view.FillRectDecal(vi2d{x,y}*24+collision.pos,collision.size,{0,0,0,128}); if("debug_collision_boxes"_I){
view.DrawRectDecal(vi2d{x,y}*24+collision.pos,collision.size,GREY); 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{ }else{
bridgeFadeFactor=std::max(bridgeFadeFactor-fElapsedTime,0.f); bridgeFadeFactor=std::max(bridgeFadeFactor-fElapsedTime,0.f);
} }
}
#pragma endregion #pragma endregion
//DrawDecal({0,0},MAP_TILESETS["assets/maps/"+MAP_DATA[LEVEL1].TilesetData[1].data["source"]]->Decal()); //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){ if(player->GetZ()>0){
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.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){ for(Effect*e:backgroundEffectsLower){
e->Draw(); e->Draw();
@ -591,28 +705,11 @@ void Crawler::RenderWorld(float fElapsedTime){
for(Monster*m:monstersBeforeLower){ for(Monster*m:monstersBeforeLower){
m->Draw(); 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){ if(!player->upperLevel){
RenderPlayer(); RenderPlayer(player->GetPos(),{1,1});
} }
if(player->GetState()==State::BLOCK){ 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){ for(Monster*m:monstersAfterLower){
m->Draw(); m->Draw();
@ -628,15 +725,15 @@ void Crawler::RenderWorld(float fElapsedTime){
float precastSize=GetPlayer()->castPrepAbility->precastInfo.size; float precastSize=GetPlayer()->castPrepAbility->precastInfo.size;
float precastRange=GetPlayer()->castPrepAbility->precastInfo.range; float precastRange=GetPlayer()->castPrepAbility->precastInfo.range;
vf2d scale=vf2d{precastSize,precastSize}*2/3.f; 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)); float distance=sqrt(pow(player->GetX()-GetWorldMousePos().x,2)+pow(player->GetY()-GetWorldMousePos().y,2));
if(distance>precastRange){//Clamp the distance. if(distance>precastRange){//Clamp the distance.
vf2d pointToCursor = {GetWorldMousePos().x-player->GetX(),GetWorldMousePos().y-player->GetY()}; vf2d pointToCursor = {GetWorldMousePos().x-player->GetX(),GetWorldMousePos().y-player->GetY()};
pointToCursor=pointToCursor.norm()*precastRange; 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}; 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.Decal(),scale,{255,0,0,96}); view.DrawDecal(centerPoint,GFX["circle.png"].Decal(),scale,{255,0,0,96});
} else { } 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); group.fadeFactor=std::max(group.fadeFactor-fElapsedTime,0.f);
} }
for(TileRenderData&tile:group.GetTiles()){ 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; int tileID=bridgeLayer->tiles[y][x]-1;
if(tileID!=-1){ if(tileID!=-1){
TilesheetData tileSheet=GetTileSheet(currentLevel,tileID); TilesheetData tileSheet=GetTileSheet(currentLevel,tileID);
int tileSheetWidth=tileSheet.tileset.tileset->Sprite()->width/24; int tileSheetWidth=tileSheet.tileset->tileset->Sprite()->width/24;
int tileSheetHeight=tileSheet.tileset.tileset->Sprite()->height/24; int tileSheetHeight=tileSheet.tileset->tileset->Sprite()->height/24;
int tileSheetIndex=tileID-(tileSheet.firstgid-1); int tileSheetIndex=tileID-(tileSheet.firstgid-1);
int tileSheetX=tileSheetIndex%tileSheetWidth; int tileSheetX=tileSheetIndex%tileSheetWidth;
int tileSheetY=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 #ifdef DEBUG_COLLISIONS
if(tileSheet.tileset.collision.find(tileSheetIndex)!=tileSheet.tileset.collision.end()){ if(tileSheet.tileset.collision.find(tileSheetIndex)!=tileSheet.tileset.collision.end()){
geom2d::rect<int>collision=tileSheet.tileset.collision[tileSheetIndex].collision; geom2d::rect<int>collision=tileSheet.tileset.collision[tileSheetIndex].collision;
@ -693,7 +790,7 @@ void Crawler::RenderWorld(float fElapsedTime){
m->Draw(); m->Draw();
} }
if(player->upperLevel){ if(player->upperLevel){
RenderPlayer(); RenderPlayer(player->GetPos(),{1,1});
} }
for(Monster*m:monstersAfterUpper){ for(Monster*m:monstersAfterUpper){
m->Draw(); m->Draw();
@ -717,7 +814,7 @@ void Crawler::RenderWorld(float fElapsedTime){
group.fadeFactor=std::max(group.fadeFactor-fElapsedTime,0.f); group.fadeFactor=std::max(group.fadeFactor-fElapsedTime,0.f);
} }
for(TileRenderData&tile:group.GetTiles()){ 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 #pragma endregion
@ -727,21 +824,22 @@ void Crawler::RenderWorld(float fElapsedTime){
dn->pauseTime-=fElapsedTime; dn->pauseTime-=fElapsedTime;
} else{ } else{
dn->lifeTime+=fElapsedTime; dn->lifeTime+=fElapsedTime;
if(dn->lifeTime>1){ if(dn->lifeTime<=1){
it=DAMAGENUMBER_LIST.erase(it);
if(it==DAMAGENUMBER_LIST.end()){
break;
}
} else {
if(dn->lifeTime<DamageNumber::MOVE_UP_TIME){ if(dn->lifeTime<DamageNumber::MOVE_UP_TIME){
dn->pos.y-=20*fElapsedTime; dn->pos.y-=20*fElapsedTime;
} }
} }
} }
std::string text=std::to_string(dn->damage); std::string text=std::to_string(dn->damage);
view.DrawStringPropDecal(dn->pos-GetTextSizeProp(text)/2,text,DARK_RED); 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(){ 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); 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,2},GFX["heart.png"].Decal());
DrawDecal({2,20},GFX_Mana.Decal()); DrawDecal({2,20},GFX["mana.png"].Decal());
std::string text=player->GetHealth()>0?std::to_string(player->GetHealth()):"X"; std::string text=player->GetHealth()>0?std::to_string(player->GetHealth()):"X";
std::string text_mana=std::to_string(player->GetMana()); std::string text_mana=std::to_string(player->GetMana());
DrawShadowStringPropDecal({20,3},text,WHITE,BLACK,{2,2}); 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].upperForegroundTiles=tileset.GetData().UpperForegroundTileData;
MAP_TILESETS["assets/maps/"+baseSourceDir].collision=tileset.GetData().CollisionData; MAP_TILESETS["assets/maps/"+baseSourceDir].collision=tileset.GetData().CollisionData;
MAP_TILESETS["assets/maps/"+baseSourceDir].staircaseTiles=tileset.GetData().StaircaseData; 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"]); r->Load("assets/maps/"+tileset.GetData().ImageData.data["source"]);
} }
} }
@ -872,103 +973,148 @@ void Crawler::LoadLevel(MapName map){
foregroundTileGroups.clear(); foregroundTileGroups.clear();
currentLevel=map; currentLevel=map;
WORLD_SIZE={MAP_DATA[map].MapData.width,MAP_DATA[map].MapData.height}; WORLD_SIZE={MAP_DATA[map].MapData.width,MAP_DATA[map].MapData.height};
levelTime=0;
for(auto key:MAP_DATA[map].SpawnerData){ #pragma region Monster Spawn Data Setup
SpawnerTag&spawnData=MAP_DATA[map].SpawnerData[key.first]; for(auto key:MAP_DATA[map].SpawnerData){
std::vector<std::pair<int,vf2d>>monster_list; 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; vf2d spawnerRadius=vf2d{spawnData.ObjectData.GetFloat("width"),spawnData.ObjectData.GetFloat("height")}/2;
for(XMLTag&monster:spawnData.monsters){ for(XMLTag&monster:spawnData.monsters){
int monsterTypeID=monster.GetInteger("value")-1; 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")}}); 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; #pragma region Foreground and Upper Foreground Tile Fade Group Setup
for(int x=0;x<WORLD_SIZE.x;x++){ std::set<vi2d>foregroundTilesAdded,upperForegroundTilesAdded;
for(int y=0;y<WORLD_SIZE.y;y++){ for(int x=0;x<WORLD_SIZE.x;x++){
for(LayerTag&layer:MAP_DATA[currentLevel].LayerData){ for(int y=0;y<WORLD_SIZE.y;y++){
int tileID=layer.tiles[y][x]-1; int layerID=0;
if(tileID!=-1){ for(LayerTag&layer:MAP_DATA[currentLevel].LayerData){
TilesheetData tileSheet=GetTileSheet(currentLevel,tileID); int tileID=layer.tiles[y][x]-1;
int tileSheetWidth=tileSheet.tileset.tileset->Sprite()->width/24; if(tileID!=-1){
int tileSheetHeight=tileSheet.tileset.tileset->Sprite()->height/24; TilesheetData tileSheet=GetTileSheet(currentLevel,tileID);
int tileSheetIndex=tileID-(tileSheet.firstgid-1); int tileSheetWidth=tileSheet.tileset->tileset->Sprite()->width/24;
int tileSheetX=tileSheetIndex%tileSheetWidth; int tileSheetHeight=tileSheet.tileset->tileset->Sprite()->height/24;
int tileSheetY=tileSheetIndex/tileSheetWidth; int tileSheetIndex=tileID-(tileSheet.firstgid-1);
#pragma region TileGroupShenanigans int realTileSheetIndex=(tileID%1000000)-(tileSheet.firstgid-1);
auto SetupTileGroups=[&](std::function<bool(TilesheetData,int)>IsForeground,TileRenderData tile,std::set<vi2d>&foregroundTilesIncluded,std::vector<TileGroup>&groups){ int tileSheetX=realTileSheetIndex%tileSheetWidth;
int layerID=layer.tag.GetInteger("id"); int tileSheetY=realTileSheetIndex/tileSheetWidth;
if(IsForeground(tileSheet,tileSheetIndex)&&foregroundTilesIncluded.find({x,y})==foregroundTilesIncluded.end()){ #pragma region TileGroupShenanigans
std::queue<vi2d>tileGroupChecks; auto SetupTileGroups=[&](std::function<bool(TilesheetData,int)>IsForeground,TileRenderData tile,std::set<vi2d>&foregroundTilesIncluded,std::vector<TileGroup>&groups){
TileGroup group; if(foregroundTilesIncluded.find({x,y})==foregroundTilesIncluded.end()&&IsForeground(tileSheet,tileSheetIndex)){
foregroundTilesIncluded.insert({x,y}); std::queue<vi2d>tileGroupChecks;
group.originatingLayer=layerID; TileGroup group;
group.InsertTile(tile); foregroundTilesIncluded.insert({x,y});
if(x>0)tileGroupChecks.push({x-1,y}); group.InsertTile(tile);
if(x<WORLD_SIZE.x-1)tileGroupChecks.push({x+1,y}); if(x>0&&foregroundTilesIncluded.find(vi2d{x,y}+vi2d{-1,0})==foregroundTilesIncluded.end())tileGroupChecks.push({x-1,y});
if(y>0)tileGroupChecks.push({x,y-1}); if(x<WORLD_SIZE.x-1&&foregroundTilesIncluded.find(vi2d{x,y}+vi2d{1,0})==foregroundTilesIncluded.end())tileGroupChecks.push({x+1,y});
if(y<WORLD_SIZE.y-1)tileGroupChecks.push({x,y+1}); if(y>0&&foregroundTilesIncluded.find(vi2d{x,y}+vi2d{0,-1})==foregroundTilesIncluded.end())tileGroupChecks.push({x,y-1});
auto IterateThroughOtherLayers=[&](vi2d pos){ if(y<WORLD_SIZE.y-1&&foregroundTilesIncluded.find(vi2d{x,y}+vi2d{0,1})==foregroundTilesIncluded.end())tileGroupChecks.push({x,y+1});
for(LayerTag&layer2:MAP_DATA[currentLevel].LayerData){ auto IterateThroughOtherLayers=[&](vi2d pos,bool loopAll=false){
if(&layer==&layer2)continue; int layer2ID=0;
int tileID=layer2.tiles[pos.y][pos.x]-1; bool hadForeground=false;
TilesheetData tileSheet=GetTileSheet(currentLevel,tileID); for(LayerTag&layer2:MAP_DATA[currentLevel].LayerData){
int tileSheetWidth=tileSheet.tileset.tileset->Sprite()->width/24; if(!loopAll&&&layer==&layer2){layer2ID++;continue;};
int tileSheetHeight=tileSheet.tileset.tileset->Sprite()->height/24; int tileID=layer2.tiles[pos.y][pos.x]-1;
int tileSheetIndex=tileID-(tileSheet.firstgid-1); TilesheetData tileSheet=GetTileSheet(currentLevel,tileID%1000000);
int tileSheetX=tileSheetIndex%tileSheetWidth; int tileSheetWidth=tileSheet.tileset->tileset->Sprite()->width/24;
int tileSheetY=tileSheetIndex/tileSheetWidth; int tileSheetHeight=tileSheet.tileset->tileset->Sprite()->height/24;
TileRenderData tile={tileSheet.tileset.tileset->Decal(),vi2d{pos.x,pos.y}*24,vi2d{tileSheetX,tileSheetY}*24}; int tileSheetIndex=tileID-(tileSheet.firstgid-1);
if(IsForeground(tileSheet,tileSheetIndex)){ int realTileSheetIndex=(tileID%1000000)-(tileSheet.firstgid-1);
foregroundTilesIncluded.insert({pos.x,pos.y}); int tileSheetX=realTileSheetIndex%tileSheetWidth;
group.InsertTile(tile); 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();
} }
}; groups.push_back(group);
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); };
} 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);
TileRenderData tile={tileSheet.tileset.tileset->Decal(),vi2d{x,y}*24,vi2d{tileSheetX,tileSheetY}*24}; SetupTileGroups([&](TilesheetData sheet,int tileID){return IsUpperForegroundTile(tileID);},tile,upperForegroundTilesAdded,upperForegroundTileGroups);
SetupTileGroups([&](TilesheetData sheet,int tileID){return IsForegroundTile(sheet,tileID);},tile,foregroundTilesAdded,foregroundTileGroups); #pragma endregion
SetupTileGroups([&](TilesheetData sheet,int tileID){return IsUpperForegroundTile(sheet,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; #pragma region Bridge Layer Setup
bridgeLayerIndex=-1; int counter=0;
for(LayerTag&layer:MAP_DATA[map].LayerData){ bridgeLayerIndex=-1;
if(IsBridgeLayer(layer)){ for(LayerTag&layer:MAP_DATA[map].LayerData){
bridgeLayerIndex=counter; if(IsBridgeLayer(layer)){
bridgeLayerIndex=counter;
}
counter++;
} }
counter++; #pragma endregion
}
player->upperLevel=false; //Assume player starts on lower level. player->upperLevel=false; //Assume player starts on lower level.
player->SetPos(MAP_DATA[map].MapData.playerSpawnLocation); player->SetPos(MAP_DATA[map].MapData.playerSpawnLocation);
@ -987,12 +1133,12 @@ vi2d Crawler::GetWorldSize(){
return WORLD_SIZE; return WORLD_SIZE;
} }
bool Crawler::IsUpperForegroundTile(TilesheetData sheet,int tileID){ bool Crawler::IsUpperForegroundTile(int tileID){
return sheet.tileset.upperForegroundTiles.find(tileID)!=sheet.tileset.upperForegroundTiles.end(); return tileID>=1000000;
} }
bool Crawler::IsForegroundTile(TilesheetData sheet,int tileID){ 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){ TilesheetData Crawler::GetTileSheet(MapName map,int tileID){
@ -1000,18 +1146,18 @@ TilesheetData Crawler::GetTileSheet(MapName map,int tileID){
if(tileData.size()==1){ if(tileData.size()==1){
size_t slashMarkerSourceDir = tileData[0].data["source"].find_last_of('/'); size_t slashMarkerSourceDir = tileData[0].data["source"].find_last_of('/');
std::string baseSourceDir=tileData[0].data["source"].substr(slashMarkerSourceDir+1); 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 { } else {
for (int i=1;i<tileData.size();i++){ 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('/'); size_t slashMarkerSourceDir = tileData[i-1].data["source"].find_last_of('/');
std::string baseSourceDir=tileData[i-1].data["source"].substr(slashMarkerSourceDir+1); 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('/'); size_t slashMarkerSourceDir = tileData[tileData.size()-1].data["source"].find_last_of('/');
std::string baseSourceDir=tileData[tileData.size()-1].data["source"].substr(slashMarkerSourceDir+1); 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. if(!upperLevel){ //We are looking for lower bridge collisions.
for(geom2d::rect<int>&zone:MAP_DATA[map].ZoneData["LowerBridgeCollision"]){ for(geom2d::rect<int>&zone:MAP_DATA[map].ZoneData["LowerBridgeCollision"]){
if(geom2d::contains(zone,pos)){ if(geom2d::contains(zone,pos)){
return {{0,0},{32,32}}; return {{0,0},{24,24}};
} }
} }
} }
@ -1041,24 +1187,34 @@ geom2d::rect<int>Crawler::GetTileCollision(MapName map,vf2d pos,bool upperLevel)
if(upperLevel&&bridgeLayerIndex!=-1){ if(upperLevel&&bridgeLayerIndex!=-1){
int tileID=MAP_DATA[map].LayerData[bridgeLayerIndex].tiles[int(pos.y)/24][int(pos.x)/24]-1; int tileID=MAP_DATA[map].LayerData[bridgeLayerIndex].tiles[int(pos.y)/24][int(pos.x)/24]-1;
if(tileID!=-1){ if(tileID!=-1){
if (GetTileSheet(map,tileID).tileset.collision.find(tileID-GetTileSheet(map,tileID).firstgid+1)!=GetTileSheet(map,tileID).tileset.collision.end()){ 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).tileset.collision[tileID-GetTileSheet(map,tileID).firstgid+1].collision; return GetTileSheet(map,tileID%1000000).tileset->collision[tileID%1000000-GetTileSheet(map,tileID%1000000).firstgid+1].collision;
} }
return NO_COLLISION; return NO_COLLISION;
} }
} }
int counter=0; int counter=0;
geom2d::rect<int>foundRect=NO_COLLISION;
for(LayerTag&layer:MAP_DATA[map].LayerData){ for(LayerTag&layer:MAP_DATA[map].LayerData){
auto HasNoClass=[&](){return layer.tag.data.find("class")==layer.tag.data.end();}; //auto HasNoClass=[&](){return layer.tag.data.find("class")==layer.tag.data.end();};
if(HasNoClass()&&counter!=bridgeLayerIndex){ if(counter!=bridgeLayerIndex){
int tileID=layer.tiles[int(pos.y)/24][int(pos.x)/24]-1; 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()){ 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()){
return GetTileSheet(map,tileID).tileset.collision[tileID-GetTileSheet(map,tileID).firstgid+1].collision; 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++; counter++;
} }
return NO_COLLISION; return foundRect;
} }
MapName Crawler::GetCurrentLevel(){ MapName Crawler::GetCurrentLevel(){
@ -1143,9 +1299,8 @@ datafiledoubledata Crawler::GetDoubleList(std::string key){
int main() int main()
{ {
std::cout<<"I change this"<<std::endl;
Crawler demo; 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(); demo.Start();
return 0; 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(){ void Crawler::InitializeLevels(){
#define INITLEVEL(map) \ #define INITLEVEL(map) \
InitializeLevel("map_path"_S + "Levels."#map ## _S,map); \ InitializeLevel("map_path"_S + "Levels."#map ## _S,map); \
@ -1226,4 +1390,8 @@ void Crawler::InitializeLevels(){
INITLEVEL(CAMPAIGN_1_2); INITLEVEL(CAMPAIGN_1_2);
LEVEL_NAMES.SetInitialized(); LEVEL_NAMES.SetInitialized();
}
void Crawler::SpawnMonster(vf2d pos,MonsterData*data,bool upperLevel){
monstersToBeSpawned.push_back(Monster(pos,*data,upperLevel));
} }

@ -12,32 +12,19 @@
#include "TMXParser.h" #include "TMXParser.h"
#include "olcUTIL_DataFile.h" #include "olcUTIL_DataFile.h"
struct TilesheetData{
TilesetData&tileset;
int firstgid;
};
class Crawler : public olc::PixelGameEngine class Crawler : public olc::PixelGameEngine
{ {
friend class sig::Animation; friend class sig::Animation;
Camera2D camera; Camera2D camera;
std::unique_ptr<Player>player; std::unique_ptr<Player>player;
Renderable GFX_Warrior_Sheet,
GFX_Effect_GroundSlam_Back,GFX_Effect_GroundSlam_Front,
GFX_Heart,GFX_BLOCK_BUBBLE,GFX_Ranger_Sheet,GFX_Wizard_Sheet,
GFX_Battlecry_Effect,GFX_Mana,GFX_SonicSlash,GFX_EnergyParticle,
GFX_Splash_Effect,GFX_LightningBolt,GFX_LightningBoltParticle1,
GFX_LightningBoltParticle2,GFX_LightningBoltParticle3,GFX_LightningBoltParticle4,
GFX_ChainLightning,GFX_LightningSplash,GFX_Meteor,GFX_Arrow,
GFX_Laser,GFX_ChargedArrow,GFX_RangeIndicator;
public: public:
Renderable GFX_BulletCircle,GFX_BulletCircleOutline,GFX_EnergyBolt,GFX_Circle;
Pathfinding pathfinder; Pathfinding pathfinder;
static Key KEY_ABILITY1; static Key KEY_ABILITY1;
static Key KEY_ABILITY2; static Key KEY_ABILITY2;
static Key KEY_ABILITY3; static Key KEY_ABILITY3;
static Key KEY_ABILITY4; static Key KEY_ABILITY4;
static float SIZE_CHANGE_SPEED; static float SIZE_CHANGE_SPEED;
float levelTime;
private: private:
std::vector<std::unique_ptr<Effect>>foregroundEffects,backgroundEffects,foregroundEffectsToBeInserted,backgroundEffectsToBeInserted; std::vector<std::unique_ptr<Effect>>foregroundEffects,backgroundEffects,foregroundEffectsToBeInserted,backgroundEffectsToBeInserted;
std::map<MapName,Map>MAP_DATA; std::map<MapName,Map>MAP_DATA;
@ -53,10 +40,19 @@ private:
int bridgeLayerIndex=-1; int bridgeLayerIndex=-1;
float bridgeFadeFactor=0.f; float bridgeFadeFactor=0.f;
void InitializeClasses(); void InitializeClasses();
int DEBUG_PATHFINDING=0;
std::vector<Monster*>monstersBeforeLower,monstersAfterLower,monstersBeforeUpper,monstersAfterUpper;
std::vector<Bullet*>bulletsLower,bulletsUpper;
std::vector<Effect*>backgroundEffectsLower,backgroundEffectsUpper,foregroundEffectsLower,foregroundEffectsUpper;
float reflectionUpdateTimer=0;
float reflectionStepTime=0;
std::set<vi2d>visibleTiles;
std::vector<Monster>monstersToBeSpawned;
public: public:
Crawler(); Crawler();
bool OnUserCreate() override; bool OnUserCreate() override;
bool OnUserUpdate(float fElapsedTime) override; bool OnUserUpdate(float fElapsedTime) override;
bool OnUserDestroy() override;
public: public:
geom2d::rect<int>NO_COLLISION={}; geom2d::rect<int>NO_COLLISION={};
vi2d WORLD_SIZE={120,8}; vi2d WORLD_SIZE={120,8};
@ -88,7 +84,7 @@ public:
//tileID is the tile number from the tilesets. //tileID is the tile number from the tilesets.
bool IsForegroundTile(TilesheetData sheet,int tileID); bool IsForegroundTile(TilesheetData sheet,int tileID);
//tileID is the tile number from the tilesets. //tileID is the tile number from the tilesets.
bool IsUpperForegroundTile(TilesheetData sheet,int tileID); bool IsUpperForegroundTile(int tileID);
//tileID is the tile number from the tilesets. //tileID is the tile number from the tilesets.
TilesheetData GetTileSheet(MapName map,int tileID); TilesheetData GetTileSheet(MapName map,int tileID);
//Gets the rectangle of the tile collision at this tile. If upperLevel is set to true, the collision tile must be in a Bridge class layer for the tile to hit. Also, zones containing LowerBridgeCollision will apply when upperLevel is set to false. //Gets the rectangle of the tile collision at this tile. If upperLevel is set to true, the collision tile must be in a Bridge class layer for the tile to hit. Also, zones containing LowerBridgeCollision will apply when upperLevel is set to false.
@ -98,7 +94,7 @@ public:
MapName GetCurrentLevel(); MapName GetCurrentLevel();
bool IsBridgeLayer(LayerTag&layer); bool IsBridgeLayer(LayerTag&layer);
std::map<std::string,std::vector<geom2d::rect<int>>>&GetZoneData(MapName map); std::map<std::string,std::vector<geom2d::rect<int>>>&GetZoneData(MapName map);
void 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 PopulateRenderLists();
void ChangePlayerClass(Class cl); void ChangePlayerClass(Class cl);
std::string GetString(std::string key); std::string GetString(std::string key);
datafilestringdata GetStringList(std::string key); datafilestringdata GetStringList(std::string key);
@ -110,6 +106,10 @@ public:
datafiledoubledata GetDoubleList(std::string key); datafiledoubledata GetDoubleList(std::string key);
static void OutputDebugInfo(const char*key,std::size_t len); static void OutputDebugInfo(const char*key,std::size_t len);
void InitializeLevels(); void InitializeLevels();
void RenderTile(vi2d pos,TilesheetData tileSheet,int tileSheetIndex,vi2d tileSheetPos);
void RenderTile(TileRenderData&tileSheet,Pixel col);
bool IsReflectiveTile(TilesheetData tileSheet,int tileID);
void SpawnMonster(vf2d pos,MonsterData*data,bool upperLevel=false); //Queues a monster for spawning on the next frame.
struct TileGroupData{ struct TileGroupData{
vi2d tilePos; vi2d tilePos;

@ -21,6 +21,18 @@
"layer" "layer"
] ]
}, },
{
"color": "#ffa44949",
"drawFill": true,
"id": 18,
"members": [
],
"name": "CollisionOnly",
"type": "class",
"useAs": [
"layer"
]
},
{ {
"color": "#ffbdc34c", "color": "#ffbdc34c",
"drawFill": true, "drawFill": true,
@ -141,6 +153,19 @@
"object" "object"
] ]
}, },
{
"color": "#ff0574a4",
"drawFill": true,
"id": 16,
"members": [
],
"name": "Reflective",
"type": "class",
"useAs": [
"property",
"tile"
]
},
{ {
"color": "#ffe67300", "color": "#ffe67300",
"drawFill": true, "drawFill": true,
@ -170,13 +195,7 @@
"type": "class", "type": "class",
"useAs": [ "useAs": [
"property", "property",
"map", "tile"
"layer",
"object",
"tile",
"tileset",
"wangcolor",
"wangset"
] ]
}, },
{ {
@ -208,32 +227,6 @@
"object" "object"
] ]
}, },
{
"color": "#ff35e500",
"drawFill": true,
"id": 13,
"members": [
],
"name": "UpperForegroundTile",
"type": "class",
"useAs": [
"property",
"tile"
]
},
{
"color": "#ffff74fd",
"drawFill": true,
"id": 16,
"members": [
],
"name": "UpperSpawnGroup",
"type": "class",
"useAs": [
"property",
"object"
]
},
{ {
"color": "#ffa40aa4", "color": "#ffa40aa4",
"drawFill": true, "drawFill": true,

@ -302,6 +302,7 @@
<ClCompile Include="Effect.cpp" /> <ClCompile Include="Effect.cpp" />
<ClCompile Include="Emitter.cpp" /> <ClCompile Include="Emitter.cpp" />
<ClCompile Include="EnergyBolt.cpp" /> <ClCompile Include="EnergyBolt.cpp" />
<ClCompile Include="FallingDebris.h" />
<ClCompile Include="FireBolt.cpp" /> <ClCompile Include="FireBolt.cpp" />
<ClCompile Include="LightningBolt.cpp" /> <ClCompile Include="LightningBolt.cpp" />
<ClCompile Include="LightningBoltEmitter.cpp" /> <ClCompile Include="LightningBoltEmitter.cpp" />
@ -327,6 +328,7 @@
<ClCompile Include="Wizard.cpp" /> <ClCompile Include="Wizard.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="ClassDiagram2.cd" />
<None Include="cpp.hint" /> <None Include="cpp.hint" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

@ -239,9 +239,13 @@
<ClCompile Include="SlimeKing.cpp"> <ClCompile Include="SlimeKing.cpp">
<Filter>Source Files\Monster Strategies</Filter> <Filter>Source Files\Monster Strategies</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="FallingDebris.h">
<Filter>Source Files\Effects</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="cpp.hint" /> <None Include="cpp.hint" />
<None Include="ClassDiagram2.cd" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Text Include="InitialConcept.txt"> <Text Include="InitialConcept.txt">

@ -5,12 +5,14 @@
#define INCLUDE_DAMAGENUMBER_LIST extern std::vector<std::shared_ptr<DamageNumber>>DAMAGENUMBER_LIST; #define INCLUDE_DAMAGENUMBER_LIST extern std::vector<std::shared_ptr<DamageNumber>>DAMAGENUMBER_LIST;
#define INCLUDE_game extern Crawler*game; #define INCLUDE_game extern Crawler*game;
#define INCLUDE_MONSTER_DATA extern std::map<int,MonsterData>MONSTER_DATA; #define INCLUDE_MONSTER_DATA extern std::map<int,MonsterData>MONSTER_DATA;
#define INCLUDE_MONSTER_NAME_DATA extern safemap<std::string,MonsterData*>MONSTER_NAME_DATA;
#define INCLUDE_BULLET_LIST extern std::vector<std::unique_ptr<Bullet>>BULLET_LIST; #define INCLUDE_BULLET_LIST extern std::vector<std::unique_ptr<Bullet>>BULLET_LIST;
#define INCLUDE_PARTICLE_LIST extern std::vector<Particle>PARTICLE_LIST;
#define INCLUDE_EMITTER_LIST extern std::vector<std::unique_ptr<Emitter>>EMITTER_LIST; #define INCLUDE_EMITTER_LIST extern std::vector<std::unique_ptr<Emitter>>EMITTER_LIST;
#define INCLUDE_DATA extern utils::datafile DATA; #define INCLUDE_DATA extern utils::datafile DATA;
#define INCLUDE_STRATEGY_DATA extern safemap<std::string,int>STRATEGY_DATA; #define INCLUDE_STRATEGY_DATA extern safemap<std::string,int>STRATEGY_DATA;
#define INCLUDE_STRATEGY_ID_DATA extern safemap<std::string,int>STRATEGY_ID_DATA; #define INCLUDE_STRATEGY_ID_DATA extern safemap<std::string,int>STRATEGY_ID_DATA;
#define INCLUDE_TILE_ANIMATION_DATA extern std::map<int,std::vector<std::pair<int,float>>>TILE_ANIMATION_DATA;
#define INCLUDE_GFX extern safemap<std::string,Renderable>GFX;
#define ACCESS_PLAYER Player*p=game->GetPlayer(); #define ACCESS_PLAYER Player*p=game->GetPlayer();

@ -6,14 +6,14 @@
INCLUDE_ANIMATION_DATA INCLUDE_ANIMATION_DATA
INCLUDE_game INCLUDE_game
Effect::Effect(vf2d pos,float lifetime,std::string animation,bool upperLevel,float size,float fadeout,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending) Effect::Effect(vf2d pos,float lifetime,std::string imgFile,bool upperLevel,float size,float fadeout,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending)
:Effect::Effect(pos,lifetime,animation,upperLevel,vf2d{size,size},fadeout,spd,col,rotation,rotationSpd,additiveBlending){ :Effect::Effect(pos,lifetime,imgFile,upperLevel,vf2d{size,size},fadeout,spd,col,rotation,rotationSpd,additiveBlending){
this->animation.AddState(animation,ANIMATION_DATA[animation]); this->animation.AddState(imgFile,ANIMATION_DATA[imgFile]);
} }
Effect::Effect(vf2d pos,float lifetime,std::string animation,bool upperLevel,vf2d size,float fadeout,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending) Effect::Effect(vf2d pos,float lifetime,std::string imgFile,bool upperLevel,vf2d size,float fadeout,vf2d spd,Pixel col,float rotation,float rotationSpd,bool additiveBlending)
:pos(pos),lifetime(lifetime),upperLevel(upperLevel),size(size),fadeout(fadeout),original_fadeoutTime(fadeout),spd(spd),col(col),rotation(rotation),rotationSpd(rotationSpd),additiveBlending(additiveBlending){ :pos(pos),lifetime(lifetime),upperLevel(upperLevel),size(size),fadeout(fadeout),original_fadeoutTime(fadeout),spd(spd),col(col),rotation(rotation),rotationSpd(rotationSpd),additiveBlending(additiveBlending){
this->animation.AddState(animation,ANIMATION_DATA[animation]); this->animation.AddState(imgFile,ANIMATION_DATA[imgFile]);
} }
bool Effect::Update(float fElapsedTime){ bool Effect::Update(float fElapsedTime){

@ -17,8 +17,8 @@ struct Effect{
private: private:
bool dead=false; bool dead=false;
public: public:
Effect(vf2d pos,float lifetime,std::string animation,bool upperLevel,float size=1.0f,float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false); Effect(vf2d pos,float lifetime,std::string imgFile,bool upperLevel,float size=1.0f,float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false);
Effect(vf2d pos,float lifetime,std::string animation,bool upperLevel,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false); Effect(vf2d pos,float lifetime,std::string imgFile,bool upperLevel,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false);
virtual bool Update(float fElapsedTime); virtual bool Update(float fElapsedTime);
Animate2D::Frame GetFrame(); Animate2D::Frame GetFrame();
virtual void Draw(); virtual void Draw();
@ -32,7 +32,7 @@ private:
}; };
struct Meteor:Effect{ struct Meteor:Effect{
Meteor(vf2d pos,float lifetime,std::string animation,bool upperLevel,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false); Meteor(vf2d pos,float lifetime,std::string imgFile,bool upperLevel,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false);
float startLifetime=0; float startLifetime=0;
bool shakeField=false; bool shakeField=false;
bool Update(float fElapsedTime)override; bool Update(float fElapsedTime)override;
@ -40,7 +40,7 @@ struct Meteor:Effect{
}; };
struct PulsatingFire:Effect{ struct PulsatingFire:Effect{
PulsatingFire(vf2d pos,float lifetime,std::string animation,bool upperLevel,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false); PulsatingFire(vf2d pos,float lifetime,std::string imgFile,bool upperLevel,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false);
std::vector<float>pulsatingFireValues; std::vector<float>pulsatingFireValues;
float lastParticleTimer=0; float lastParticleTimer=0;
float lastDamageTimer=0; float lastDamageTimer=0;

@ -8,13 +8,13 @@ INCLUDE_game
EnergyBolt::EnergyBolt(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col) EnergyBolt::EnergyBolt(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col)
:Bullet(pos,vel,radius,damage, :Bullet(pos,vel,radius,damage,
"ENERGY_BOLT",upperLevel,false,INFINITE,true,friendly,col){} "energy_bolt.png",upperLevel,false,INFINITE,true,friendly,col){}
void EnergyBolt::Update(float fElapsedTime){ void EnergyBolt::Update(float fElapsedTime){
lastParticleSpawn=std::max(0.f,lastParticleSpawn-fElapsedTime); lastParticleSpawn=std::max(0.f,lastParticleSpawn-fElapsedTime);
if(lastParticleSpawn==0){ if(lastParticleSpawn==0){
lastParticleSpawn="Wizard.Auto Attack.ParticleFrequency"_F; lastParticleSpawn="Wizard.Auto Attack.ParticleFrequency"_F;
game->AddEffect(std::make_unique<Effect>(pos,"Wizard.Auto Attack.ParticleLifetimeRange"_FRange,"ENERGY_PARTICLE",upperLevel,"Wizard.Auto Attack.ParticleSizeRange"_FRange,"Wizard.Auto Attack.ParticleFadeoutTime"_F,vf2d{"Wizard.Auto Attack.ParticleSpeedRange"_FRange,"Wizard.Auto Attack.ParticleSpeedRange"_FRange})); game->AddEffect(std::make_unique<Effect>(pos,"Wizard.Auto Attack.ParticleLifetimeRange"_FRange,"energy_particle.png",upperLevel,"Wizard.Auto Attack.ParticleSizeRange"_FRange,"Wizard.Auto Attack.ParticleFadeoutTime"_F,vf2d{"Wizard.Auto Attack.ParticleSpeedRange"_FRange,"Wizard.Auto Attack.ParticleSpeedRange"_FRange}));
} }
} }
@ -22,7 +22,7 @@ bool EnergyBolt::PlayerHit(Player*player)
{ {
deactivated=true; deactivated=true;
fadeOutTime="Wizard.Auto Attack.BulletHitFadeoutTime"_F; fadeOutTime="Wizard.Auto Attack.BulletHitFadeoutTime"_F;
game->AddEffect(std::make_unique<Effect>(player->GetPos(),0,"SPLASH_EFFECT",upperLevel,player->GetSizeMult(),"Wizard.Auto Attack.SplashEffectFadeoutTime"_F)); game->AddEffect(std::make_unique<Effect>(player->GetPos(),0,"splash_effect.png",upperLevel,player->GetSizeMult(),"Wizard.Auto Attack.SplashEffectFadeoutTime"_F));
return false; return false;
} }
@ -30,6 +30,6 @@ bool EnergyBolt::MonsterHit(Monster& monster)
{ {
deactivated=true; deactivated=true;
fadeOutTime="Wizard.Auto Attack.BulletHitFadeoutTime"_F; fadeOutTime="Wizard.Auto Attack.BulletHitFadeoutTime"_F;
game->AddEffect(std::make_unique<Effect>(monster.GetPos(),0,"SPLASH_EFFECT",upperLevel,monster.GetSizeMult(),"Wizard.Auto Attack.SplashEffectFadeoutTime"_F)); game->AddEffect(std::make_unique<Effect>(monster.GetPos(),0,"splash_effect.png",upperLevel,monster.GetSizeMult(),"Wizard.Auto Attack.SplashEffectFadeoutTime"_F));
return false; return false;
} }

@ -0,0 +1,19 @@
#include "Effect.h"
#include "DEFINES.h"
#include "safemap.h"
INCLUDE_GFX
class FallingDebris:public Effect{
const float GRAVITY=20;
public:
inline FallingDebris(vf2d pos, float lifetime, std::string imgFile, bool upperLevel,vf2d size={1,1},float fadeout=0.0f,vf2d spd={},Pixel col=WHITE,float rotation=0,float rotationSpd=0,bool additiveBlending=false)
:Effect(pos,lifetime,imgFile,upperLevel,size,fadeout,spd,col,rotation,rotationSpd,additiveBlending){
}
inline bool Update(float fElapsedTime)override{
spd.y+=GRAVITY*fElapsedTime;
return Effect::Update(fElapsedTime);
}
};

@ -9,13 +9,13 @@ INCLUDE_MONSTER_LIST
FireBolt::FireBolt(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col) FireBolt::FireBolt(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col)
:Bullet(pos,vel,radius,damage, :Bullet(pos,vel,radius,damage,
"ENERGY_BOLT",upperLevel,false,INFINITE,true,friendly,col){} "energy_bolt.png",upperLevel,false,INFINITE,true,friendly,col){}
void FireBolt::Update(float fElapsedTime){ void FireBolt::Update(float fElapsedTime){
lastParticleSpawn=std::max(0.f,lastParticleSpawn-fElapsedTime); lastParticleSpawn=std::max(0.f,lastParticleSpawn-fElapsedTime);
if(lastParticleSpawn==0){ if(lastParticleSpawn==0){
lastParticleSpawn="Wizard.Ability 1.ParticleFrequency"_F; lastParticleSpawn="Wizard.Ability 1.ParticleFrequency"_F;
game->AddEffect(std::make_unique<Effect>(pos,"Wizard.Ability 1.ParticleLifetimeRange"_FRange,"ENERGY_PARTICLE",upperLevel,"Wizard.Ability 1.ParticleSizeRange"_FRange,"Wizard.Ability 1.ParticleFadeoutTime"_F,vf2d{"Wizard.Ability 1.ParticleXSpeedRange"_FRange,"Wizard.Ability 1.ParticleYSpeedRange"_FRange},Pixel{uint8_t("Wizard.Ability 1.ParticleRedRange"_FRange),uint8_t("Wizard.Ability 1.ParticleGreenRange"_FRange),uint8_t("Wizard.Ability 1.ParticleBlueRange"_FRange),uint8_t("Wizard.Ability 1.ParticleAlphaRange"_FRange)})); game->AddEffect(std::make_unique<Effect>(pos,"Wizard.Ability 1.ParticleLifetimeRange"_FRange,"energy_particle.png",upperLevel,"Wizard.Ability 1.ParticleSizeRange"_FRange,"Wizard.Ability 1.ParticleFadeoutTime"_F,vf2d{"Wizard.Ability 1.ParticleXSpeedRange"_FRange,"Wizard.Ability 1.ParticleYSpeedRange"_FRange},Pixel{uint8_t("Wizard.Ability 1.ParticleRedRange"_FRange),uint8_t("Wizard.Ability 1.ParticleGreenRange"_FRange),uint8_t("Wizard.Ability 1.ParticleBlueRange"_FRange),uint8_t("Wizard.Ability 1.ParticleAlphaRange"_FRange)}));
} }
} }
@ -23,7 +23,7 @@ bool FireBolt::PlayerHit(Player*player)
{ {
deactivated=true; deactivated=true;
fadeOutTime="Wizard.Ability 1.BulletHitFadeoutTime"_F; fadeOutTime="Wizard.Ability 1.BulletHitFadeoutTime"_F;
game->AddEffect(std::make_unique<Effect>(player->GetPos(),0,"SPLASH_EFFECT",upperLevel,5,0.25,vf2d{},Pixel{240,120,60})); game->AddEffect(std::make_unique<Effect>(player->GetPos(),0,"splash_effect.png",upperLevel,5,0.25,vf2d{},Pixel{240,120,60}));
return false; return false;
} }
@ -32,10 +32,10 @@ bool FireBolt::MonsterHit(Monster& monster)
deactivated=true; deactivated=true;
fadeOutTime="Wizard.Ability 1.BulletHitFadeoutTime"_F; fadeOutTime="Wizard.Ability 1.BulletHitFadeoutTime"_F;
for(int i=0;i<"Wizard.Ability 1.BulletHitExplosionParticleCount"_I;i++){ for(int i=0;i<"Wizard.Ability 1.BulletHitExplosionParticleCount"_I;i++){
game->AddEffect(std::make_unique<Effect>(monster.GetPos(),"Wizard.Ability 1.BulletHitExplosionParticleLifetimeRange"_FRange,"DOT_PARTICLE",upperLevel,"Wizard.Ability 1.BulletHitExplosionParticleSizeRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleFadeoutTimeRange"_FRange,vf2d{"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange},Pixel{uint8_t("Wizard.Ability 1.BulletHitExplosionParticleRedRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleGreenRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleBlueRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleAlphaRange"_FRange)})); game->AddEffect(std::make_unique<Effect>(monster.GetPos(),"Wizard.Ability 1.BulletHitExplosionParticleLifetimeRange"_FRange,"circle.png",upperLevel,"Wizard.Ability 1.BulletHitExplosionParticleSizeRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleFadeoutTimeRange"_FRange,vf2d{"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange,"Wizard.Ability 1.BulletHitExplosionParticleSpeedRange"_FRange},Pixel{uint8_t("Wizard.Ability 1.BulletHitExplosionParticleRedRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleGreenRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleBlueRange"_FRange),uint8_t("Wizard.Ability 1.BulletHitExplosionParticleAlphaRange"_FRange)}));
} }
game->SetupWorldShake("Wizard.Ability 1.WorldShakeTime"_F); game->SetupWorldShake("Wizard.Ability 1.WorldShakeTime"_F);
game->HurtEnemies(monster.GetPos(),"Wizard.Ability 1.BulletHitExplosionRange"_F/100*12,"Wizard.Ability 1.BulletHitExplosionDamageMult"_F*game->GetPlayer()->GetAttack(),OnUpperLevel(),0); game->HurtEnemies(monster.GetPos(),"Wizard.Ability 1.BulletHitExplosionRange"_F/100*12,"Wizard.Ability 1.BulletHitExplosionDamageMult"_F*game->GetPlayer()->GetAttack(),OnUpperLevel(),0);
game->AddEffect(std::make_unique<Effect>(monster.GetPos(),0,"SPLASH_EFFECT",upperLevel,"Wizard.Ability 1.BulletHitExplosionRange"_F/100*2,"Wizard.Ability 1.BulletHitExplosionFadeoutTime"_F,vf2d{},"Wizard.Ability 1.BulletHitExplosionColor"_Pixel)); game->AddEffect(std::make_unique<Effect>(monster.GetPos(),0,"splash_effect.png",upperLevel,"Wizard.Ability 1.BulletHitExplosionRange"_F/100*2,"Wizard.Ability 1.BulletHitExplosionFadeoutTime"_F,vf2d{},"Wizard.Ability 1.BulletHitExplosionColor"_Pixel));
return false; return false;
} }

@ -11,7 +11,7 @@ INCLUDE_EMITTER_LIST
LightningBolt::LightningBolt(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col) LightningBolt::LightningBolt(vf2d pos,vf2d vel,float radius,int damage,bool upperLevel,bool friendly,Pixel col)
:Bullet(pos,vel,radius,damage, :Bullet(pos,vel,radius,damage,
"LIGHTNING_BOLT",upperLevel,false,INFINITE,true,friendly,col){} "lightning_bolt.png",upperLevel,false,INFINITE,true,friendly,col){}
void LightningBolt::Update(float fElapsedTime){ void LightningBolt::Update(float fElapsedTime){
lastParticleSpawn=std::max(0.f,lastParticleSpawn-fElapsedTime); lastParticleSpawn=std::max(0.f,lastParticleSpawn-fElapsedTime);
@ -21,16 +21,16 @@ void LightningBolt::Update(float fElapsedTime){
uint8_t brightness=uint8_t("Wizard.Ability 2.ParticleColorRange"_FRange); uint8_t brightness=uint8_t("Wizard.Ability 2.ParticleColorRange"_FRange);
switch(rand()%4){ switch(rand()%4){
case 0:{ case 0:{
game->AddEffect(std::make_unique<Effect>(pos+vf2d{"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange,"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange},"Wizard.Ability 2.ParticleLifetimeRange"_FRange,"LIGHTNING_BOLT_PARTICLE1",upperLevel,"Wizard.Ability 2.ParticleSizeRange"_FRange,"Wizard.Ability 2.ParticleFadeoutTime"_F,vel*"Wizard.Ability 2.ParticleSpeedMultRange"_FRange,Pixel{brightness,brightness,brightness})); game->AddEffect(std::make_unique<Effect>(pos+vf2d{"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange,"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange},"Wizard.Ability 2.ParticleLifetimeRange"_FRange,"lightning_bolt_part1.png",upperLevel,"Wizard.Ability 2.ParticleSizeRange"_FRange,"Wizard.Ability 2.ParticleFadeoutTime"_F,vel*"Wizard.Ability 2.ParticleSpeedMultRange"_FRange,Pixel{brightness,brightness,brightness}));
}break; }break;
case 1:{ case 1:{
game->AddEffect(std::make_unique<Effect>(pos+vf2d{"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange,"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange},"Wizard.Ability 2.ParticleLifetimeRange"_FRange,"LIGHTNING_BOLT_PARTICLE2",upperLevel,"Wizard.Ability 2.ParticleSizeRange"_FRange,"Wizard.Ability 2.ParticleFadeoutTime"_F,vel*"Wizard.Ability 2.ParticleSpeedMultRange"_FRange,Pixel{brightness,brightness,brightness})); game->AddEffect(std::make_unique<Effect>(pos+vf2d{"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange,"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange},"Wizard.Ability 2.ParticleLifetimeRange"_FRange,"lightning_bolt_part2.png",upperLevel,"Wizard.Ability 2.ParticleSizeRange"_FRange,"Wizard.Ability 2.ParticleFadeoutTime"_F,vel*"Wizard.Ability 2.ParticleSpeedMultRange"_FRange,Pixel{brightness,brightness,brightness}));
}break; }break;
case 2:{ case 2:{
game->AddEffect(std::make_unique<Effect>(pos+vf2d{"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange,"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange},"Wizard.Ability 2.ParticleLifetimeRange"_FRange,"LIGHTNING_BOLT_PARTICLE3",upperLevel,"Wizard.Ability 2.ParticleSizeRange"_FRange,"Wizard.Ability 2.ParticleFadeoutTime"_F,vel*"Wizard.Ability 2.ParticleSpeedMultRange"_FRange,Pixel{brightness,brightness,brightness})); game->AddEffect(std::make_unique<Effect>(pos+vf2d{"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange,"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange},"Wizard.Ability 2.ParticleLifetimeRange"_FRange,"lightning_bolt_part3.png",upperLevel,"Wizard.Ability 2.ParticleSizeRange"_FRange,"Wizard.Ability 2.ParticleFadeoutTime"_F,vel*"Wizard.Ability 2.ParticleSpeedMultRange"_FRange,Pixel{brightness,brightness,brightness}));
}break; }break;
case 3:{ case 3:{
game->AddEffect(std::make_unique<Effect>(pos+vf2d{"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange,"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange},"Wizard.Ability 2.ParticleLifetimeRange"_FRange,"LIGHTNING_BOLT_PARTICLE4",upperLevel,"Wizard.Ability 2.ParticleSizeRange"_FRange,"Wizard.Ability 2.ParticleFadeoutTime"_F,vel*"Wizard.Ability 2.ParticleSpeedMultRange"_FRange,Pixel{brightness,brightness,brightness})); game->AddEffect(std::make_unique<Effect>(pos+vf2d{"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange,"Wizard.Ability 2.ParticleSpawnRadiusRange"_FRange},"Wizard.Ability 2.ParticleLifetimeRange"_FRange,"lightning_bolt_part4.png",upperLevel,"Wizard.Ability 2.ParticleSizeRange"_FRange,"Wizard.Ability 2.ParticleFadeoutTime"_F,vel*"Wizard.Ability 2.ParticleSpeedMultRange"_FRange,Pixel{brightness,brightness,brightness}));
}break; }break;
} }
} }
@ -40,7 +40,7 @@ bool LightningBolt::PlayerHit(Player*player)
{ {
deactivated=true; deactivated=true;
fadeOutTime="Wizard.Ability 2.BulletFadeoutTime"_F; fadeOutTime="Wizard.Ability 2.BulletFadeoutTime"_F;
game->AddEffect(std::make_unique<Effect>(player->GetPos(),"Wizard.Ability 2.SplashLifetime"_F,"LIGHTNING_SPLASH",upperLevel,player->GetSizeMult(),"Wizard.Ability 2.SplashFadeoutTime"_F,vf2d{},WHITE,"Wizard.Ability 2.SplashRotationRange"_FRange)); game->AddEffect(std::make_unique<Effect>(player->GetPos(),"Wizard.Ability 2.SplashLifetime"_F,"lightning_splash_effect.png",upperLevel,player->GetSizeMult(),"Wizard.Ability 2.SplashFadeoutTime"_F,vf2d{},WHITE,"Wizard.Ability 2.SplashRotationRange"_FRange));
return false; return false;
} }
@ -48,7 +48,7 @@ bool LightningBolt::MonsterHit(Monster& monster)
{ {
deactivated=true; deactivated=true;
fadeOutTime="Wizard.Ability 2.BulletFadeoutTime"_F; fadeOutTime="Wizard.Ability 2.BulletFadeoutTime"_F;
game->AddEffect(std::make_unique<Effect>(monster.GetPos(),"Wizard.Ability 2.SplashLifetime"_F,"LIGHTNING_SPLASH",upperLevel,monster.GetSizeMult(),"Wizard.Ability 2.SplashFadeoutTime"_F,vf2d{},WHITE,"Wizard.Ability 2.SplashRotationRange"_FRange)); game->AddEffect(std::make_unique<Effect>(monster.GetPos(),"Wizard.Ability 2.SplashLifetime"_F,"lightning_splash_effect.png",upperLevel,monster.GetSizeMult(),"Wizard.Ability 2.SplashFadeoutTime"_F,vf2d{},WHITE,"Wizard.Ability 2.SplashRotationRange"_FRange));
int targetsHit=0; int targetsHit=0;
for(Monster&m:MONSTER_LIST){ for(Monster&m:MONSTER_LIST){
if(&m==&monster||monster.OnUpperLevel()!=m.OnUpperLevel())continue; if(&m==&monster||monster.OnUpperLevel()!=m.OnUpperLevel())continue;
@ -57,7 +57,7 @@ bool LightningBolt::MonsterHit(Monster& monster)
if(dist<="Wizard.Ability 2.LightningChainRadius"_F/100*24){ if(dist<="Wizard.Ability 2.LightningChainRadius"_F/100*24){
if(m.Hurt(game->GetPlayer()->GetAttack()*"Wizard.Ability 2.LightningChainDamageMult"_F,OnUpperLevel(),0)){ if(m.Hurt(game->GetPlayer()->GetAttack()*"Wizard.Ability 2.LightningChainDamageMult"_F,OnUpperLevel(),0)){
EMITTER_LIST.push_back(std::make_unique<LightningBoltEmitter>(LightningBoltEmitter(monster.GetPos(),m.GetPos(),"Wizard.Ability 2.LightningChainFrequency"_F,"Wizard.Ability 2.LightningChainLifetime"_F,upperLevel))); EMITTER_LIST.push_back(std::make_unique<LightningBoltEmitter>(LightningBoltEmitter(monster.GetPos(),m.GetPos(),"Wizard.Ability 2.LightningChainFrequency"_F,"Wizard.Ability 2.LightningChainLifetime"_F,upperLevel)));
game->AddEffect(std::make_unique<Effect>(m.GetPos(),"Wizard.Ability 2.LightningChainSplashLifetime"_F,"LIGHTNING_SPLASH",upperLevel,monster.GetSizeMult(),"Wizard.Ability 2.LightningChainSplashFadeoutTime"_F,vf2d{},WHITE,"Wizard.Ability 2.LightningChainSplashRotationRange"_FRange)); game->AddEffect(std::make_unique<Effect>(m.GetPos(),"Wizard.Ability 2.LightningChainSplashLifetime"_F,"lightning_splash_effect.png",upperLevel,monster.GetSizeMult(),"Wizard.Ability 2.LightningChainSplashFadeoutTime"_F,vf2d{},WHITE,"Wizard.Ability 2.LightningChainSplashRotationRange"_FRange));
targetsHit++; targetsHit++;
} }
} }

@ -22,7 +22,7 @@ void LightningBoltEmitter::DrawLightningBolt(){
float targetDist=lineToTarget.length()*util::random(0.5); float targetDist=lineToTarget.length()*util::random(0.5);
targetAngle+=util::random((PI/2))-PI/4; targetAngle+=util::random((PI/2))-PI/4;
geom2d::line<float>lightningLine=geom2d::line<float>(currentPos,currentPos+vf2d{cos(targetAngle)*targetDist,sin(targetAngle)*targetDist}); geom2d::line<float>lightningLine=geom2d::line<float>(currentPos,currentPos+vf2d{cos(targetAngle)*targetDist,sin(targetAngle)*targetDist});
game->AddEffect(std::make_unique<Effect>(lightningLine.upoint(0),0,"CHAIN_LIGHTNING",upperLevel,vf2d{lightningLine.length(),0.2},0.2,vf2d{},WHITE,targetAngle,0,true)); game->AddEffect(std::make_unique<Effect>(lightningLine.upoint(0),0,"chain_lightning.png",upperLevel,vf2d{lightningLine.length(),0.2},0.2,vf2d{},WHITE,targetAngle,0,true));
int iterations=1; int iterations=1;
currentPos+=vf2d{cos(targetAngle)*targetDist,sin(targetAngle)*targetDist}; currentPos+=vf2d{cos(targetAngle)*targetDist,sin(targetAngle)*targetDist};
while(iterations<MAX_ITERATIONS&&geom2d::line<float>(currentPos,endPos).length()>1){ while(iterations<MAX_ITERATIONS&&geom2d::line<float>(currentPos,endPos).length()>1){
@ -31,7 +31,7 @@ void LightningBoltEmitter::DrawLightningBolt(){
float targetDist=lineToTarget.length()*util::random(0.5); float targetDist=lineToTarget.length()*util::random(0.5);
targetAngle+=util::random((PI/2))-PI/4; targetAngle+=util::random((PI/2))-PI/4;
geom2d::line<float>lightningLine=geom2d::line<float>(currentPos,currentPos+vf2d{cos(targetAngle)*targetDist,sin(targetAngle)*targetDist}); geom2d::line<float>lightningLine=geom2d::line<float>(currentPos,currentPos+vf2d{cos(targetAngle)*targetDist,sin(targetAngle)*targetDist});
game->AddEffect(std::make_unique<Effect>(lightningLine.upoint(0),0,"CHAIN_LIGHTNING",upperLevel,vf2d{lightningLine.length(),0.2},0.2,vf2d{},WHITE,targetAngle,0,true)); game->AddEffect(std::make_unique<Effect>(lightningLine.upoint(0),0,"chain_lightning.png",upperLevel,vf2d{lightningLine.length(),0.2},0.2,vf2d{},WHITE,targetAngle,0,true));
currentPos+=vf2d{cos(targetAngle)*targetDist,sin(targetAngle)*targetDist}; currentPos+=vf2d{cos(targetAngle)*targetDist,sin(targetAngle)*targetDist};
iterations++; iterations++;
} }

@ -33,7 +33,7 @@ geom2d::rect<int>TileGroup::GetRange(){
} }
geom2d::rect<int>TileGroup::GetFadeRange(){ geom2d::rect<int>TileGroup::GetFadeRange(){
return {range.pos+vi2d{-24,-24},range.size+vi2d{48,48}}; return {range.pos+vi2d{-24,-24},range.size+vi2d{48,24}};
} }
std::vector<TileRenderData>&TileGroup::GetTiles(){ std::vector<TileRenderData>&TileGroup::GetTiles(){

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "olcUTIL_Geometry2D.h" #include "olcUTIL_Geometry2D.h"
#include <set>
struct XMLTag; struct XMLTag;
@ -20,12 +21,21 @@ struct TilesetData{
std::map<int,XMLTag>upperForegroundTiles; std::map<int,XMLTag>upperForegroundTiles;
std::map<int,TileCollisionData>collision; std::map<int,TileCollisionData>collision;
std::map<int,XMLTag>staircaseTiles; std::map<int,XMLTag>staircaseTiles;
std::map<int,std::vector<int>>animationData;
std::set<int>reflectiveData;
};
struct TilesheetData{
TilesetData*tileset;
int firstgid;
}; };
struct TileRenderData{ struct TileRenderData{
Decal*tileset; TilesheetData tileSheet;
vi2d pos; vi2d pos;
vi2d tileSheetPos; vi2d tileSheetPos;
int tileID;
int layerID;
}; };
struct TileGroup{ struct TileGroup{
@ -44,5 +54,4 @@ public:
void InsertTile(TileRenderData tile); void InsertTile(TileRenderData tile);
bool playerBehind=false; bool playerBehind=false;
float fadeFactor=0.f; float fadeFactor=0.f;
int originatingLayer=-1;
}; };

@ -2,12 +2,14 @@
#include "DEFINES.h" #include "DEFINES.h"
#include "Crawler.h" #include "Crawler.h"
#include "utils.h" #include "utils.h"
#include "safemap.h"
INCLUDE_game INCLUDE_game
INCLUDE_MONSTER_LIST INCLUDE_MONSTER_LIST
INCLUDE_GFX
Meteor::Meteor(vf2d pos, float lifetime, std::string animation, bool upperLevel, vf2d size, float fadeout, vf2d spd, Pixel col, float rotation, float rotationSpd, bool additiveBlending) Meteor::Meteor(vf2d pos, float lifetime, std::string imgFile, bool upperLevel, vf2d size, float fadeout, vf2d spd, Pixel col, float rotation, float rotationSpd, bool additiveBlending)
:Effect(pos,lifetime,animation,upperLevel,size,fadeout,spd,col,rotation,rotationSpd,additiveBlending),startLifetime(lifetime){ :Effect(pos,lifetime,imgFile,upperLevel,size,fadeout,spd,col,rotation,rotationSpd,additiveBlending),startLifetime(lifetime){
} }
@ -22,10 +24,10 @@ bool Meteor::Update(float fElapsedTime){
float randomColorTintG=256*(1-util::random("Wizard.Ability 3.MeteorImpactParticleColorGVariance"_F))*(1-util::random("Wizard.Ability 3.MeteorImpactParticleColorGVariance"_F)); float randomColorTintG=256*(1-util::random("Wizard.Ability 3.MeteorImpactParticleColorGVariance"_F))*(1-util::random("Wizard.Ability 3.MeteorImpactParticleColorGVariance"_F));
float randomColorTintB="Wizard.Ability 3.MeteorImpactParticleColorBlueRange"_FRange; float randomColorTintB="Wizard.Ability 3.MeteorImpactParticleColorBlueRange"_FRange;
vf2d effectPos=vf2d{cos(randomAngle),sin(randomAngle)}*randomRange+meteorOffset; vf2d effectPos=vf2d{cos(randomAngle),sin(randomAngle)}*randomRange+meteorOffset;
game->AddEffect(std::make_unique<Effect>(effectPos,0,"DOT_PARTICLE",OnUpperLevel(),vf2d{util::random(2)+1,util::random(3)+1},util::random(3)+1,vf2d{util::random(10)-5,-util::random(20)-5},Pixel{255,uint8_t(randomColorTintG),uint8_t(randomColorTintB),uint8_t("Wizard.Ability 3.MeteorImpactParticleAlphaRange"_FRange)},0,0,true),effectPos.y<meteorOffset.y); game->AddEffect(std::make_unique<Effect>(effectPos,0,"circle.png",OnUpperLevel(),vf2d{util::random(2)+1,util::random(3)+1},util::random(3)+1,vf2d{util::random(10)-5,-util::random(20)-5},Pixel{255,uint8_t(randomColorTintG),uint8_t(randomColorTintB),uint8_t("Wizard.Ability 3.MeteorImpactParticleAlphaRange"_FRange)},0,0,true),effectPos.y<meteorOffset.y);
} }
game->HurtEnemies(pos,"Wizard.Ability 3.MeteorRadius"_F/100*24,game->GetPlayer()->GetAttack()*"Wizard.Ability 3.MeteorDamageMult"_F,OnUpperLevel(),0); game->HurtEnemies(pos,"Wizard.Ability 3.MeteorRadius"_F/100*24,game->GetPlayer()->GetAttack()*"Wizard.Ability 3.MeteorDamageMult"_F,OnUpperLevel(),0);
game->AddEffect(std::make_unique<PulsatingFire>(pos,"Wizard.Ability 3.FireRingLifetime"_F,"FIRE_RING1",OnUpperLevel(),vf2d{"Wizard.Ability 3.MeteorRadius"_F/100*2,"Wizard.Ability 3.MeteorRadius"_F/100*2},"Wizard.Ability 3.FireRingFadeoutTime"_F),true); game->AddEffect(std::make_unique<PulsatingFire>(pos,"Wizard.Ability 3.FireRingLifetime"_F,"fire_ring1.png",OnUpperLevel(),vf2d{"Wizard.Ability 3.MeteorRadius"_F/100*2,"Wizard.Ability 3.MeteorRadius"_F/100*2},"Wizard.Ability 3.FireRingFadeoutTime"_F),true);
} }
return Effect::Update(fElapsedTime); return Effect::Update(fElapsedTime);
} }
@ -34,8 +36,8 @@ void Meteor::Draw(){
if(lifetime>0){ if(lifetime>0){
vf2d scale=vf2d{192,64}/3.f*(startLifetime+1-lifetime)*0.25*size; vf2d scale=vf2d{192,64}/3.f*(startLifetime+1-lifetime)*0.25*size;
vf2d meteorOffset=vf2d{lifetime*"Wizard.Ability 3.MeteorXMovementMult"_I,0}*"Wizard.Ability 3.MeteorShadowStartingDist"_F; vf2d meteorOffset=vf2d{lifetime*"Wizard.Ability 3.MeteorXMovementMult"_I,0}*"Wizard.Ability 3.MeteorShadowStartingDist"_F;
vf2d centerPoint=pos-vf2d{game->GFX_Circle.Sprite()->width*scale.x/2,game->GFX_Circle.Sprite()->height*scale.y/2}; vf2d centerPoint=pos-vf2d{GFX["circle.png"].Sprite()->width*scale.x/2,GFX["circle.png"].Sprite()->height*scale.y/2};
game->view.DrawDecal(centerPoint+meteorOffset,game->GFX_Circle.Decal(),scale,{0,0,0,192}); game->view.DrawDecal(centerPoint+meteorOffset,GFX["circle.png"].Decal(),scale,{0,0,0,192});
} }
vf2d meteorOffset=pos+vf2d{lifetime*"Wizard.Ability 3.MeteorXMovementMult"_I,lifetime*"Wizard.Ability 3.MeteorYMovementMult"_I}*"Wizard.Ability 3.MeteorStartingDist"_F-vf2d{0,GetFrame().GetSourceRect().size.y/4.f}*size; vf2d meteorOffset=pos+vf2d{lifetime*"Wizard.Ability 3.MeteorXMovementMult"_I,lifetime*"Wizard.Ability 3.MeteorYMovementMult"_I}*"Wizard.Ability 3.MeteorStartingDist"_F-vf2d{0,GetFrame().GetSourceRect().size.y/4.f}*size;
if(lifetime<=0){ if(lifetime<=0){

@ -5,6 +5,8 @@
#include "BulletTypes.h" #include "BulletTypes.h"
#include "DEFINES.h" #include "DEFINES.h"
#include "safemap.h" #include "safemap.h"
#include "MonsterStrategyHelpers.h"
#include "utils.h"
INCLUDE_ANIMATION_DATA INCLUDE_ANIMATION_DATA
INCLUDE_MONSTER_DATA INCLUDE_MONSTER_DATA
@ -14,6 +16,7 @@ INCLUDE_game
INCLUDE_BULLET_LIST INCLUDE_BULLET_LIST
INCLUDE_DATA INCLUDE_DATA
INCLUDE_STRATEGY_DATA INCLUDE_STRATEGY_DATA
INCLUDE_GFX
safemap<std::string,int>STRATEGY_DATA; safemap<std::string,int>STRATEGY_DATA;
safemap<int,std::string>STRATEGY_ID_DATA; safemap<int,std::string>STRATEGY_ID_DATA;
@ -139,7 +142,7 @@ bool Monster::Update(float fElapsedTime){
} }
} }
} }
if(!game->GetPlayer()->HasIframes()&&game->GetPlayer()->OnUpperLevel()==OnUpperLevel()&&geom2d::overlaps(geom2d::circle(pos,12*size/2),geom2d::circle(game->GetPlayer()->GetPos(),12*game->GetPlayer()->GetSizeMult()/2))){ if(!game->GetPlayer()->HasIframes()&&abs(game->GetPlayer()->GetZ()-GetZ())<=1&&game->GetPlayer()->OnUpperLevel()==OnUpperLevel()&&geom2d::overlaps(geom2d::circle(pos,12*size/2),geom2d::circle(game->GetPlayer()->GetPos(),12*game->GetPlayer()->GetSizeMult()/2))){
geom2d::line line(pos,game->GetPlayer()->GetPos()); geom2d::line line(pos,game->GetPlayer()->GetPos());
float dist = line.length(); float dist = line.length();
SetPos(line.rpoint(-0.1)); SetPos(line.rpoint(-0.1));
@ -183,16 +186,16 @@ Key Monster::GetFacingDirection(){
return facingDirection; return facingDirection;
} }
void Monster::Draw(){ void Monster::Draw(){
strategyDraw(game);
if(GetZ()>0){ if(GetZ()>0){
vf2d shadowScale=vf2d{8*GetSizeMult()/3.f,1}/std::max(1.f,GetZ()/24); vf2d shadowScale=vf2d{8*GetSizeMult()/3.f,1}/std::max(1.f,GetZ()/24);
game->view.DrawDecal(GetPos()-vf2d{3,3}*shadowScale/2+vf2d{0,6*GetSizeMult()},game->GFX_Circle.Decal(),shadowScale,BLACK); game->view.DrawDecal(GetPos()-vf2d{3,3}*shadowScale/2+vf2d{0,6*GetSizeMult()},GFX["circle.png"].Decal(),shadowScale,BLACK);
}
if(GetFacingDirection()==RIGHT){
game->view.DrawPartialDecal((GetPos()+vf2d{float(GetFrame().GetSourceRect().size.x),0}*GetSizeMult())-vf2d{12,12}*GetSizeMult()-vf2d{0,GetZ()},GetFrame().GetSourceImage()->Decal(),GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,vf2d(GetSizeMult()*-1,GetSizeMult()),GetBuffs(BuffType::SLOWDOWN).size()>0?Pixel{uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(128+127*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration)))}:WHITE);
} else {
game->view.DrawPartialDecal(GetPos()-vf2d{12,12}*GetSizeMult()-vf2d{0,GetZ()},GetFrame().GetSourceImage()->Decal(),GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,vf2d(GetSizeMult(),GetSizeMult()),GetBuffs(BuffType::SLOWDOWN).size()>0?Pixel{uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(128+127*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration)))}:WHITE);
} }
game->view.DrawPartialRotatedDecal(GetPos()-vf2d{0,GetZ()},GetFrame().GetSourceImage()->Decal(),0,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,vf2d(GetSizeMult()*(GetFacingDirection()==RIGHT?-1:1),GetSizeMult()),GetBuffs(BuffType::SLOWDOWN).size()>0?Pixel{uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(128+127*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration)))}:WHITE);
}
void Monster::DrawReflection(float drawRatioX,float multiplierX){
game->SetDecalMode(DecalMode::ADDITIVE);
game->view.DrawPartialRotatedDecal(GetPos()+vf2d{drawRatioX*GetFrame().GetSourceRect().size.x,GetZ()+(GetFrame().GetSourceRect().size.y-16)*GetSizeMult()},GetFrame().GetSourceImage()->Decal(),0,GetFrame().GetSourceRect().size/2,GetFrame().GetSourceRect().pos,GetFrame().GetSourceRect().size,vf2d(GetSizeMult()*(GetFacingDirection()==RIGHT?-1:1)*multiplierX,GetSizeMult()*-1),GetBuffs(BuffType::SLOWDOWN).size()>0?Pixel{uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(255*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration))),uint8_t(128+127*abs(sin(1.4*GetBuffs(BuffType::SLOWDOWN)[0].duration)))}:WHITE);
game->SetDecalMode(DecalMode::NORMAL);
} }
void Monster::Collision(Player*p){ void Monster::Collision(Player*p){
if(MONSTER_DATA[id].GetCollisionDmg()>0&&!hasHitPlayer){ if(MONSTER_DATA[id].GetCollisionDmg()>0&&!hasHitPlayer){
@ -206,7 +209,7 @@ void Monster::Collision(Monster&m){
Collision(); Collision();
} }
void Monster::Collision(){ void Monster::Collision(){
if(strategy==0&&GetState()==State::MOVE_TOWARDS){//The run towards strategy causes state to return to normal upon a collision. if(strategy==0&&GetState()==State::MOVE_TOWARDS&&util::random(Monster::STRATEGY::_GetInt(*this,"BumpStopChance",strategy))<1){//The run towards strategy causes state to return to normal upon a collision.
SetState(State::NORMAL); SetState(State::NORMAL);
} }
} }
@ -285,7 +288,7 @@ void MonsterSpawner::SetTriggered(bool trigger,bool spawnMonsters){
triggered=trigger; triggered=trigger;
if(spawnMonsters){ if(spawnMonsters){
for(std::pair<int,vf2d>&monsterInfo:monsters){ for(std::pair<int,vf2d>&monsterInfo:monsters){
MONSTER_LIST.push_back(Monster(pos+monsterInfo.second,MONSTER_DATA[monsterInfo.first],DoesUpperLevelSpawning())); game->SpawnMonster(pos+monsterInfo.second,&MONSTER_DATA[monsterInfo.first],DoesUpperLevelSpawning());
} }
} }
} }

@ -92,7 +92,6 @@ private:
bool diesNormally=true; //If set to false, the monster death is handled in a special way. Set it to true when it's time to die. bool diesNormally=true; //If set to false, the monster death is handled in a special way. Set it to true when it's time to die.
float targetSize=0; float targetSize=0;
std::map<Attribute,std::variant<VARIANTS>>attributes; std::map<Attribute,std::variant<VARIANTS>>attributes;
std::function<void(Crawler*)>strategyDraw=[](Crawler*pge){};
protected: protected:
public: public:
Monster()=delete; Monster()=delete;
@ -112,6 +111,7 @@ public:
vf2d&GetTargetPos(); vf2d&GetTargetPos();
Key GetFacingDirection(); Key GetFacingDirection();
void Draw(); void Draw();
void DrawReflection(float drawRatioX,float multiplierX);
void Collision(Player*p); void Collision(Player*p);
void Collision(Monster&p); void Collision(Monster&p);
void Collision(); void Collision();
@ -145,6 +145,7 @@ public:
bool&GetBool(Attribute a); bool&GetBool(Attribute a);
vf2d&GetVf2d(Attribute a); vf2d&GetVf2d(Attribute a);
void SetStrategyDrawFunction(std::function<void(Crawler*)>func); void SetStrategyDrawFunction(std::function<void(Crawler*)>func);
std::function<void(Crawler*)>strategyDraw=[](Crawler*pge){};
private: private:
struct STRATEGY{ struct STRATEGY{
static int _GetInt(Monster&m,std::string param,int strategyNumber,int index=0); static int _GetInt(Monster&m,std::string param,int strategyNumber,int index=0);

@ -20,4 +20,6 @@ enum class Attribute{
JUMP_TARGET_POS, JUMP_TARGET_POS,
JUMP_ORIGINAL_POS, JUMP_ORIGINAL_POS,
RECOVERY_TIME, RECOVERY_TIME,
SHOOT_ANIMATION_TIME,
SHOOT_TIMER,
}; };

@ -10,6 +10,7 @@ INCLUDE_STRATEGY_DATA
INCLUDE_ANIMATION_DATA INCLUDE_ANIMATION_DATA
std::map<int,MonsterData>MONSTER_DATA; std::map<int,MonsterData>MONSTER_DATA;
safemap<std::string,MonsterData*>MONSTER_NAME_DATA;
MonsterData::MonsterData() MonsterData::MonsterData()
:atk(0),collisionDmg(0),hp(0),id(0),moveSpd(0),size(0),strategy(0){} :atk(0),collisionDmg(0),hp(0),id(0),moveSpd(0),size(0),strategy(0){}
@ -98,6 +99,7 @@ void MonsterData::InitializeMonsterData(){
); );
MONSTER_DATA[id]=monster; MONSTER_DATA[id]=monster;
MONSTER_NAME_DATA[MonsterName]=&MONSTER_DATA[id];
id++; id++;
} }

@ -88,6 +88,7 @@ std::vector<vf2d> Pathfinding::Solve_AStar(vf2d startPos,vf2d endPos,float maxRa
nodeStart->fGlobalGoal = heuristic(nodeStart, nodeEnd); nodeStart->fGlobalGoal = heuristic(nodeStart, nodeEnd);
std::list<sNode*> listNotTestedNodes; std::list<sNode*> listNotTestedNodes;
//if((!upperLevel && nodeStart->bObstacle)||(upperLevel && nodeStart->bObstacleUpper))return {};
listNotTestedNodes.push_back(nodeStart); listNotTestedNodes.push_back(nodeStart);
while (!listNotTestedNodes.empty() && nodeCurrent != nodeEnd) while (!listNotTestedNodes.empty() && nodeCurrent != nodeEnd)

@ -6,6 +6,7 @@
#include "BulletTypes.h" #include "BulletTypes.h"
#include "DEFINES.h" #include "DEFINES.h"
#include "safemap.h" #include "safemap.h"
#include "utils.h"
INCLUDE_MONSTER_DATA INCLUDE_MONSTER_DATA
INCLUDE_MONSTER_LIST INCLUDE_MONSTER_LIST
@ -230,7 +231,7 @@ void Player::Update(float fElapsedTime){
spin_angle-=spin_spd*fElapsedTime; spin_angle-=spin_spd*fElapsedTime;
} }
if(spin_attack_timer>0){ if(spin_attack_timer>0){
z="Warrior.Ability 2.SpinMaxHeight"_I*sin(3.3*(GROUND_SLAM_SPIN_TIME-spin_attack_timer)/GROUND_SLAM_SPIN_TIME); z=float("Warrior.Ability 2.SpinMaxHeight"_I)*sin(3.3*(GROUND_SLAM_SPIN_TIME-spin_attack_timer)/GROUND_SLAM_SPIN_TIME);
spin_attack_timer=std::max(0.f,spin_attack_timer-fElapsedTime); spin_attack_timer=std::max(0.f,spin_attack_timer-fElapsedTime);
} else { } else {
SetState(State::NORMAL); SetState(State::NORMAL);
@ -238,7 +239,7 @@ void Player::Update(float fElapsedTime){
z=0; z=0;
float numb=4; float numb=4;
game->HurtEnemies(pos,"Warrior.Ability 2.Range"_F/100*12,GetAttack()*"Warrior.Ability 2.DamageMult"_F,OnUpperLevel(),0); game->HurtEnemies(pos,"Warrior.Ability 2.Range"_F/100*12,GetAttack()*"Warrior.Ability 2.DamageMult"_F,OnUpperLevel(),0);
game->AddEffect(std::make_unique<Effect>(GetPos(),"Warrior.Ability 2.EffectLifetime"_F,"GROUND_SLAM_ATTACK_FRONT",upperLevel,"Warrior.Ability 2.Range"_F/300*1.33f,"Warrior.Ability 2.EffectFadetime"_F),std::make_unique<Effect>(GetPos(),"Warrior.Ability 2.EffectLifetime"_F,"GROUND_SLAM_ATTACK_BACK",upperLevel,"Warrior.Ability 2.Range"_F/300*1.33f,"Warrior.Ability 2.EffectFadetime"_F)); game->AddEffect(std::make_unique<Effect>(GetPos(),"Warrior.Ability 2.EffectLifetime"_F,"ground-slam-attack-front.png",upperLevel,"Warrior.Ability 2.Range"_F/300*1.33f,"Warrior.Ability 2.EffectFadetime"_F),std::make_unique<Effect>(GetPos(),"Warrior.Ability 2.EffectLifetime"_F,"ground-slam-attack-back.png",upperLevel,"Warrior.Ability 2.Range"_F/300*1.33f,"Warrior.Ability 2.EffectFadetime"_F));
} }
if(lastAnimationFlip>0){ if(lastAnimationFlip>0){
lastAnimationFlip=std::max(0.f,lastAnimationFlip-fElapsedTime); lastAnimationFlip=std::max(0.f,lastAnimationFlip-fElapsedTime);
@ -310,7 +311,11 @@ void Player::Update(float fElapsedTime){
} }
geom2d::line line(pos,m.GetPos()); geom2d::line line(pos,m.GetPos());
float dist = line.length(); float dist = line.length();
m.SetPos(line.rpoint(dist*1.1)); if(dist<=0.001){
m.SetPos(m.GetPos()+vf2d{util::random(2)-1,util::random(2)-1});
}else{
m.SetPos(line.rpoint(dist*1.1));
}
if(m.IsAlive()){ if(m.IsAlive()){
vel=line.vector().norm()*-128; vel=line.vector().norm()*-128;
} }
@ -341,9 +346,13 @@ void Player::Update(float fElapsedTime){
//If pressed is set to false, uses held instead. //If pressed is set to false, uses held instead.
auto CheckAndPerformAbility=[&](Ability&ability,HWButton key){ auto CheckAndPerformAbility=[&](Ability&ability,HWButton key){
if(ability.name!="???"){ if(ability.name!="???"){
if(CanAct()){ if(CanAct(ability)){
if(ability.cooldown==0&&GetMana()>=ability.manaCost){ if(ability.cooldown==0&&GetMana()>=ability.manaCost){
if(key.bHeld||key.bReleased&&&ability==castPrepAbility&&GetState()==State::PREP_CAST){ if(key.bHeld||key.bReleased&&&ability==castPrepAbility&&GetState()==State::PREP_CAST){
if(GetState()==State::CASTING){
SetState(State::NORMAL);
castInfo.castTimer=castInfo.castTotalTime=0;
}
if(AllowedToCast(ability)&&ability.action(this,{})){ if(AllowedToCast(ability)&&ability.action(this,{})){
ability.cooldown=ability.COOLDOWN_TIME; ability.cooldown=ability.COOLDOWN_TIME;
mana-=ability.manaCost; mana-=ability.manaCost;
@ -483,7 +492,12 @@ bool Player::CanMove(){
} }
bool Player::CanAct(){ bool Player::CanAct(){
return state!=State::CASTING&&state!=State::ANIMATION_LOCK; Ability dummyAbility{"Dummy Ability",0,0};
return CanAct(dummyAbility);
}
bool Player::CanAct(Ability&ability){
return (ability.canCancelCast||state!=State::CASTING)&&state!=State::ANIMATION_LOCK;
} }
bool Player::HasIframes(){ bool Player::HasIframes(){
@ -669,4 +683,8 @@ void Player::SetAnimationBasedOnTargetingDirection(float targetDirection){
UpdateAnimation("RANGER_SHOOT_N"); UpdateAnimation("RANGER_SHOOT_N");
} }
} }
}
void Player::SetIframes(float duration){
iframe_time=duration;
} }

@ -53,6 +53,7 @@ private:
float lastHitTimer=0; //When this is greater than zero, if we get hit again it adds to our displayed combo number. float lastHitTimer=0; //When this is greater than zero, if we get hit again it adds to our displayed combo number.
std::shared_ptr<DamageNumber>damageNumberPtr; std::shared_ptr<DamageNumber>damageNumberPtr;
void Initialize(); void Initialize();
float iframe_time=0;
protected: protected:
const float ATTACK_COOLDOWN="Warrior.Auto Attack.Cooldown"_F; const float ATTACK_COOLDOWN="Warrior.Auto Attack.Cooldown"_F;
const float MAGIC_ATTACK_COOLDOWN="Wizard.Auto Attack.Cooldown"_F; const float MAGIC_ATTACK_COOLDOWN="Wizard.Auto Attack.Cooldown"_F;
@ -69,10 +70,8 @@ protected:
void SetZ(float z); void SetZ(float z);
//Returns true if the move was valid and successful. //Returns true if the move was valid and successful.
bool SetPos(vf2d pos); bool SetPos(vf2d pos);
void Knockback(vf2d vel);
float friction="Player.Friction"_F; float friction="Player.Friction"_F;
float attack_cooldown_timer=0; float attack_cooldown_timer=0;
float iframe_time=0;
float teleportAnimationTimer=0; float teleportAnimationTimer=0;
vf2d teleportTarget={}; vf2d teleportTarget={};
vf2d teleportStartPosition={}; vf2d teleportStartPosition={};
@ -130,6 +129,9 @@ public:
bool CanPathfindTo(vf2d pos,vf2d targetPos,float range=8); bool CanPathfindTo(vf2d pos,vf2d targetPos,float range=8);
bool CanMove(); bool CanMove();
bool CanAct(); bool CanAct();
bool CanAct(Ability&ability);
void Knockback(vf2d vel);
void SetIframes(float duration);
void AddBuff(BuffType type,float duration,float intensity); void AddBuff(BuffType type,float duration,float intensity);
std::vector<Buff>GetBuffs(BuffType buff); std::vector<Buff>GetBuffs(BuffType buff);
@ -352,7 +354,8 @@ struct Witch:Player{
#class".Right Click Ability.Mana Cost"_I, \ #class".Right Click Ability.Mana Cost"_I, \
{uint8_t(#class".Right Click Ability.Cooldown Bar Color 1"_f[0]),uint8_t(#class".Right Click Ability.Cooldown Bar Color 1"_f[1]),uint8_t(#class".Right Click Ability.Cooldown Bar Color 1"_f[2]),uint8_t(#class".Right Click Ability.Cooldown Bar Color 1"_f[3]==0?255:#class".Right Click Ability.Cooldown Bar Color 1"_f[3])}, \ {uint8_t(#class".Right Click Ability.Cooldown Bar Color 1"_f[0]),uint8_t(#class".Right Click Ability.Cooldown Bar Color 1"_f[1]),uint8_t(#class".Right Click Ability.Cooldown Bar Color 1"_f[2]),uint8_t(#class".Right Click Ability.Cooldown Bar Color 1"_f[3]==0?255:#class".Right Click Ability.Cooldown Bar Color 1"_f[3])}, \
{uint8_t(#class".Right Click Ability.Cooldown Bar Color 2"_f[0]),uint8_t(#class".Right Click Ability.Cooldown Bar Color 2"_f[1]),uint8_t(#class".Right Click Ability.Cooldown Bar Color 2"_f[2]),uint8_t(#class".Right Click Ability.Cooldown Bar Color 2"_f[3]==0?255:#class".Right Click Ability.Cooldown Bar Color 2"_f[3])}, \ {uint8_t(#class".Right Click Ability.Cooldown Bar Color 2"_f[0]),uint8_t(#class".Right Click Ability.Cooldown Bar Color 2"_f[1]),uint8_t(#class".Right Click Ability.Cooldown Bar Color 2"_f[2]),uint8_t(#class".Right Click Ability.Cooldown Bar Color 2"_f[3]==0?255:#class".Right Click Ability.Cooldown Bar Color 2"_f[3])}, \
{#class".Right Click Ability.Precast Time"_F,#class".Right Click Ability.Casting Range"_I/100.f*24,#class".Right Click Ability.Casting Size"_I/100.f*24} \ {#class".Right Click Ability.Precast Time"_F,#class".Right Click Ability.Casting Range"_I/100.f*24,#class".Right Click Ability.Casting Size"_I/100.f*24}, \
bool( #class".Right Click Ability.CancelCast"_I ) \
}; \ }; \
class::ability1={ \ class::ability1={ \
#class".Ability 1.Name"_S, \ #class".Ability 1.Name"_S, \
@ -360,7 +363,8 @@ struct Witch:Player{
#class".Ability 1.Mana Cost"_I, \ #class".Ability 1.Mana Cost"_I, \
{uint8_t(#class".Ability 1.Cooldown Bar Color 1"_f[0]),uint8_t(#class".Ability 1.Cooldown Bar Color 1"_f[1]),uint8_t(#class".Ability 1.Cooldown Bar Color 1"_f[2]),uint8_t(#class".Ability 1.Cooldown Bar Color 1"_f[3]==0?255:#class".Ability 1.Cooldown Bar Color 1"_f[3])}, \ {uint8_t(#class".Ability 1.Cooldown Bar Color 1"_f[0]),uint8_t(#class".Ability 1.Cooldown Bar Color 1"_f[1]),uint8_t(#class".Ability 1.Cooldown Bar Color 1"_f[2]),uint8_t(#class".Ability 1.Cooldown Bar Color 1"_f[3]==0?255:#class".Ability 1.Cooldown Bar Color 1"_f[3])}, \
{uint8_t(#class".Ability 1.Cooldown Bar Color 2"_f[0]),uint8_t(#class".Ability 1.Cooldown Bar Color 2"_f[1]),uint8_t(#class".Ability 1.Cooldown Bar Color 2"_f[2]),uint8_t(#class".Ability 1.Cooldown Bar Color 2"_f[3]==0?255:#class".Ability 1.Cooldown Bar Color 2"_f[3])}, \ {uint8_t(#class".Ability 1.Cooldown Bar Color 2"_f[0]),uint8_t(#class".Ability 1.Cooldown Bar Color 2"_f[1]),uint8_t(#class".Ability 1.Cooldown Bar Color 2"_f[2]),uint8_t(#class".Ability 1.Cooldown Bar Color 2"_f[3]==0?255:#class".Ability 1.Cooldown Bar Color 2"_f[3])}, \
{#class".Ability 1.Precast Time"_F,#class".Ability 1.Casting Range"_I/100.f*24,#class".Ability 1.Casting Size"_I/100.f*24} \ {#class".Ability 1.Precast Time"_F,#class".Ability 1.Casting Range"_I/100.f*24,#class".Ability 1.Casting Size"_I/100.f*24}, \
bool(#class".Ability 1.CancelCast"_I) \
}; \ }; \
class::ability2={ \ class::ability2={ \
#class".Ability 2.Name"_S, \ #class".Ability 2.Name"_S, \
@ -368,7 +372,8 @@ struct Witch:Player{
#class".Ability 2.Mana Cost"_I, \ #class".Ability 2.Mana Cost"_I, \
{uint8_t(#class".Ability 2.Cooldown Bar Color 1"_f[0]),uint8_t(#class".Ability 2.Cooldown Bar Color 1"_f[1]),uint8_t(#class".Ability 2.Cooldown Bar Color 1"_f[2]),uint8_t(#class".Ability 2.Cooldown Bar Color 1"_f[3]==0?255:#class".Ability 2.Cooldown Bar Color 1"_f[3])}, \ {uint8_t(#class".Ability 2.Cooldown Bar Color 1"_f[0]),uint8_t(#class".Ability 2.Cooldown Bar Color 1"_f[1]),uint8_t(#class".Ability 2.Cooldown Bar Color 1"_f[2]),uint8_t(#class".Ability 2.Cooldown Bar Color 1"_f[3]==0?255:#class".Ability 2.Cooldown Bar Color 1"_f[3])}, \
{uint8_t(#class".Ability 2.Cooldown Bar Color 2"_f[0]),uint8_t(#class".Ability 2.Cooldown Bar Color 2"_f[1]),uint8_t(#class".Ability 2.Cooldown Bar Color 2"_f[2]),uint8_t(#class".Ability 2.Cooldown Bar Color 2"_f[3]==0?255:#class".Ability 2.Cooldown Bar Color 2"_f[3])}, \ {uint8_t(#class".Ability 2.Cooldown Bar Color 2"_f[0]),uint8_t(#class".Ability 2.Cooldown Bar Color 2"_f[1]),uint8_t(#class".Ability 2.Cooldown Bar Color 2"_f[2]),uint8_t(#class".Ability 2.Cooldown Bar Color 2"_f[3]==0?255:#class".Ability 2.Cooldown Bar Color 2"_f[3])}, \
{#class".Ability 2.Precast Time"_F,#class".Ability 2.Casting Range"_I/100.f*24,#class".Ability 2.Casting Size"_I/100.f*24} \ {#class".Ability 2.Precast Time"_F,#class".Ability 2.Casting Range"_I/100.f*24,#class".Ability 2.Casting Size"_I/100.f*24}, \
bool(#class".Ability 2.CancelCast"_I) \
}; \ }; \
class::ability3={ \ class::ability3={ \
#class".Ability 3.Name"_S, \ #class".Ability 3.Name"_S, \
@ -376,6 +381,7 @@ struct Witch:Player{
#class".Ability 3.Mana Cost"_I, \ #class".Ability 3.Mana Cost"_I, \
{uint8_t(#class".Ability 3.Cooldown Bar Color 1"_f[0]),uint8_t(#class".Ability 3.Cooldown Bar Color 1"_f[1]),uint8_t(#class".Ability 3.Cooldown Bar Color 1"_f[2]),uint8_t(#class".Ability 3.Cooldown Bar Color 1"_f[3]==0?255:#class".Ability 3.Cooldown Bar Color 1"_f[3])}, \ {uint8_t(#class".Ability 3.Cooldown Bar Color 1"_f[0]),uint8_t(#class".Ability 3.Cooldown Bar Color 1"_f[1]),uint8_t(#class".Ability 3.Cooldown Bar Color 1"_f[2]),uint8_t(#class".Ability 3.Cooldown Bar Color 1"_f[3]==0?255:#class".Ability 3.Cooldown Bar Color 1"_f[3])}, \
{uint8_t(#class".Ability 3.Cooldown Bar Color 2"_f[0]),uint8_t(#class".Ability 3.Cooldown Bar Color 2"_f[1]),uint8_t(#class".Ability 3.Cooldown Bar Color 2"_f[2]),uint8_t(#class".Ability 3.Cooldown Bar Color 2"_f[3]==0?255:#class".Ability 3.Cooldown Bar Color 2"_f[3])}, \ {uint8_t(#class".Ability 3.Cooldown Bar Color 2"_f[0]),uint8_t(#class".Ability 3.Cooldown Bar Color 2"_f[1]),uint8_t(#class".Ability 3.Cooldown Bar Color 2"_f[2]),uint8_t(#class".Ability 3.Cooldown Bar Color 2"_f[3]==0?255:#class".Ability 3.Cooldown Bar Color 2"_f[3])}, \
{#class".Ability 3.Precast Time"_F,#class".Ability 3.Casting Range"_I/100.f*24,#class".Ability 3.Casting Size"_I/100.f*24} \ {#class".Ability 3.Precast Time"_F,#class".Ability 3.Casting Range"_I/100.f*24,#class".Ability 3.Casting Size"_I/100.f*24}, \
bool(#class".Ability 3.CancelCast"_I) \
}; \ }; \
class::ability4={"???",0,0}; class::ability4={"???",0,0};

@ -25,7 +25,7 @@ bool PulsatingFire::Update(float fElapsedTime){
float randomRange=12*size.x*(1-util::random("Wizard.Ability 3.FireRingParticleRandomVariance"_F))*(1-util::random("Wizard.Ability 3.FireRingParticleRandomVariance"_F)); float randomRange=12*size.x*(1-util::random("Wizard.Ability 3.FireRingParticleRandomVariance"_F))*(1-util::random("Wizard.Ability 3.FireRingParticleRandomVariance"_F));
float randomColorTintG=128*(1-util::random("Wizard.Ability 3.FireRingParticleColorGVariance"_F))*(1-util::random("Wizard.Ability 3.FireRingParticleColorGVariance"_F)); float randomColorTintG=128*(1-util::random("Wizard.Ability 3.FireRingParticleColorGVariance"_F))*(1-util::random("Wizard.Ability 3.FireRingParticleColorGVariance"_F));
float randomColorTint="Wizard.Ability 3.FireRingParticleColorBlueRange"_FRange; float randomColorTint="Wizard.Ability 3.FireRingParticleColorBlueRange"_FRange;
game->AddEffect(std::make_unique<Effect>(pos+vf2d{cos(randomAngle),sin(randomAngle)}*randomRange,0,"DOT_PARTICLE",OnUpperLevel(),vf2d{"Wizard.Ability 3.FireRingParticleXSizeRange"_FRange,"Wizard.Ability 3.FireRingParticleYSizeRange"_FRange},"Wizard.Ability 3.FireRingParticleFadeoutTimeRange"_FRange,vf2d{"Wizard.Ability 3.FireRingParticleXSpeedRange"_FRange,"Wizard.Ability 3.FireRingParticleYSpeedRange"_FRange},Pixel{128,uint8_t(randomColorTintG),uint8_t(randomColorTint),uint8_t("Wizard.Ability 3.FireRingParticleAlphaRange"_FRange)})); game->AddEffect(std::make_unique<Effect>(pos+vf2d{cos(randomAngle),sin(randomAngle)}*randomRange,0,"circle.png",OnUpperLevel(),vf2d{"Wizard.Ability 3.FireRingParticleXSizeRange"_FRange,"Wizard.Ability 3.FireRingParticleYSizeRange"_FRange},"Wizard.Ability 3.FireRingParticleFadeoutTimeRange"_FRange,vf2d{"Wizard.Ability 3.FireRingParticleXSpeedRange"_FRange,"Wizard.Ability 3.FireRingParticleYSpeedRange"_FRange},Pixel{128,uint8_t(randomColorTintG),uint8_t(randomColorTint),uint8_t("Wizard.Ability 3.FireRingParticleAlphaRange"_FRange)}));
} }
lastParticleTimer="Wizard.Ability 3.FireRingParticleFreqRange"_FRange; lastParticleTimer="Wizard.Ability 3.FireRingParticleFreqRange"_FRange;
} }
@ -41,22 +41,22 @@ void PulsatingFire::Draw(){
Animate2D::FrameSequence*effectSpr=nullptr; Animate2D::FrameSequence*effectSpr=nullptr;
switch(int(pulsatingFireValues[i]*5)){ switch(int(pulsatingFireValues[i]*5)){
case 0:{ case 0:{
effectSpr=&ANIMATION_DATA["FIRE_RING1"]; effectSpr=&ANIMATION_DATA["fire_ring0.png"];
}break; }break;
case 1:{ case 1:{
effectSpr=&ANIMATION_DATA["FIRE_RING2"]; effectSpr=&ANIMATION_DATA["fire_ring1.png"];
}break; }break;
case 2:{ case 2:{
effectSpr=&ANIMATION_DATA["FIRE_RING3"]; effectSpr=&ANIMATION_DATA["fire_ring2.png"];
}break; }break;
case 3:{ case 3:{
effectSpr=&ANIMATION_DATA["FIRE_RING4"]; effectSpr=&ANIMATION_DATA["fire_ring3.png"];
}break; }break;
case 4:{ case 4:{
effectSpr=&ANIMATION_DATA["FIRE_RING5"]; effectSpr=&ANIMATION_DATA["fire_ring4.png"];
}break; }break;
default: default:
effectSpr=&ANIMATION_DATA["FIRE_RING1"]; effectSpr=&ANIMATION_DATA["fire_ring0.png"];
} }
const Renderable*img=effectSpr->GetFrame(0).GetSourceImage(); const Renderable*img=effectSpr->GetFrame(0).GetSourceImage();
game->view.DrawPartialDecal(pos-effectSpr->GetFrame(0).GetSourceRect().size/2*size,img->Decal(),effectSpr->GetFrame(0).GetSourceRect().pos,effectSpr->GetFrame(0).GetSourceRect().size,size,{255,uint8_t(pulsatingFireValues[i]*256),0,uint8_t((63*(sin("Wizard.Ability 3.FireRingOscillatingFrequency"_F*lifetime+PI*pulsatingFireValues[i]))+63)*(fadeout/original_fadeoutTime))}); game->view.DrawPartialDecal(pos-effectSpr->GetFrame(0).GetSourceRect().size/2*size,img->Decal(),effectSpr->GetFrame(0).GetSourceRect().pos,effectSpr->GetFrame(0).GetSourceRect().size,size,{255,uint8_t(pulsatingFireValues[i]*256),0,uint8_t((63*(sin("Wizard.Ability 3.FireRingOscillatingFrequency"_F*lifetime+PI*pulsatingFireValues[i]))+63)*(fadeout/original_fadeoutTime))});

@ -4,29 +4,77 @@
#include "Crawler.h" #include "Crawler.h"
#include "utils.h" #include "utils.h"
#include "safemap.h" #include "safemap.h"
#include "Effect.h"
#include "FallingDebris.h"
INCLUDE_game INCLUDE_game
INCLUDE_BULLET_LIST INCLUDE_BULLET_LIST
INCLUDE_ANIMATION_DATA INCLUDE_ANIMATION_DATA
INCLUDE_MONSTER_NAME_DATA
typedef Attribute A; typedef Attribute A;
void Monster::STRATEGY::SLIMEKING(Monster&m,float fElapsedTime,int strategyNumber){ void Monster::STRATEGY::SLIMEKING(Monster&m,float fElapsedTime,int strategyNumber){
float bulletSpd=ConfigFloat("BulletSpd")/100*24; float bulletSpd=ConfigFloat("BulletSpd")/100*24;
m.F(A::SHOOT_TIMER)=std::max(0.f,m.F(A::SHOOT_TIMER)-fElapsedTime);
m.F(A::SHOOT_RING_TIMER)=std::max(0.f,m.F(A::SHOOT_RING_TIMER)-fElapsedTime); m.F(A::SHOOT_RING_TIMER)=std::max(0.f,m.F(A::SHOOT_RING_TIMER)-fElapsedTime);
m.F(A::SHOOT_RING_DELAY)=std::max(0.f,m.F(A::SHOOT_RING_DELAY)-fElapsedTime); m.F(A::SHOOT_RING_DELAY)=std::max(0.f,m.F(A::SHOOT_RING_DELAY)-fElapsedTime);
m.F(A::JUMP_LANDING_TIMER)=std::max(0.f,m.F(A::JUMP_LANDING_TIMER)-fElapsedTime); m.F(A::JUMP_LANDING_TIMER)=std::max(0.f,m.F(A::JUMP_LANDING_TIMER)-fElapsedTime);
auto ShootBulletRing=[&](float angleOffset){ const auto ShootBulletRing=[&](float angleOffset){
int bulletCount=ConfigInt("Phase1.RingBulletCount"); int bulletCount=ConfigInt("Phase1.RingBulletCount");
for(int i=0;i<bulletCount;i++){ for(int i=0;i<bulletCount;i++){
float angle=((2*PI)/bulletCount)*i+angleOffset; float angle=((2*PI)/bulletCount)*i+angleOffset;
BULLET_LIST.emplace_back(std::make_unique<Bullet>(m.GetPos(),vf2d{cos(angle),sin(angle)}*bulletSpd,6,ConfigInt("ProjectileDamage"),m.OnUpperLevel(),false,YELLOW,vf2d{6,6})); BULLET_LIST.emplace_back(std::make_unique<Bullet>(m.GetPos(),vf2d{cos(angle),sin(angle)}*bulletSpd,6,ConfigInt("ProjectileDamage"),m.OnUpperLevel(),false,YELLOW,vf2d{6,6}));
} }
}; };
auto StartJump=[&](float jumpDuration,vf2d targetPos,float recoveryTime){
const auto Landed=[&ShootBulletRing,&m](int currentPhase){
if(currentPhase==1){
ShootBulletRing(m.F(A::SHOOT_RING_OFFSET));
}
};
const auto TransitionPhase=[&](int newPhase){
const int MAX_ATTEMPTS=100; //Maximum number of tries to find a valid location.
Player*player=game->GetPlayer();
const auto PositionInRangeOfPlayer=[&player](vf2d&pos,float radius){
return geom2d::line<float>(player->GetPos(),pos).length()<=player->GetSizeMult()*12*2+radius;
};
const auto SpawnMonsterFromConfig=[&](int phase){
std::string spawnMonster=ConfigStringArr("Phase"+std::to_string(phase)+".MonsterSpawnOnChange",0);
int spawnCount=ConfigIntArr("Phase"+std::to_string(phase)+".MonsterSpawnOnChange",1);
for(int i=0;i<spawnCount;i++){
float randomAngle=util::random(2*PI);
vf2d spawnPos=m.pos+vf2d{cos(randomAngle),sin(randomAngle)}*m.GetSizeMult()*12;
for(int attempts=0;attempts<MAX_ATTEMPTS&&PositionInRangeOfPlayer(spawnPos,MONSTER_NAME_DATA[spawnMonster]->GetSizeMult()*12);attempts++){
randomAngle=util::random(2*PI);
spawnPos=m.pos+vf2d{cos(randomAngle),sin(randomAngle)}*m.GetSizeMult()*12;
}
game->SpawnMonster(spawnPos,MONSTER_NAME_DATA[spawnMonster]);
}
};
switch(newPhase){
case 2:{
SpawnMonsterFromConfig(2);
}break;
case 3:{
SpawnMonsterFromConfig(3);
}break;
case 4:{
SpawnMonsterFromConfig(4);
}break;
case 5:{
}break;
}
};
const auto StartJump=[&](float jumpDuration,vf2d targetPos,float recoveryTime){
m.V(A::JUMP_ORIGINAL_POS)=m.GetPos(); m.V(A::JUMP_ORIGINAL_POS)=m.GetPos();
m.F(A::JUMP_ORIGINAL_LANDING_TIMER)=m.F(A::JUMP_LANDING_TIMER)=jumpDuration; m.F(A::JUMP_ORIGINAL_LANDING_TIMER)=m.F(A::JUMP_LANDING_TIMER)=jumpDuration;
m.V(A::JUMP_TARGET_POS)=targetPos; m.V(A::JUMP_TARGET_POS)=targetPos;
@ -44,7 +92,6 @@ void Monster::STRATEGY::SLIMEKING(Monster&m,float fElapsedTime,int strategyNumbe
if(m.state==State::JUMP){ if(m.state==State::JUMP){
float jumpLandingTimerRatio=m.F(A::JUMP_LANDING_TIMER)/m.F(A::JUMP_ORIGINAL_LANDING_TIMER); float jumpLandingTimerRatio=m.F(A::JUMP_LANDING_TIMER)/m.F(A::JUMP_ORIGINAL_LANDING_TIMER);
vf2d moveVel;
if(m.GetPos().x>game->GetPlayer()->GetPos().x){ if(m.GetPos().x>game->GetPlayer()->GetPos().x){
m.SetX(std::max(game->GetPlayer()->GetPos().x,m.GetPos().x-ConfigInt("JumpMoveSpd")*game->GetElapsedTime())); m.SetX(std::max(game->GetPlayer()->GetPos().x,m.GetPos().x-ConfigInt("JumpMoveSpd")*game->GetElapsedTime()));
} else } else
@ -65,29 +112,52 @@ void Monster::STRATEGY::SLIMEKING(Monster&m,float fElapsedTime,int strategyNumbe
if(m.F(A::JUMP_LANDING_TIMER)==0){ if(m.F(A::JUMP_LANDING_TIMER)==0){
m.state=State::RECOVERY; m.state=State::RECOVERY;
game->SetupWorldShake(0.6); game->SetupWorldShake(0.6);
geom2d::line<float>lineToPlayer(m.GetPos(),game->GetPlayer()->GetPos());
float dist=lineToPlayer.length();
for(int i=0;i<200;i++){
float randomDir=util::random(2*PI);
game->AddEffect(std::make_unique<FallingDebris>(m.GetPos()+vf2d{cos(randomDir),sin(randomDir)}*m.GetSizeMult()*8,util::random(1),"circle.png",m.OnUpperLevel(),vf2d{1,1},0.5,vf2d{cos(randomDir)*util::random(5),sin(randomDir)*-util::random(15)-5}*30,BLACK),true);
}
if(dist<12*m.GetSizeMult()){
game->GetPlayer()->Hurt(ConfigInt("JumpAttackDamage"),m.OnUpperLevel(),m.GetZ());
if(dist<0.001){
float randomDir=util::random(2*PI);
lineToPlayer={m.GetPos(),m.GetPos()+vf2d{cos(randomDir),sin(randomDir)}*1};
}
game->GetPlayer()->Knockback(lineToPlayer.vector().norm()*ConfigInt("JumpKnockbackFactor"));
game->GetPlayer()->SetIframes(1);
}
Landed(m.phase);
m.SetStrategyDrawFunction([](Crawler*game){}); m.SetStrategyDrawFunction([](Crawler*game){});
} else } else
if(m.F(A::JUMP_LANDING_TIMER)<=ConfigFloat("JumpWarningIndicatorTime")){ if(m.F(A::JUMP_LANDING_TIMER)<=ConfigFloat("JumpWarningIndicatorTime")){
m.SetStrategyDrawFunction([&](Crawler*game){ m.SetStrategyDrawFunction([&](Crawler*game){
Decal*dec=ANIMATION_DATA["RANGE_INDICATOR"].GetFrame(game->GetElapsedTime()).GetSourceImage()->Decal(); Decal*dec=ANIMATION_DATA["range_indicator.png"].GetFrame(game->GetElapsedTime()).GetSourceImage()->Decal();
game->view.DrawRotatedDecal(m.GetPos(),dec,0,dec->sprite->Size()/2,vf2d{m.GetSizeMult(),m.GetSizeMult()}/2,RED); game->view.DrawRotatedDecal(m.GetPos(),dec,0,dec->sprite->Size()/2,vf2d{m.GetSizeMult(),m.GetSizeMult()},RED);
}); });
} }
return; return;
} }
if(m.state==State::CASTING){
m.UpdateAnimation("monsters/Slime King - Cast.png");
return;
}
switch(m.phase){ switch(m.phase){
case 0:{ case 0:{
m.size=ConfigInt("Phase1.Size")/100; m.size=ConfigInt("Phase1.Size")/100;
m.diesNormally=false; m.diesNormally=false;
m.F(A::IFRAME_TIME_UPON_HIT)=0; m.F(A::IFRAME_TIME_UPON_HIT)=0;
m.iframe_timer=ConfigFloat("Phase5.IframeTimePerHit"); m.iframe_timer=ConfigFloat("Phase5.IframeTimePerHit");
m.phase=1; m.phase=ConfigInt("StartPhase");
}break; }break;
case 1:{ case 1:{
if(m.hp<=m.maxhp*ConfigFloat("Phase2.Change")/100){ if(m.hp<=m.maxhp*ConfigFloat("Phase2.Change")/100){
m.phase=2; m.phase=2;
m.SetSize(ConfigFloat("Phase2.Size")/100,false); m.SetSize(ConfigFloat("Phase2.Size")/100,false);
TransitionPhase(m.phase);
return;
} }
if(m.F(A::SHOOT_RING_TIMER)==0){ if(m.F(A::SHOOT_RING_TIMER)==0){
if(m.I(A::PATTERN_REPEAT_COUNT)>=ConfigInt("Phase1.JumpAfter")){ if(m.I(A::PATTERN_REPEAT_COUNT)>=ConfigInt("Phase1.JumpAfter")){
@ -119,18 +189,38 @@ void Monster::STRATEGY::SLIMEKING(Monster&m,float fElapsedTime,int strategyNumbe
if(m.hp<=m.maxhp*ConfigFloat("Phase3.Change")/100){ if(m.hp<=m.maxhp*ConfigFloat("Phase3.Change")/100){
m.phase=3; m.phase=3;
m.SetSize(ConfigFloat("Phase3.Size")/100,false); m.SetSize(ConfigFloat("Phase3.Size")/100,false);
TransitionPhase(m.phase);
return;
}
if(m.F(A::SHOOT_TIMER)==0){
m.F(A::SHOOT_TIMER)=ConfigInt("Phase2.ShootRate");
m.I(A::PATTERN_REPEAT_COUNT)++;
int bulletCount=ConfigInt("Phase2.ShootProjectileCount");
for(int i=0;i<bulletCount;i++){
float initialAngle=util::angleTo(m.GetPos(),game->GetPlayer()->GetPos());
float angle=(i-(bulletCount/2))*util::degToRad(ConfigFloat("Phase2.ShootAngleSpread"))+initialAngle;
BULLET_LIST.emplace_back(std::make_unique<Bullet>(m.GetPos(),vf2d{cos(angle),sin(angle)}*bulletSpd,6,ConfigInt("ProjectileDamage"),m.OnUpperLevel(),false,YELLOW,vf2d{6,6}));
}
}
if(m.I(A::PATTERN_REPEAT_COUNT)>ConfigInt("Phase2.ShootCount")){
m.I(A::PATTERN_REPEAT_COUNT)=0;
m.SetState(State::CASTING);
} }
}break; }break;
case 3:{ case 3:{
if(m.hp<=m.maxhp*ConfigFloat("Phase4.Change")/100){ if(m.hp<=m.maxhp*ConfigFloat("Phase4.Change")/100){
m.phase=4; m.phase=4;
m.SetSize(ConfigFloat("Phase4.Size")/100,false); m.SetSize(ConfigFloat("Phase4.Size")/100,false);
TransitionPhase(m.phase);
return;
} }
}break; }break;
case 4:{ case 4:{
if(m.hp<=0){ if(m.hp<=0){
m.phase=5; m.phase=5;
m.F(A::IFRAME_TIME_UPON_HIT)=1; m.F(A::IFRAME_TIME_UPON_HIT)=1;
TransitionPhase(m.phase);
return;
} }
}break; }break;
} }

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "olcPixelGameEngine.h" #include "olcPixelGameEngine.h"
#include "olcUTIL_Geometry2D.h" #include "olcUTIL_Geometry2D.h"
#include <strstream> #include <sstream>
using namespace olc; using namespace olc;
@ -223,10 +223,6 @@ typedef std::map<std::string,std::vector<geom2d::rect<int>>> ZoneData;
LayerTag l = {newTag}; LayerTag l = {newTag};
parsedMapInfo.LayerData.push_back(l); parsedMapInfo.LayerData.push_back(l);
}else }else
if (newTag.tag=="object"&&newTag.data["type"]=="UpperSpawnGroup") {
parsedMapInfo.SpawnerData[newTag.GetInteger("id")]={newTag};
parsedMapInfo.SpawnerData[newTag.GetInteger("id")].upperLevel=true;
} else
if (newTag.tag=="object"&&newTag.data["type"]=="SpawnGroup") { if (newTag.tag=="object"&&newTag.data["type"]=="SpawnGroup") {
parsedMapInfo.SpawnerData[newTag.GetInteger("id")]={newTag}; parsedMapInfo.SpawnerData[newTag.GetInteger("id")]={newTag};
} else } else
@ -318,6 +314,26 @@ typedef std::map<std::string,std::vector<geom2d::rect<int>>> ZoneData;
for(XMLTag&monster:accumulatedMonsterTags){ for(XMLTag&monster:accumulatedMonsterTags){
parsedMapInfo.SpawnerData[monster.GetInteger("spawnerLink")].monsters.push_back(monster); parsedMapInfo.SpawnerData[monster.GetInteger("spawnerLink")].monsters.push_back(monster);
} }
for(auto&spawnerData:parsedMapInfo.SpawnerData){
SpawnerTag&spawner=spawnerData.second;
for(auto&zoneData:parsedMapInfo.ZoneData){
if(zoneData.first=="UpperZone"){
std::vector<geom2d::rect<int>>&zones=zoneData.second;
for(geom2d::rect<int>&zone:zones){
if(geom2d::overlaps(zone,geom2d::rect<int>{{spawner.ObjectData.GetInteger("x"),spawner.ObjectData.GetInteger("y")},{spawner.ObjectData.GetInteger("width"),spawner.ObjectData.GetInteger("height")}})){
spawner.upperLevel=true;
goto continueSpawnerLoop;
}
}
}
}
continueSpawnerLoop:
continue;
}
std::sort(parsedMapInfo.TilesetData.begin(),parsedMapInfo.TilesetData.end(),[](XMLTag&t1,XMLTag&t2){return t1.GetInteger("firstgid")<t2.GetInteger("firstgid");});
std::cout<<"Parsed Map Data:\n"<<parsedMapInfo<<"\n"; std::cout<<"Parsed Map Data:\n"<<parsedMapInfo<<"\n";
} }
#endif #endif

@ -1,9 +1,10 @@
#pragma once #pragma once
#include "olcPixelGameEngine.h" #include "olcPixelGameEngine.h"
#include <strstream> #include <sstream>
#include "TMXParser.h" #include "TMXParser.h"
#include "Map.h" #include "Map.h"
#include "olcUTIL_Geometry2D.h" #include "olcUTIL_Geometry2D.h"
#include "olcUTIL_DataFile.h"
using namespace olc; using namespace olc;
@ -13,6 +14,8 @@ struct Tileset{
std::map<int,XMLTag> UpperForegroundTileData; std::map<int,XMLTag> UpperForegroundTileData;
std::map<int,TileCollisionData> CollisionData; std::map<int,TileCollisionData> CollisionData;
std::map<int,XMLTag> StaircaseData; std::map<int,XMLTag> StaircaseData;
std::map<int,std::vector<int>> AnimationData;
std::set<int> ReflectiveData;
friend std::ostream& operator << (std::ostream& os, Tileset& rhs); friend std::ostream& operator << (std::ostream& os, Tileset& rhs);
}; };
@ -89,19 +92,35 @@ class TSXParser{
parsedTilesetInfo.ImageData=newTag; parsedTilesetInfo.ImageData=newTag;
} else } else
if (newTag.tag=="tile"&&newTag.data["type"]=="ForegroundTile"){ if (newTag.tag=="tile"&&newTag.data["type"]=="ForegroundTile"){
previousTag=newTag.tag;
previousTagID=newTag.GetInteger("id");
parsedTilesetInfo.ForegroundTileData[newTag.GetInteger("id")]=newTag; parsedTilesetInfo.ForegroundTileData[newTag.GetInteger("id")]=newTag;
} else } else
if (newTag.tag=="tile"&&newTag.data["type"]=="UpperForegroundTile"){ if (newTag.tag=="tile"&&newTag.data["type"]=="UpperForegroundTile"){
previousTag=newTag.tag;
previousTagID=newTag.GetInteger("id");
parsedTilesetInfo.UpperForegroundTileData[newTag.GetInteger("id")]=newTag; parsedTilesetInfo.UpperForegroundTileData[newTag.GetInteger("id")]=newTag;
} else } else
if (newTag.tag=="tile"&&newTag.data["type"]=="Staircase"){ if (newTag.tag=="tile"&&newTag.data["type"]=="Staircase"){
previousTag=newTag.tag;
staircaseTag=newTag.tag; staircaseTag=newTag.tag;
previousTagID=newTag.GetInteger("id"); previousTagID=newTag.GetInteger("id");
} else } else
if (newTag.tag=="tile"&&newTag.data["type"]=="Reflective"){
previousTag=newTag.tag;
previousTagID=newTag.GetInteger("id");
parsedTilesetInfo.ReflectiveData.insert(newTag.GetInteger("id"));
} else
if (newTag.tag=="tile"){ if (newTag.tag=="tile"){
previousTag=newTag.tag; previousTag=newTag.tag;
previousTagID=newTag.GetInteger("id"); previousTagID=newTag.GetInteger("id");
} else } else
if (newTag.tag=="frame"){
//The way animation data is stored is every "animation_tile_precision" ms indicating which frame we should be on.
for(int i=0;i<newTag.GetInteger("duration")/"animation_tile_precision"_I;i++){
parsedTilesetInfo.AnimationData[previousTagID].push_back(newTag.GetInteger("tileid"));
}
} else
if (newTag.tag=="property"&&staircaseTag=="tile"){ if (newTag.tag=="property"&&staircaseTag=="tile"){
parsedTilesetInfo.StaircaseData[previousTagID]=newTag; parsedTilesetInfo.StaircaseData[previousTagID]=newTag;
staircaseTag=""; staircaseTag="";
@ -109,6 +128,10 @@ class TSXParser{
if (newTag.tag=="object"&&previousTag=="tile"){ if (newTag.tag=="object"&&previousTag=="tile"){
TileCollisionData data; TileCollisionData data;
data.collision=geom2d::rect<int>{{newTag.GetInteger("x"),newTag.GetInteger("y")},{newTag.GetInteger("width"),newTag.GetInteger("height")}}; data.collision=geom2d::rect<int>{{newTag.GetInteger("x"),newTag.GetInteger("y")},{newTag.GetInteger("width"),newTag.GetInteger("height")}};
if(parsedTilesetInfo.CollisionData.count(previousTagID)){
std::cout<<"WARNING! There was already collision data defined for tile "<<previousTagID<<"!"<<std::endl;
throw;
}
parsedTilesetInfo.CollisionData[previousTagID]=data; parsedTilesetInfo.CollisionData[previousTagID]=data;
} }
std::cout<<"\n"<<"=============\n"; std::cout<<"\n"<<"=============\n";

@ -4,11 +4,19 @@
#include "Crawler.h" #include "Crawler.h"
#include "utils.h" #include "utils.h"
typedef Attribute A;
INCLUDE_game INCLUDE_game
INCLUDE_BULLET_LIST INCLUDE_BULLET_LIST
void Monster::STRATEGY::TURRET(Monster&m,float fElapsedTime,int strategyNumber){ void Monster::STRATEGY::TURRET(Monster&m,float fElapsedTime,int strategyNumber){
m.attackCooldownTimer=std::max(0.f,m.attackCooldownTimer-fElapsedTime); m.attackCooldownTimer=std::max(0.f,m.attackCooldownTimer-fElapsedTime);
if(m.F(A::SHOOT_ANIMATION_TIME)>0){
m.F(A::SHOOT_ANIMATION_TIME)=std::max(0.f,m.F(A::SHOOT_ANIMATION_TIME)-fElapsedTime);
if(m.F(A::SHOOT_ANIMATION_TIME)==0){
m.PerformIdleAnimation();
}
}
if(m.queueShotTimer>0){ if(m.queueShotTimer>0){
m.queueShotTimer-=fElapsedTime; m.queueShotTimer-=fElapsedTime;
@ -23,6 +31,7 @@ void Monster::STRATEGY::TURRET(Monster&m,float fElapsedTime,int strategyNumber){
if(m.attackCooldownTimer==0){ if(m.attackCooldownTimer==0){
m.attackCooldownTimer=ConfigFloat("ShootingSpeed"); m.attackCooldownTimer=ConfigFloat("ShootingSpeed");
m.queueShotTimer=std::min(m.attackCooldownTimer-0.001,0.3); m.queueShotTimer=std::min(m.attackCooldownTimer-0.001,0.3);
m.F(A::SHOOT_ANIMATION_TIME)=ConfigIntArr("ShootAnimation",0)*ConfigFloatArr("ShootAnimation",1);
m.PerformShootAnimation(); m.PerformShootAnimation();
} }
} }

@ -2,7 +2,7 @@
#define VERSION_MAJOR 0 #define VERSION_MAJOR 0
#define VERSION_MINOR 2 #define VERSION_MINOR 2
#define VERSION_PATCH 0 #define VERSION_PATCH 0
#define VERSION_BUILD 1147 #define VERSION_BUILD 1372
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

@ -80,7 +80,7 @@ void Warrior::InitializeClassAbilities(){
#pragma region Warrior Ability 1 (Battlecry) #pragma region Warrior Ability 1 (Battlecry)
Warrior::ability1.action= Warrior::ability1.action=
[](Player*p,vf2d pos={}){ [](Player*p,vf2d pos={}){
game->AddEffect(std::make_unique<Effect>(p->GetPos(),"Warrior.Ability 1.EffectLifetime"_F,"BATTLECRY_EFFECT",p->upperLevel,"Warrior.Ability 1.Range"_F/350,"Warrior.Ability 1.EffectFadetime"_F)); game->AddEffect(std::make_unique<Effect>(p->GetPos(),"Warrior.Ability 1.EffectLifetime"_F,"battlecry_effect.png",p->upperLevel,"Warrior.Ability 1.Range"_F/350,"Warrior.Ability 1.EffectFadetime"_F));
p->AddBuff(BuffType::ATTACK_UP,"Warrior.Ability 1.AttackUpDuration"_F,"Warrior.Ability 1.AttackIncrease"_F); p->AddBuff(BuffType::ATTACK_UP,"Warrior.Ability 1.AttackUpDuration"_F,"Warrior.Ability 1.AttackIncrease"_F);
p->AddBuff(BuffType::DAMAGE_REDUCTION,"Warrior.Ability 1.DamageReductionDuration"_F,"Warrior.Ability 1.DamageReduction"_F); p->AddBuff(BuffType::DAMAGE_REDUCTION,"Warrior.Ability 1.DamageReductionDuration"_F,"Warrior.Ability 1.DamageReduction"_F);
for(Monster&m:MONSTER_LIST){ for(Monster&m:MONSTER_LIST){
@ -127,7 +127,7 @@ void Warrior::InitializeClassAbilities(){
p->UpdateAnimation("WARRIOR_SWINGSONICSWORD_S",WARRIOR); p->UpdateAnimation("WARRIOR_SWINGSONICSWORD_S",WARRIOR);
}break; }break;
} }
BULLET_LIST.push_back(std::make_unique<Bullet>(p->GetPos(),bulletVel,"Warrior.Ability 3.Radius"_F,p->GetAttack()*"Warrior.Ability 3.DamageMult"_F,"SONICSLASH",p->upperLevel,true,"Warrior.Ability 3.Lifetime"_F,true,true,WHITE,vf2d{"Warrior.Ability 3.Radius"_F/30,"Warrior.Ability 3.Radius"_F/30})); BULLET_LIST.push_back(std::make_unique<Bullet>(p->GetPos(),bulletVel,"Warrior.Ability 3.Radius"_F,p->GetAttack()*"Warrior.Ability 3.DamageMult"_F,"sonicslash.png",p->upperLevel,true,"Warrior.Ability 3.Lifetime"_F,true,true,WHITE,vf2d{"Warrior.Ability 3.Radius"_F/30,"Warrior.Ability 3.Radius"_F/30}));
game->SetupWorldShake("Warrior.Ability 3.ShakeTime"_F); game->SetupWorldShake("Warrior.Ability 3.ShakeTime"_F);
return true; return true;
}; };

@ -74,14 +74,13 @@ void Wizard::InitializeClassAbilities(){
#pragma region Wizard Right-click Ability (Teleport) #pragma region Wizard Right-click Ability (Teleport)
Wizard::rightClickAbility.action= Wizard::rightClickAbility.action=
[](Player*p,vf2d pos={}){ [](Player*p,vf2d pos={}){
if(p->GetState()==State::CASTING)return false;
float pointMouseDirection=atan2(game->GetWorldMousePos().y-p->GetPos().y,game->GetWorldMousePos().x-p->GetPos().x); float pointMouseDirection=atan2(game->GetWorldMousePos().y-p->GetPos().y,game->GetWorldMousePos().x-p->GetPos().x);
vf2d pointTowardsMouse={cos(pointMouseDirection),sin(pointMouseDirection)}; vf2d pointTowardsMouse={cos(pointMouseDirection),sin(pointMouseDirection)};
float dist=std::clamp(geom2d::line<float>{p->GetPos(),game->GetWorldMousePos()}.length(),0.f,"Wizard.Right Click Ability.TeleportRange"_F/100*24); float dist=std::clamp(geom2d::line<float>{p->GetPos(),game->GetWorldMousePos()}.length(),0.f,"Wizard.Right Click Ability.TeleportRange"_F/100*24);
if(dist<"Wizard.Right Click Ability.TilesMin"_I*12)return false; if(dist<"Wizard.Right Click Ability.TilesMin"_I*12)return false;
vf2d teleportPoint=p->GetPos()+pointTowardsMouse*dist; vf2d teleportPoint=p->GetPos()+pointTowardsMouse*dist;
while(dist>0&&game->HasTileCollision(game->GetCurrentLevel(),teleportPoint)&&p->CanPathfindTo(p->GetPos(),teleportPoint,"Wizard.Right Click Ability.TilesMax"_I)){ while(dist>0&&game->HasTileCollision(game->GetCurrentLevel(),teleportPoint)&&p->CanPathfindTo(p->GetPos(),teleportPoint,"Wizard.Right Click Ability.TilesMax"_I)){
dist-=24; dist-=4;
teleportPoint=p->GetPos()+pointTowardsMouse*dist; teleportPoint=p->GetPos()+pointTowardsMouse*dist;
} }
if(dist>0&&p->CanPathfindTo(p->GetPos(),teleportPoint,"Wizard.Right Click Ability.TilesMax"_I)){ if(dist>0&&p->CanPathfindTo(p->GetPos(),teleportPoint,"Wizard.Right Click Ability.TilesMax"_I)){
@ -91,7 +90,7 @@ void Wizard::InitializeClassAbilities(){
p->teleportStartPosition=p->GetPos(); p->teleportStartPosition=p->GetPos();
p->iframe_time="Wizard.Right Click Ability.IframeTime"_F; p->iframe_time="Wizard.Right Click Ability.IframeTime"_F;
for(int i=0;i<"Wizard.Right Click Ability.ParticleCount"_I;i++){ for(int i=0;i<"Wizard.Right Click Ability.ParticleCount"_I;i++){
game->AddEffect(std::make_unique<Effect>(p->GetPos()+vf2d{(util::random("Wizard.Right Click Ability.ParticleRange"_F/100*2)-"Wizard.Right Click Ability.ParticleRange"_F/100)*12,(util::random("Wizard.Right Click Ability.ParticleRange"_F/100*2)-"Wizard.Right Click Ability.ParticleRange"_F/100)*12},util::random("Wizard.Right Click Ability.ParticleLifetimeMax"_F)+"Wizard.Right Click Ability.ParticleLifetimeMin"_F,"DOT_PARTICLE",p->upperLevel,"Wizard.Right Click Ability.ParticleSize"_F,"Wizard.Right Click Ability.ParticleFadetime"_F,vf2d{util::random("Wizard.Right Click Ability.ParticleSpeedMax"_F*2)+"Wizard.Right Click Ability.ParticleSpeedMin"_F,util::random("Wizard.Right Click Ability.ParticleSpeedMax"_F*2)+"Wizard.Right Click Ability.ParticleSpeedMin"_F},"Wizard.Right Click Ability.ParticleColor"_Pixel)); game->AddEffect(std::make_unique<Effect>(p->GetPos()+vf2d{(util::random("Wizard.Right Click Ability.ParticleRange"_F/100*2)-"Wizard.Right Click Ability.ParticleRange"_F/100)*12,(util::random("Wizard.Right Click Ability.ParticleRange"_F/100*2)-"Wizard.Right Click Ability.ParticleRange"_F/100)*12},util::random("Wizard.Right Click Ability.ParticleLifetimeMax"_F)+"Wizard.Right Click Ability.ParticleLifetimeMin"_F,"circle.png",p->upperLevel,"Wizard.Right Click Ability.ParticleSize"_F,"Wizard.Right Click Ability.ParticleFadetime"_F,vf2d{util::random("Wizard.Right Click Ability.ParticleSpeedMax"_F*2)+"Wizard.Right Click Ability.ParticleSpeedMin"_F,util::random("Wizard.Right Click Ability.ParticleSpeedMax"_F*2)+"Wizard.Right Click Ability.ParticleSpeedMin"_F},"Wizard.Right Click Ability.ParticleColor"_Pixel));
} }
return true; return true;
} else { } else {
@ -120,7 +119,7 @@ void Wizard::InitializeClassAbilities(){
Wizard::ability3.action= Wizard::ability3.action=
[](Player*p,vf2d pos={}){ [](Player*p,vf2d pos={}){
p->CastSpell(Wizard::ability3); p->CastSpell(Wizard::ability3);
game->AddEffect(std::make_unique<Meteor>(pos,3,"METEOR",p->OnUpperLevel(),vf2d{"Wizard.Ability 3.MeteorRadius"_F/100/4,"Wizard.Ability 3.MeteorRadius"_F/100/4},"Wizard.Ability 3.MeteorFadeoutTime"_F)); game->AddEffect(std::make_unique<Meteor>(pos,3,"meteor.png",p->OnUpperLevel(),vf2d{"Wizard.Ability 3.MeteorRadius"_F/100/4,"Wizard.Ability 3.MeteorRadius"_F/100/4},"Wizard.Ability 3.MeteorFadeoutTime"_F));
return true; return true;
}; };
#pragma endregion #pragma endregion

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

File diff suppressed because it is too large Load Diff

@ -43,6 +43,8 @@ MonsterStrategy
WaitTime = 3 WaitTime = 3
# How far the monster will travel before reassessing for a new path. # How far the monster will travel before reassessing for a new path.
MaxDistance = 999999 MaxDistance = 999999
# 1 of X chance to stop after bumping into something.
BumpStopChance = 5
} }
1 1
{ {
@ -63,7 +65,7 @@ MonsterStrategy
# How far away the monster starts shooting from # How far away the monster starts shooting from
Range = 800 Range = 800
# How often the enemy shoots. # How often the enemy shoots.
ShootingSpeed = 0.6 ShootingSpeed = 2
BulletSpeed = 450 BulletSpeed = 450
BulletSize = 30 BulletSize = 30
BulletColor = 0, 255, 0, 255 BulletColor = 0, 255, 0, 255
@ -72,13 +74,17 @@ MonsterStrategy
{ {
# The Slime King Boss script. # The Slime King Boss script.
Name = Slime King Name = Slime King
# Which phase to start on. Should be 1 most of the time.
StartPhase = 1
# How much time a jump will be pre-telegraphed. # How much time a jump will be pre-telegraphed.
JumpWarningIndicatorTime = 1.0 JumpWarningIndicatorTime = 1.0
# Distance to jump up into the sky. A higher value causes it to launch up and down seemingly faster. # Distance to jump up into the sky. A higher value causes it to launch up and down seemingly faster.
JumpHeight = 2400 JumpHeight = 2400
ProjectileDamage = 10 ProjectileDamage = 10
JumpAttackDamage = 20 JumpAttackDamage = 20
JumpMoveSpd = 95 JumpMoveSpd = 75
# How far the player gets knocked back if hit.
JumpKnockbackFactor = 250
BulletSpd = 250 BulletSpd = 250

@ -12,6 +12,7 @@ Monsters
Size = 80 Size = 80
Strategy = Run Towards Strategy = Run Towards
BumpStopChance = 2
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
@ -138,6 +139,7 @@ Monsters
Size = 800 Size = 800
Strategy = Slime King Strategy = Slime King
StartPhase = 2
#Size of each animation frame #Size of each animation frame
SheetFrameSize = 24,24 SheetFrameSize = 24,24
@ -149,6 +151,6 @@ Monsters
DeathAnimation = 10, 0.1, OneShot DeathAnimation = 10, 0.1, OneShot
#Additional custom animations go down below. Start with ANIMATION[0] #Additional custom animations go down below. Start with ANIMATION[0]
#ANIMATION[0] = MY_NEW_ANIMATION ANIMATION[0] = monsters/Slime King - Cast.png
} }
} }

@ -7,14 +7,19 @@ Ranger
DamageMult = 1 DamageMult = 1
Radius = 100 Radius = 100
Cooldown = 0.6 Cooldown = 0.6
# Whether or not this ability cancels casts.
CancelCast = 0
ArrowSpd = 250 ArrowSpd = 250
} }
Right Click Ability Right Click Ability
{ {
Name = Retreat Name = Retreat
Cooldown = 7 Cooldown = 7
Mana Cost = 0 Mana Cost = 0
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 0, 0, 64, 255 Cooldown Bar Color 1 = 0, 0, 64, 255
@ -34,6 +39,8 @@ Ranger
Name = Rapid Fire Name = Rapid Fire
Cooldown = 12 Cooldown = 12
Mana Cost = 35 Mana Cost = 35
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 64, 0, 0, 255 Cooldown Bar Color 1 = 64, 0, 0, 255
@ -62,6 +69,8 @@ Ranger
Name = Charged Shot Name = Charged Shot
Cooldown = 15 Cooldown = 15
Mana Cost = 40 Mana Cost = 40
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 64, 0, 0, 255 Cooldown Bar Color 1 = 64, 0, 0, 255
@ -88,6 +97,8 @@ Ranger
Name = Multishot Name = Multishot
Cooldown = 25 Cooldown = 25
Mana Cost = 50 Mana Cost = 50
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 64, 0, 0, 255 Cooldown Bar Color 1 = 64, 0, 0, 255

@ -7,6 +7,8 @@ Thief
Name = ??? Name = ???
Cooldown = 8 Cooldown = 8
Mana Cost = 5 Mana Cost = 5
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 0, 0, 64, 255 Cooldown Bar Color 1 = 0, 0, 64, 255
@ -21,6 +23,8 @@ Thief
Name = ??? Name = ???
Cooldown = 6 Cooldown = 6
Mana Cost = 30 Mana Cost = 30
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 64, 0, 0, 255 Cooldown Bar Color 1 = 64, 0, 0, 255
@ -35,6 +39,8 @@ Thief
Name = ??? Name = ???
Cooldown = 6 Cooldown = 6
Mana Cost = 25 Mana Cost = 25
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 64, 0, 0, 255 Cooldown Bar Color 1 = 64, 0, 0, 255
@ -49,6 +55,8 @@ Thief
Name = ??? Name = ???
Cooldown = 40 Cooldown = 40
Mana Cost = 75 Mana Cost = 75
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 64, 0, 0, 255 Cooldown Bar Color 1 = 64, 0, 0, 255

@ -7,6 +7,8 @@ Trapper
Name = ??? Name = ???
Cooldown = 8 Cooldown = 8
Mana Cost = 5 Mana Cost = 5
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 0, 0, 64, 255 Cooldown Bar Color 1 = 0, 0, 64, 255
@ -21,6 +23,8 @@ Trapper
Name = ??? Name = ???
Cooldown = 6 Cooldown = 6
Mana Cost = 30 Mana Cost = 30
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 64, 0, 0, 255 Cooldown Bar Color 1 = 64, 0, 0, 255
@ -35,6 +39,8 @@ Trapper
Name = ??? Name = ???
Cooldown = 6 Cooldown = 6
Mana Cost = 25 Mana Cost = 25
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 64, 0, 0, 255 Cooldown Bar Color 1 = 64, 0, 0, 255
@ -49,6 +55,8 @@ Trapper
Name = ??? Name = ???
Cooldown = 40 Cooldown = 40
Mana Cost = 75 Mana Cost = 75
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 64, 0, 0, 255 Cooldown Bar Color 1 = 64, 0, 0, 255

@ -7,6 +7,8 @@ Warrior
DamageMult = 1 DamageMult = 1
Range = 150 Range = 150
Cooldown = 0.35 Cooldown = 0.35
# Whether or not this ability cancels casts.
CancelCast = 0
SwordSwingTime = 0.2 SwordSwingTime = 0.2
} }
@ -15,6 +17,8 @@ Warrior
Name = Block Name = Block
Cooldown = 15 Cooldown = 15
Mana Cost = 0 Mana Cost = 0
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 0, 0, 64, 255 Cooldown Bar Color 1 = 0, 0, 64, 255
@ -37,6 +41,8 @@ Warrior
Name = Battlecry Name = Battlecry
Cooldown = 12 Cooldown = 12
Mana Cost = 40 Mana Cost = 40
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 64, 0, 0, 255 Cooldown Bar Color 1 = 64, 0, 0, 255
@ -79,6 +85,8 @@ Warrior
Name = Ground Slam Name = Ground Slam
Cooldown = 15 Cooldown = 15
Mana Cost = 50 Mana Cost = 50
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 64, 0, 0, 255 Cooldown Bar Color 1 = 64, 0, 0, 255
@ -107,6 +115,8 @@ Warrior
Name = Sonic Slash Name = Sonic Slash
Cooldown = 40 Cooldown = 40
Mana Cost = 60 Mana Cost = 60
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 64, 0, 0, 255 Cooldown Bar Color 1 = 64, 0, 0, 255

@ -7,6 +7,8 @@ Witch
Name = ??? Name = ???
Cooldown = 8 Cooldown = 8
Mana Cost = 5 Mana Cost = 5
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 0, 0, 64, 255 Cooldown Bar Color 1 = 0, 0, 64, 255
@ -21,6 +23,8 @@ Witch
Name = ??? Name = ???
Cooldown = 6 Cooldown = 6
Mana Cost = 30 Mana Cost = 30
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 64, 0, 0, 255 Cooldown Bar Color 1 = 64, 0, 0, 255
@ -35,6 +39,8 @@ Witch
Name = ??? Name = ???
Cooldown = 6 Cooldown = 6
Mana Cost = 25 Mana Cost = 25
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 64, 0, 0, 255 Cooldown Bar Color 1 = 64, 0, 0, 255
@ -49,6 +55,8 @@ Witch
Name = ??? Name = ???
Cooldown = 40 Cooldown = 40
Mana Cost = 75 Mana Cost = 75
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 64, 0, 0, 255 Cooldown Bar Color 1 = 64, 0, 0, 255

@ -8,6 +8,8 @@ Wizard
Radius = 100 Radius = 100
Speed = 200 Speed = 200
Cooldown = 0.85 Cooldown = 0.85
# Whether or not this ability cancels casts.
CancelCast = 0
# When bullet makes contact, how fast the bullet will fade out. # When bullet makes contact, how fast the bullet will fade out.
BulletHitFadeoutTime = 0.2 BulletHitFadeoutTime = 0.2
@ -28,6 +30,8 @@ Wizard
Name = Teleport Name = Teleport
Cooldown = 8 Cooldown = 8
Mana Cost = 5 Mana Cost = 5
# Whether or not this ability cancels casts.
CancelCast = 1
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 0, 0, 64, 255 Cooldown Bar Color 1 = 0, 0, 64, 255
@ -64,6 +68,8 @@ Wizard
Name = Firebolt Name = Firebolt
Cooldown = 6 Cooldown = 6
Mana Cost = 30 Mana Cost = 30
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 64, 0, 0, 255 Cooldown Bar Color 1 = 64, 0, 0, 255
@ -126,6 +132,8 @@ Wizard
Name = Lightning Bolt Name = Lightning Bolt
Cooldown = 6 Cooldown = 6
Mana Cost = 25 Mana Cost = 25
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 64, 0, 0, 255 Cooldown Bar Color 1 = 64, 0, 0, 255
@ -178,6 +186,8 @@ Wizard
Name = Meteor Name = Meteor
Cooldown = 40 Cooldown = 40
Mana Cost = 75 Mana Cost = 75
# Whether or not this ability cancels casts.
CancelCast = 0
#RGB Values. Color 1 is the left side of the bar, Color 2 is the right side. #RGB Values. Color 1 is the left side of the bar, Color 2 is the right side.
Cooldown Bar Color 1 = 64, 0, 0, 255 Cooldown Bar Color 1 = 64, 0, 0, 255

@ -34,4 +34,19 @@ debug_access_options = 0
debug_player_info = 0 debug_player_info = 0
# Shows collision boxes of tiles. # Shows collision boxes of tiles.
debug_collision_boxes = 0 debug_collision_boxes = 0
# Shows pathfinding debugging
debug_pathfinding = 0
# ms precision of animation tile caching.
animation_tile_precision = 50
# frequency of water reflection moving update.
water_reflection_update_time = 0.5
# amount of time step of water reflection moving update.
water_reflection_time_step = 0.6
# the amount of scaling done to the water reflection.
water_reflection_scale_factor = 0.05

@ -2,32 +2,38 @@ GFX_Prefix = assets/
Images Images
{ {
GFX_Warrior_Sheet = nico-warrior.png GFX_Arrow = arrow.png
GFX_Circle = circle.png
GFX_Effect_GroundSlam_Back = ground-slam-attack-back.png
GFX_Effect_GroundSlam_Front = ground-slam-attack-front.png
GFX_Heart = heart.png
GFX_BLOCK_BUBBLE = block.png
GFX_Ranger_Sheet = nico-ranger.png
GFX_Wizard_Sheet = nico-wizard.png
GFX_Battlecry_Effect = battlecry_effect.png GFX_Battlecry_Effect = battlecry_effect.png
GFX_Mana = mana.png GFX_BLOCK_BUBBLE = block.png
GFX_SonicSlash = sonicslash.png
GFX_BulletCircle = circle.png GFX_BulletCircle = circle.png
GFX_BulletCircleOutline = circle_outline.png GFX_BulletCircleOutline = circle_outline.png
GFX_ChainLightning = chain_lightning.png
GFX_ChargedArrow = charged_shot_arrow.png
GFX_Circle = circle.png
GFX_Effect_GroundSlam_Back = ground-slam-attack-back.png
GFX_Effect_GroundSlam_Front = ground-slam-attack-front.png
GFX_EnergyBolt = energy_bolt.png GFX_EnergyBolt = energy_bolt.png
GFX_EnergyParticle = energy_particle.png GFX_EnergyParticle = energy_particle.png
GFX_Splash_Effect = splash_effect.png GFX_FireRing0 = fire_ring0.png
GFX_FireRing1 = fire_ring1.png
GFX_FireRing2 = fire_ring2.png
GFX_FireRing3 = fire_ring3.png
GFX_FireRing4 = fire_ring4.png
GFX_Heart = heart.png
GFX_Laser = laser.png
GFX_LightningBolt = lightning_bolt.png GFX_LightningBolt = lightning_bolt.png
GFX_LightningBoltParticle1 = lightning_bolt_part1.png GFX_LightningBoltParticle1 = lightning_bolt_part1.png
GFX_LightningBoltParticle2 = lightning_bolt_part2.png GFX_LightningBoltParticle2 = lightning_bolt_part2.png
GFX_LightningBoltParticle3 = lightning_bolt_part3.png GFX_LightningBoltParticle3 = lightning_bolt_part3.png
GFX_LightningBoltParticle4 = lightning_bolt_part4.png GFX_LightningBoltParticle4 = lightning_bolt_part4.png
GFX_ChainLightning = chain_lightning.png
GFX_LightningSplash = lightning_splash_effect.png GFX_LightningSplash = lightning_splash_effect.png
GFX_Mana = mana.png
GFX_Meteor = meteor.png GFX_Meteor = meteor.png
GFX_Arrow = arrow.png
GFX_Laser = laser.png
GFX_ChargedArrow = charged_shot_arrow.png
GFX_RangeIndicator = range_indicator.png GFX_RangeIndicator = range_indicator.png
GFX_Ranger_Sheet = nico-ranger.png
GFX_SonicSlash = sonicslash.png
GFX_Splash_Effect = splash_effect.png
GFX_Warrior_Sheet = nico-warrior.png
GFX_Wizard_Sheet = nico-wizard.png
GFX_SlimeKing_Cast = monsters/Slime King - Cast.png
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 706 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 683 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 681 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 B

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.10.1" name="24x24_Waterfall" tilewidth="24" tileheight="24" tilecount="80" columns="8">
<image source="24x24_Waterfall.png" width="192" height="240"/>
<tile id="0">
<animation>
<frame tileid="0" duration="100"/>
<frame tileid="1" duration="100"/>
<frame tileid="2" duration="100"/>
<frame tileid="3" duration="100"/>
<frame tileid="4" duration="100"/>
<frame tileid="5" duration="100"/>
<frame tileid="6" duration="100"/>
<frame tileid="7" duration="100"/>
</animation>
</tile>
<tile id="8">
<animation>
<frame tileid="8" duration="100"/>
<frame tileid="9" duration="100"/>
<frame tileid="10" duration="100"/>
<frame tileid="11" duration="100"/>
<frame tileid="12" duration="100"/>
<frame tileid="13" duration="100"/>
<frame tileid="14" duration="100"/>
<frame tileid="15" duration="100"/>
</animation>
</tile>
<tile id="16">
<animation>
<frame tileid="16" duration="100"/>
<frame tileid="17" duration="100"/>
<frame tileid="18" duration="100"/>
<frame tileid="19" duration="100"/>
<frame tileid="20" duration="100"/>
<frame tileid="21" duration="100"/>
<frame tileid="22" duration="100"/>
<frame tileid="23" duration="100"/>
</animation>
</tile>
<tile id="24">
<animation>
<frame tileid="24" duration="100"/>
<frame tileid="25" duration="100"/>
<frame tileid="26" duration="100"/>
<frame tileid="27" duration="100"/>
<frame tileid="28" duration="100"/>
<frame tileid="29" duration="100"/>
<frame tileid="30" duration="100"/>
<frame tileid="31" duration="100"/>
</animation>
</tile>
<tile id="32">
<animation>
<frame tileid="32" duration="100"/>
<frame tileid="33" duration="100"/>
<frame tileid="34" duration="100"/>
<frame tileid="35" duration="100"/>
<frame tileid="36" duration="100"/>
<frame tileid="37" duration="100"/>
<frame tileid="38" duration="100"/>
<frame tileid="39" duration="100"/>
</animation>
</tile>
<tile id="40">
<animation>
<frame tileid="40" duration="100"/>
<frame tileid="41" duration="100"/>
<frame tileid="42" duration="100"/>
<frame tileid="43" duration="100"/>
<frame tileid="44" duration="100"/>
<frame tileid="45" duration="100"/>
<frame tileid="46" duration="100"/>
<frame tileid="47" duration="100"/>
</animation>
</tile>
<tile id="48">
<animation>
<frame tileid="48" duration="100"/>
<frame tileid="49" duration="100"/>
<frame tileid="50" duration="100"/>
<frame tileid="51" duration="100"/>
<frame tileid="52" duration="100"/>
<frame tileid="53" duration="100"/>
<frame tileid="54" duration="100"/>
<frame tileid="55" duration="100"/>
</animation>
</tile>
<tile id="56">
<animation>
<frame tileid="56" duration="100"/>
<frame tileid="57" duration="100"/>
<frame tileid="58" duration="100"/>
<frame tileid="59" duration="100"/>
<frame tileid="60" duration="100"/>
<frame tileid="61" duration="100"/>
<frame tileid="62" duration="100"/>
<frame tileid="63" duration="100"/>
</animation>
</tile>
<tile id="64">
<animation>
<frame tileid="64" duration="100"/>
<frame tileid="65" duration="100"/>
<frame tileid="66" duration="100"/>
<frame tileid="67" duration="100"/>
<frame tileid="68" duration="100"/>
<frame tileid="69" duration="100"/>
<frame tileid="70" duration="100"/>
<frame tileid="71" duration="100"/>
</animation>
</tile>
<tile id="72">
<animation>
<frame tileid="72" duration="100"/>
<frame tileid="73" duration="100"/>
<frame tileid="74" duration="100"/>
<frame tileid="75" duration="100"/>
<frame tileid="76" duration="100"/>
<frame tileid="77" duration="100"/>
<frame tileid="78" duration="100"/>
<frame tileid="79" duration="100"/>
</animation>
</tile>
</tileset>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

@ -35,7 +35,7 @@ var Module = {
})(), })(),
}; };
</script> </script>
<script async type="text/javascript" src="pge.js"></script> <script async type="text/javascript" src="_REPLACEME_"></script>
<script type="text/javascript"> <script type="text/javascript">
Module.canvas.addEventListener("resize", (e) => { Module.canvas.addEventListener("resize", (e) => {

@ -324,7 +324,7 @@ namespace olc
olc::vf2d TransformedView::WorldToScreen(const olc::vf2d& vWorldPos) const olc::vf2d TransformedView::WorldToScreen(const olc::vf2d& vWorldPos) const
{ {
olc::vf2d vFloat = ((vd2d(vWorldPos) - vd2d(m_vWorldOffset)) * vd2d(m_vWorldScale)); olc::vf2d vFloat = ((vf2d(vWorldPos) - vf2d(m_vWorldOffset)) * vf2d(m_vWorldScale));
//vFloat = { std::floor(vFloat.x + 0.5f), std::floor(vFloat.y + 0.5f) }; //vFloat = { std::floor(vFloat.x + 0.5f), std::floor(vFloat.y + 0.5f) };
return vFloat; return vFloat;
} }

@ -2891,8 +2891,8 @@ namespace olc
di.decal = decal; di.decal = decal;
di.tint = { tint, tint, tint, tint }; di.tint = { tint, tint, tint, tint };
di.pos = { { vScreenSpacePos.x, vScreenSpacePos.y }, { vScreenSpacePos.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpacePos.y } }; di.pos = { { vScreenSpacePos.x, vScreenSpacePos.y }, { vScreenSpacePos.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpaceDim.y }, { vScreenSpaceDim.x, vScreenSpacePos.y } };
olc::vf2d uvtl = (source_pos) * decal->vUVScale; olc::vf2d uvtl = (source_pos + olc::vf2d(0.0001f, 0.0001f)) * decal->vUVScale;
olc::vf2d uvbr = uvtl + ((source_size) * decal->vUVScale); olc::vf2d uvbr = uvtl + ((source_size - olc::vf2d(0.0001f, 0.0001f)) * decal->vUVScale);
di.uv = { { uvtl.x, uvtl.y }, { uvtl.x, uvbr.y }, { uvbr.x, uvbr.y }, { uvbr.x, uvtl.y } }; di.uv = { { uvtl.x, uvtl.y }, { uvtl.x, uvbr.y }, { uvbr.x, uvbr.y }, { uvbr.x, uvtl.y } };
di.w = { 1,1,1,1 }; di.w = { 1,1,1,1 };
di.mode = nDecalMode; di.mode = nDecalMode;

@ -130,11 +130,26 @@ namespace olc::utils
return m_vContent; return m_vContent;
} }
inline std::unordered_map<std::string,size_t> GetKeys() const{
return m_mapObjects;
}
// Checks if a property exists - useful to avoid creating properties // Checks if a property exists - useful to avoid creating properties
// via reading them, though non-essential // via reading them, though non-essential
inline bool HasProperty(const std::string& sName) const inline bool HasProperty(const std::string& sName)
{ {
return m_mapObjects.count(sName) > 0; size_t x = sName.find_first_of('.');
if (x != std::string::npos)
{
std::string sProperty = sName.substr(0, x);
if(HasProperty(sProperty)){
return GetProperty(sName.substr(0, x)).HasProperty(sName.substr(x + 1, sName.size()));
}else{
return false;
}
}else{
return m_mapObjects.count(sName) > 0;
}
} }
// Access a datafile via a convenient name - "root.node.something.property" // Access a datafile via a convenient name - "root.node.something.property"

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

@ -1,3 +1,4 @@
//#define OLC_PGE_HEADLESS
#define OLC_PGE_APPLICATION #define OLC_PGE_APPLICATION
#include "olcPixelGameEngine.h" #include "olcPixelGameEngine.h"
#define OLC_PGEX_TRANSFORMEDVIEW #define OLC_PGEX_TRANSFORMEDVIEW

@ -0,0 +1,75 @@
<!doctype html>
<html lang="en-us">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Emscripten-Generated Code</title>
<style>
html,body { width: 100%; height: 100%; }
body { font-family: arial; margin: 0; padding: 0; background: #000; }
.emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
div.emscripten_border { border: none; }
/* the canvas *must not* have any border or padding, or mouse coords will be wrong */
canvas.emscripten { border: 0px none; background-color: black; }
</style>
</head>
<body>
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas>
<script type='text/javascript'>
var Module = {
preRun: [],
postRun: [],
canvas: (function() {
var canvas = document.getElementById('canvas');
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
// application robust, you may want to override this behavior before shipping!
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
return canvas;
})(),
};
</script>
<script async type="text/javascript" src="pge.js"></script>
<script type="text/javascript">
Module.canvas.addEventListener("resize", (e) => {
var viewWidth = e.detail.width;
var viewHeight = e.detail.width / Module._olc_WindowAspectRatio;
if(viewHeight > e.detail.height)
{
viewHeight = e.detail.height;
viewWidth = e.detail.height * Module._olc_WindowAspectRatio;
}
// update dom attributes
Module.canvas.setAttribute("width", viewWidth);
Module.canvas.setAttribute("height", viewHeight);
var top = (e.detail.height - viewHeight) / 2;
var left = (e.detail.width - viewWidth) / 2;
// update styles
Module.canvas.style.position = "fixed";
Module.canvas.style.top = top.toString() + "px";
Module.canvas.style.left = left.toString() + "px";
Module.canvas.style.width = "";
Module.canvas.style.height = "";
// trigger PGE update
Module._olc_PGE_UpdateWindowSize(viewWidth, viewHeight);
// ensure canvas has focus
Module.canvas.focus();
e.preventDefault();
});
</script>
</body>
</html>

@ -14,7 +14,24 @@ public:
} }
return map[key]; return map[key];
} }
size_t count(T key){
return map.count(key);
}
void SetInitialized(){ void SetInitialized(){
initialized=true; initialized=true;
} }
size_t size(){
return map.size();
}
//Clears the entire map and unlocks the map so items can be added to it again.
void Reset(){
initialized=false;
map.clear();
}
auto begin()const{
return map.begin();
}
auto end()const{
return map.end();
}
}; };

@ -1,9 +1,10 @@
export AUTO_UPDATE=false export AUTO_UPDATE=true
source utils/define.sh source utils/define.sh
define PROJECT_NAME "Crawler" define PROJECT_NAME "Crawler"
define CUSTOM_PARAMS "-std=c++20 -lX11 -lGL -lpthread -lpng -lstdc++fs -I/usr/include/lua5.3" define CUSTOM_PARAMS "-std=c++20 -lX11 -lpthread -lpng -lstdc++fs -I/usr/include/lua5.3"
define EMSCRIPTEN_CUSTOM_PARAMS "-s MAXIMUM_MEMORY=4GB"
define LANGUAGE "C++" define LANGUAGE "C++"
source utils/main.sh source utils/main.sh

@ -8,6 +8,10 @@ vf2d util::pointTo(vf2d posFrom,vf2d posTo){
return geom2d::line(posFrom,posTo).vector().norm(); return geom2d::line(posFrom,posTo).vector().norm();
} }
float util::angleTo(vf2d posFrom,vf2d posTo){
return geom2d::line<float>(posFrom,posTo).vector().polar().y;
}
float util::degToRad(float deg){ float util::degToRad(float deg){
return deg*(PI/180); return deg*(PI/180);
} }

@ -6,6 +6,8 @@ namespace util{
float random(float range); float random(float range);
//Returns a normalized vector pointing from posFrom towards posTo. //Returns a normalized vector pointing from posFrom towards posTo.
vf2d pointTo(vf2d posFrom,vf2d posTo); vf2d pointTo(vf2d posFrom,vf2d posTo);
//Returns the angle (in radians) pointing from posFrom towards posTo.
float angleTo(vf2d posFrom,vf2d posTo);
float degToRad(float deg); float degToRad(float deg);
float radToDeg(float rad); float radToDeg(float rad);
float lerp(float n1,float n2,double t); float lerp(float n1,float n2,double t);

Binary file not shown.
Loading…
Cancel
Save