From 8bdc26fe27725ed359a66f78caec1c4ab95fa949 Mon Sep 17 00:00:00 2001 From: Ben Frankel Date: Sat, 27 Jul 2024 22:48:05 -0700 Subject: [PATCH] Set up musical notes and rests --- assets/config/actor.ron | 66 ++------ assets/config/card.ron | 154 +++++++++++++++--- assets/config/projectile.ron | 41 ++++- .../card/background/backgrounds.aseprite | Bin 789 -> 957 bytes .../card/icon/{major_chord.png => chord.png} | Bin .../icon/{cluster_chord.png => cluster.png} | Bin assets/image/card/icon/double_beat.png | Bin 158 -> 0 bytes assets/image/card/icon/eighth_rest.png | Bin 0 -> 125 bytes assets/image/card/icon/half_note.png | Bin 0 -> 121 bytes assets/image/card/icon/half_rest.png | Bin 0 -> 117 bytes assets/image/card/icon/icons.aseprite | Bin 2416 -> 2996 bytes assets/image/card/icon/quarter_note.png | Bin 0 -> 123 bytes .../card/icon/{rest.png => quarter_rest.png} | Bin assets/image/card/icon/whole_note.png | Bin 0 -> 118 bytes assets/image/card/icon/whole_rest.png | Bin 0 -> 119 bytes assets/image/projectile/eighth_note.png | Bin 0 -> 127 bytes assets/image/projectile/half_note.png | Bin 0 -> 113 bytes assets/image/projectile/projectiles.aseprite | Bin 0 -> 476 bytes assets/image/projectile/quarter_note.aseprite | Bin 261 -> 0 bytes assets/image/projectile/whole_note.png | Bin 0 -> 117 bytes src/game/actor/health.rs | 12 +- src/game/card.rs | 7 +- src/game/card/action.rs | 51 +++--- src/game/card/attack.rs | 18 +- src/game/card/deck.rs | 4 +- 25 files changed, 229 insertions(+), 124 deletions(-) rename assets/image/card/icon/{major_chord.png => chord.png} (100%) rename assets/image/card/icon/{cluster_chord.png => cluster.png} (100%) delete mode 100644 assets/image/card/icon/double_beat.png create mode 100644 assets/image/card/icon/eighth_rest.png create mode 100644 assets/image/card/icon/half_note.png create mode 100644 assets/image/card/icon/half_rest.png create mode 100644 assets/image/card/icon/quarter_note.png rename assets/image/card/icon/{rest.png => quarter_rest.png} (100%) create mode 100644 assets/image/card/icon/whole_note.png create mode 100644 assets/image/card/icon/whole_rest.png create mode 100644 assets/image/projectile/eighth_note.png create mode 100644 assets/image/projectile/half_note.png create mode 100644 assets/image/projectile/projectiles.aseprite delete mode 100644 assets/image/projectile/quarter_note.aseprite create mode 100644 assets/image/projectile/whole_note.png diff --git a/assets/config/actor.ron b/assets/config/actor.ron index c6b38c9..703f90b 100644 --- a/assets/config/actor.ron +++ b/assets/config/actor.ron @@ -16,22 +16,10 @@ ], ), - movement: Movement( - speed: 80.0, - ), - // TODO: Does this still work or does it get overwritten? - attack: Attack( - power: 2, - force: 4, - color: Srgba(Srgba(red: 0.855, green: 0.576, blue: 0.800, alpha: 1.000)), - ), - health: Health( - max: 100, - current: 100, - ), - deck: Deck( - cards: ["step", "pair"], - ), + movement: Movement(speed: 80.0), + attack: Attack(color: Srgba(Srgba(red: 0.855, green: 0.576, blue: 0.800, alpha: 1.000))), + health: Health(max: 100, current: 100), + deck: Deck(cards: ["step", "pair"]), ), }, @@ -52,15 +40,13 @@ ], ), - attack: Attack( - color: Srgba(Srgba(red: 0.929, green: 0.557, blue: 0.576, alpha: 1.000)), - ), - deck: Deck( - cards: ["step", "step", "pair"], - ), + attack: Attack(color: Srgba(Srgba(red: 0.929, green: 0.557, blue: 0.576, alpha: 1.000))), + deck: Deck(cards: ["step", "step", "pair"]), ), - "pink": Actor( + // TODO: If character select screen is implemented, uncomment this and include logic to + // avoid spawning enemies that look like the player (aka same key). + /*"pink": Actor( name: "Linus", texture: "image/actor/pink.png", @@ -76,13 +62,9 @@ ], ), - attack: Attack( - color: Srgba(Srgba(red: 0.855, green: 0.576, blue: 0.800, alpha: 1.000)), - ), - deck: Deck( - cards: ["step", "pair", "pair"], - ), - ), + attack: Attack(color: Srgba(Srgba(red: 0.855, green: 0.576, blue: 0.800, alpha: 1.000))), + deck: Deck(cards: ["step", "pair", "pair"]), + ),*/ "green": Actor( name: "Jade", @@ -100,12 +82,8 @@ ], ), - attack: Attack( - color: Srgba(Srgba(red: 0.557, green: 0.722, blue: 0.518, alpha: 1.000)), - ), - deck: Deck( - cards: ["pair"], - ), + attack: Attack(color: Srgba(Srgba(red: 0.557, green: 0.722, blue: 0.518, alpha: 1.000))), + deck: Deck(cards: ["pair"]), ), "blue": Actor( @@ -124,12 +102,8 @@ ], ), - attack: Attack( - color: Srgba(Srgba(red: 0.424, green: 0.694, blue: 0.725, alpha: 1.000)), - ), - deck: Deck( - cards: ["step", "pair"], - ), + attack: Attack(color: Srgba(Srgba(red: 0.424, green: 0.694, blue: 0.725, alpha: 1.000))), + deck: Deck(cards: ["step", "pair"]), ), "purple": Actor( @@ -148,12 +122,8 @@ ], ), - attack: Attack( - color: Srgba(Srgba(red: 0.694, green: 0.529, blue: 0.788, alpha: 1.000)), - ), - deck: Deck( - cards: ["step"], - ), + attack: Attack(color: Srgba(Srgba(red: 0.694, green: 0.529, blue: 0.788, alpha: 1.000))), + deck: Deck(cards: ["step"]), ), }, ) diff --git a/assets/config/card.ron b/assets/config/card.ron index 7bb9e74..dc3126a 100644 --- a/assets/config/card.ron +++ b/assets/config/card.ron @@ -40,25 +40,32 @@ ), }, card_icon_map: { - // TODO: Long-duration notes are stronger versions of short-duration notes (more damage and knockback, maybe less speed). + "step": CardIcon(texture: "image/card/icon/step.png"), + "splits": CardIcon(texture: "image/card/icon/splits.png"), + "ballet": CardIcon(texture: "image/card/icon/ballet.png"), + "moonwalk": CardIcon(texture: "image/card/icon/moonwalk.png"), + "cartwheel": CardIcon(texture: "image/card/icon/cartwheel.png"), + "eighth_note": CardIcon(texture: "image/card/icon/eighth_note.png"), - //"quarter_note": CardIcon(texture: "image/card/icon/quarter_note.png"), - //"half_note": CardIcon(texture: "image/card/icon/half_note.png"), - //"whole_note": CardIcon(texture: "image/card/icon/whole_note.png"), + "quarter_note": CardIcon(texture: "image/card/icon/quarter_note.png"), + "half_note": CardIcon(texture: "image/card/icon/half_note.png"), + "whole_note": CardIcon(texture: "image/card/icon/whole_note.png"), "pair": CardIcon(texture: "image/card/icon/pair.png"), - "major_chord": CardIcon(texture: "image/card/icon/major_chord.png"), - "cluster_chord": CardIcon(texture: "image/card/icon/cluster_chord.png"), - "rest": CardIcon(texture: "image/card/icon/rest.png"), + //"triplet": CardIcon(texture: "image/card/icon/triplet.png"), + "chord": CardIcon(texture: "image/card/icon/chord.png"), + "cluster": CardIcon(texture: "image/card/icon/cluster.png"), + + "eighth_rest": CardIcon(texture: "image/card/icon/eighth_rest.png"), + "quarter_rest": CardIcon(texture: "image/card/icon/quarter_rest.png"), + "half_rest": CardIcon(texture: "image/card/icon/half_rest.png"), + "whole_rest": CardIcon(texture: "image/card/icon/whole_rest.png"), + "sharp_flat": CardIcon(texture: "image/card/icon/sharp_flat.png"), "natural": CardIcon(texture: "image/card/icon/natural.png"), "fermata": CardIcon(texture: "image/card/icon/fermata.png"), "bass_clef": CardIcon(texture: "image/card/icon/bass_clef.png"), - - "step": CardIcon(texture: "image/card/icon/step.png"), - "splits": CardIcon(texture: "image/card/icon/splits.png"), - "ballet": CardIcon(texture: "image/card/icon/ballet.png"), - "moonwalk": CardIcon(texture: "image/card/icon/moonwalk.png"), }, + // TODO: Write descriptions. card_map: { "step": Card( name: "Basic Step", @@ -69,11 +76,11 @@ // TODO: "Movement card" sfx. play_sfx: "audio/sfx/Projectile Hits Enemy.ogg", action: Step, - action_config: CardActionConfig( + action_modifier: CardActionModifier( remove_on_beat: 8, ), ), - "splits": Card( + /*"splits": Card( name: "Splits", description: "Split in two!", background: "blue", @@ -81,9 +88,59 @@ // TODO: "Movement card" sfx. play_sfx: "audio/sfx/Projectile Hits Enemy.ogg", - action_config: CardActionConfig( + action_modifier: CardActionModifier( remove_on_beat: 16, ), + ),*/ + // TODO: Add other movement cards. + + "eighth_note": Card( + name: "Eighth Note", + description: "", + background: "pink", + icon: "eighth_note", + + action: Attack, + action_modifier: CardActionModifier( + remove_on_beat: 0, + attack: Attack(projectile: Some("eighth_note")), + ), + ), + "quarter_note": Card( + name: "Quarter Note", + description: "", + background: "pink", + icon: "quarter_note", + + action: Attack, + action_modifier: CardActionModifier( + remove_on_beat: 0, + attack: Attack(projectile: Some("quarter_note")), + ), + ), + "half_note": Card( + name: "Half Note", + description: "", + background: "pink", + icon: "half_note", + + action: Attack, + action_modifier: CardActionModifier( + remove_on_beat: 0, + attack: Attack(projectile: Some("half_note")), + ), + ), + "whole_note": Card( + name: "Whole Note", + description: "", + background: "pink", + icon: "whole_note", + + action: Attack, + action_modifier: CardActionModifier( + remove_on_beat: 0, + attack: Attack(projectile: Some("whole_note")), + ), ), "pair": Card( name: "Pair", @@ -91,25 +148,70 @@ background: "pink", icon: "pair", - action: DoubleBeat, - action_config: CardActionConfig( + action: Attack, + action_modifier: CardActionModifier( remove_on_beat: 4, - attack: Attack ( - power: 2.0, - force: 4.0, - projectile: Some("quarter_note"), - ), + attack: Attack(projectile: Some("eighth_note")), ), ), - "major_chord": Card( + /*"major_chord": Card( name: "Major Chord", - description: "Notes that move apart synchronously", + description: "", + background: "pink", + icon: "chord", + + action_modifier: CardActionModifier( + remove_on_beat: 16, + attack: Attack(projectile: Some("eighth_note")), + ), + ), + "cluster_chord": Card( + name: "Cluster Chord", + description: "", background: "pink", - icon: "major_chord", + icon: "chord", - action_config: CardActionConfig( + action_modifier: CardActionModifier( remove_on_beat: 16, + attack: Attack(projectile: Some("whole_note")), ), + ),*/ + + "eighth_rest": Card( + name: "Eighth Rest", + description: "Heal a little bit", + background: "green", + icon: "eighth_rest", + + action: Heal, + action_modifier: CardActionModifier(heal_flat: 5), + ), + "quarter_rest": Card( + name: "Quarter Rest", + description: "Heal 25% health", + background: "green", + icon: "quarter_rest", + + action: Heal, + action_modifier: CardActionModifier(heal_percent: 25), + ), + "half_rest": Card( + name: "Half Rest", + description: "Heal 50% health", + background: "green", + icon: "half_rest", + + action: Heal, + action_modifier: CardActionModifier(heal_percent: 50), + ), + "whole_rest": Card( + name: "Whole Rest", + description: "Heal 100% health", + background: "green", + icon: "whole_rest", + + action: Heal, + action_modifier: CardActionModifier(heal_percent: 100), ), } ) diff --git a/assets/config/projectile.ron b/assets/config/projectile.ron index dd09176..733ceb2 100644 --- a/assets/config/projectile.ron +++ b/assets/config/projectile.ron @@ -1,5 +1,19 @@ ( + // TODO: Tune stats for each projectile. projectiles: { + "eighth_note": Projectile( + name: "Eighth Note", + + texture: "image/projectile/eighth_note.png", + spawn_sfx: "audio/sfx/Projectile Hits Enemy.ogg", + spawn_sfx_volume: 0.5, + + lifetime: 1, + radius: 3.0, + speed: 20.0, + damage: 2.0, + knockback: 0.5, + ), "quarter_note": Projectile( name: "Quarter Note", @@ -13,18 +27,31 @@ damage: 2.0, knockback: 0.5, ), - "double_beat": Projectile( - name: "Double Beat", + "half_note": Projectile( + name: "Half Note", - texture: "image/projectile/quarter_note.png", + texture: "image/projectile/half_note.png", spawn_sfx: "audio/sfx/Projectile Hits Enemy.ogg", spawn_sfx_volume: 0.5, - lifetime: 2, + lifetime: 1, radius: 3.0, - speed: 25.0, - damage: 3.0, - knockback: 0.6, + speed: 20.0, + damage: 2.0, + knockback: 0.5, + ), + "whole_note": Projectile( + name: "Whole Note", + + texture: "image/projectile/whole_note.png", + spawn_sfx: "audio/sfx/Projectile Hits Enemy.ogg", + spawn_sfx_volume: 0.5, + + lifetime: 1, + radius: 3.0, + speed: 20.0, + damage: 2.0, + knockback: 0.5, ), }, ) diff --git a/assets/image/card/background/backgrounds.aseprite b/assets/image/card/background/backgrounds.aseprite index 59f5a2ce9ec0060f62850084db10b864aa18ca5d..cad0c04ea151181e83b58388c4520e30ac0e1893 100644 GIT binary patch delta 201 zcmbQrwwIl8??lFW-fl()hF>2!8B!P+7&s^PcGedF84?OCKoSOkDv$vSgKvIWDiZ@U zvLFKk8-rs>Nn&y~3j-^v1Pg;lYGMu>13RiP8_<}P%(O~Aps<1h6GZYqpC&374{x&= H<9|i~Pnj4i delta 31 mcmdnXK9!A8bRuIt?_&lAhF>397*c>V%f#N!&HEVtGXemTF$w1Y diff --git a/assets/image/card/icon/major_chord.png b/assets/image/card/icon/chord.png similarity index 100% rename from assets/image/card/icon/major_chord.png rename to assets/image/card/icon/chord.png diff --git a/assets/image/card/icon/cluster_chord.png b/assets/image/card/icon/cluster.png similarity index 100% rename from assets/image/card/icon/cluster_chord.png rename to assets/image/card/icon/cluster.png diff --git a/assets/image/card/icon/double_beat.png b/assets/image/card/icon/double_beat.png deleted file mode 100644 index 490e021731341f9dbd22b3540bcd6c3b121670fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 158 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|B0OCjLo9mF zPCUrPpupjr{^kGv9QA`v*-inwpKadBxL)p0rx;PlVaEWNfOlbVJy8gb^hk%oe z%(JA7OG*#UI&av_<0ETuwUtk60sjm;#cWlciEBUb^I9%aP&)Q|Mm5k522WQ%mvv4F FO#sBBHKzao diff --git a/assets/image/card/icon/eighth_rest.png b/assets/image/card/icon/eighth_rest.png new file mode 100644 index 0000000000000000000000000000000000000000..f359a2994108463f0a734c559a237f115c8b62d4 GIT binary patch literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|%spKkLo9le z6C_wI4%VwQ=(Mft>l9($*l9dzQRBpkg3GHm#X4+ETXeWVZQJF0tVdX6-X3mv#=vlB Xs`|5=S6^uXjbQL}^>bP0l+XkKJe?_9 literal 0 HcmV?d00001 diff --git a/assets/image/card/icon/half_note.png b/assets/image/card/icon/half_note.png new file mode 100644 index 0000000000000000000000000000000000000000..c9a6fbb1974a3d94e1ed54247cad4f5c20ff2da3 GIT binary patch literal 121 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|j6Gc(Lo9le z6C{Kl{0D-mdKI;Vst0My?lhX4Qo literal 0 HcmV?d00001 diff --git a/assets/image/card/icon/half_rest.png b/assets/image/card/icon/half_rest.png new file mode 100644 index 0000000000000000000000000000000000000000..c765ed563209154a8251af95a36b70cba6f0a758 GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|^gUf1Lo9le z6C_wgnB8)k{sTdOsG+iQTa}tutiwje0`-SQW`4a9dyKi-bQlbP0l+XkKjs+n1 literal 0 HcmV?d00001 diff --git a/assets/image/card/icon/icons.aseprite b/assets/image/card/icon/icons.aseprite index 379bef67f8bd004f11278f040bc45a7c31c60bb5..3b17ca6969cd985749286be82c667df112249959 100644 GIT binary patch delta 763 zcmew$v_+hK3pWG9gQX%9*(-UcGcqvz`pC_Y!oa}5J+W7_z5vLOP+$R)Fo4Vkim@>G z=9i_iG62m$25bzDB_)Z;**pyV$ig7?9;t~r0t~{a!fZfeQZmyj`GCR-3QQ2m|9l3h zTs%BApd5<=)5N{ulNC6HHveR;XJTxhypY9q@@7U)#(WUV$PlQ8Re_O#m4S)jKhzGO z2m=p8#hl~>2iE_M4T%#v|1K9|n90fzVV6F$7^Kb2lsIk2nJ!#?DCB&dnW6uj|He{~ zRts~eRu%>}BpW$^c7kk7NchpuY@l$`Z~C@V!;D@sRL?l zdi{JGI{DeQGF;#cURwn+Oc2Ac$)3!%;IPtm!H|=Og&q^o^$3f2fYyRTui?K112dlk z_tza)9xyRP)RlK;gDi2tG)Na3C`=3-7zX|RKi}j)14~DsbM{w;(+A5tCj$-95jg$r g*L-uBue<*!O+L)rj42q#QjRHjmn9cdFp4!00Mnkt1poj5 delta 244 zcmdlY{y~VnfRlmY!BXLg?3KJ<85kITePm-u0n%&}do|hBfD9G|=Es?7Fir-s7(*vBvWQN8%$YN}fK?EvmTPhr7li#B vN~drK2nv90V*uL*WHNwE)}H*1S!nY)#(E}RJFqk(SekM2Ll$|E6y>4-p4dY} diff --git a/assets/image/card/icon/quarter_note.png b/assets/image/card/icon/quarter_note.png new file mode 100644 index 0000000000000000000000000000000000000000..4ff3deb28e25f60b80596fc9554b8c1c6dd43dec GIT binary patch literal 123 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|Og&v3Lo9le z6C{Kl{0D- literal 0 HcmV?d00001 diff --git a/assets/image/card/icon/rest.png b/assets/image/card/icon/quarter_rest.png similarity index 100% rename from assets/image/card/icon/rest.png rename to assets/image/card/icon/quarter_rest.png diff --git a/assets/image/card/icon/whole_note.png b/assets/image/card/icon/whole_note.png new file mode 100644 index 0000000000000000000000000000000000000000..0f38ff4d0d9a12687bad04d588f972e940f1e96d GIT binary patch literal 118 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|3_M*NLo9le z6C_xf`6V`T{`>#`zkS%zo}P%S$r;De81xF&lwvx?19BL?9!?OMz{kLxBL2N@!{ltB OUItHBKbLh*2~7apULv*t literal 0 HcmV?d00001 diff --git a/assets/image/card/icon/whole_rest.png b/assets/image/card/icon/whole_rest.png new file mode 100644 index 0000000000000000000000000000000000000000..a194927b9dc4bb5f14253f5e9bca77d6e1467d37 GIT binary patch literal 119 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|3_V>OLo9le z6C_v{H#9a19{chC|Nr_)CPqd^izFI&3MAPsxA4sH*eEK!;6_8>fddQ-N7Xsl7wzqy Q57f-y>FVdQ&MBb@069=3N&o-= literal 0 HcmV?d00001 diff --git a/assets/image/projectile/eighth_note.png b/assets/image/projectile/eighth_note.png new file mode 100644 index 0000000000000000000000000000000000000000..4842c98e8a382d8b0a1c57cd9c4ea9f4ddbefb2b GIT binary patch literal 127 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqjKx9jP7LeL$-D$|EInNuLnNjq zCpa+wU&wGQ-6_0b&4dL<{sX~d6GruhnGB01H%gv8ae_lU{m^R#Hl2MA*Ula|aDai~ Y`7h;ni3{Sk0}WyDboFyt=akR{0R8VQ6951J literal 0 HcmV?d00001 diff --git a/assets/image/projectile/half_note.png b/assets/image/projectile/half_note.png new file mode 100644 index 0000000000000000000000000000000000000000..9f0ec953cc5471e11fc536d748e5371da3a41511 GIT binary patch literal 113 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqjKx9jP7LeL$-D$|v^`xMLnNjq zCmdk<_y7NY`D1B^mN7_PaAf2*V!v4^!4N4l^K3`xgo%QBd<_4e3;$ccd9^rD8-u5- KpUXO@geCw|I3f=K literal 0 HcmV?d00001 diff --git a/assets/image/projectile/projectiles.aseprite b/assets/image/projectile/projectiles.aseprite new file mode 100644 index 0000000000000000000000000000000000000000..54c304ef040be450ecc09083a281353696dbdbcf GIT binary patch literal 476 zcmcb^$iVPmDGLJ!5GpVLISeU4i~vjwj37Y<0U)FWm<%-Z*GCqxtt>#c7!b27fUQKb z4rDhA$aPFW#{d8SG=~EYtpDnj7(H|uY%W+Ibwbl`M4Wz;2AzIAK8DIxk literal 0 HcmV?d00001 diff --git a/assets/image/projectile/quarter_note.aseprite b/assets/image/projectile/quarter_note.aseprite deleted file mode 100644 index 46833163c143a4131fd9d29c467d49468ae1d6ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 261 zcmZQ&WMFu(l#zi02o)HB9EKDiMgS%TMvx$b01(mwv;qzN^^pZ^D+`b<2E^EHkJWmYc=9t5~6Yl(19P|*&NUGeMCNB`MB_^(V}+rX_aF2Lqer^E=< O%HZkh=d#Wzp$P!Cx*`Pt literal 0 HcmV?d00001 diff --git a/src/game/actor/health.rs b/src/game/actor/health.rs index 24009bc..7270788 100644 --- a/src/game/actor/health.rs +++ b/src/game/actor/health.rs @@ -50,10 +50,7 @@ impl Configure for Health { fn configure(app: &mut App) { app.register_type::(); app.observe(lose_health_on_damage); - app.add_systems( - Update, - trigger_death_from_health.in_set(UpdateSet::TriggerDeath), - ); + app.add_systems(Update, check_health.in_set(UpdateSet::TriggerDeath)); } } @@ -75,14 +72,15 @@ fn lose_health_on_damage(trigger: Trigger, mut health_query: Query<&mu health.current -= trigger.event().0; } -fn trigger_death_from_health( +fn check_health( mut commands: Commands, - health_query: Query<(Entity, &Health), (Changed, Without)>, + mut health_query: Query<(Entity, &mut Health), (Changed, Without)>, ) { - for (entity, health) in &health_query { + for (entity, mut health) in &mut health_query { if health.current <= 0.0 { commands.entity(entity).trigger(OnDeath); } + health.current = health.current.clamp(0.0, health.max); } } diff --git a/src/game/card.rs b/src/game/card.rs index 5bf2fbe..e16f026 100644 --- a/src/game/card.rs +++ b/src/game/card.rs @@ -8,9 +8,9 @@ use serde::Deserialize; use serde::Serialize; use crate::game::card::action::CardAction; -use crate::game::card::action::CardActionConfig; use crate::game::card::action::CardActionKey; use crate::game::card::action::CardActionMap; +use crate::game::card::action::CardActionModifier; use crate::ui::prelude::*; use crate::util::prelude::*; @@ -162,6 +162,7 @@ impl EntityCommand for CardIcon { } } +// TODO: `min_level` field before the card can be offered in the level up menu. #[derive(Reflect, Serialize, Deserialize, Clone)] pub struct Card { pub name: String, @@ -177,11 +178,11 @@ pub struct Card { pub play_sfx: Option>, #[serde(default = "one")] pub play_sfx_volume: f64, - #[serde(rename = "action", default)] + #[serde(rename = "action")] action_key: CardActionKey, #[serde(skip)] pub action: CardAction, - pub action_config: CardActionConfig, // TODO: Naming + pub action_modifier: CardActionModifier, } fn one() -> f64 { diff --git a/src/game/card/action.rs b/src/game/card/action.rs index b7a2dd4..0b3bdb8 100644 --- a/src/game/card/action.rs +++ b/src/game/card/action.rs @@ -5,8 +5,9 @@ use serde::Deserialize; use serde::Serialize; use crate::game::actor::attack::Attack; +use crate::game::actor::health::Health; use crate::game::card::attack::AimTowardsFacing; -use crate::game::card::attack::DoubleBeat; +use crate::game::card::attack::AttackOnBeat; use crate::game::card::movement::MoveTowardsFacing; use crate::game::cleanup::RemoveOnBeat; use crate::util::prelude::*; @@ -30,37 +31,45 @@ impl FromWorld for CardActionMap { fn from_world(world: &mut World) -> Self { Self( [ - ( - CardActionKey::Rest, - world.register_system(|_: In<(Entity, CardActionConfig)>, _: &mut World| {}), - ), ( CardActionKey::Step, world.register_system( - |In((entity, config)): In<(Entity, CardActionConfig)>, + |In((entity, modifier)): In<(Entity, CardActionModifier)>, world: &mut World| { r!(world.get_entity_mut(entity)).insert(RemoveOnBeat::bundle( MoveTowardsFacing, - config.remove_on_beat, + modifier.remove_on_beat, )); }, ), ), ( - CardActionKey::DoubleBeat, + CardActionKey::Attack, world.register_system( - |In((entity, config)): In<(Entity, CardActionConfig)>, + |In((entity, modifier)): In<(Entity, CardActionModifier)>, world: &mut World| { r!(world.get_entity_mut(entity)).insert(( RemoveOnBeat::bundle( - DoubleBeat(config.attack.clone()), - config.remove_on_beat, + AttackOnBeat(modifier.attack.clone()), + modifier.remove_on_beat, ), - RemoveOnBeat::bundle(AimTowardsFacing, config.remove_on_beat), + RemoveOnBeat::bundle(AimTowardsFacing, modifier.remove_on_beat), )); }, ), ), + ( + CardActionKey::Heal, + world.register_system( + |In((entity, modifier)): In<(Entity, CardActionModifier)>, + world: &mut World| { + let mut entity = r!(world.get_entity_mut(entity)); + let mut health = r!(entity.get_mut::()); + health.current += modifier.heal_flat; + health.current += modifier.heal_percent / 100.0 * health.max; + }, + ), + ), ] .into_iter() .map(|(key, sys)| (key, CardAction(sys))) @@ -69,18 +78,17 @@ impl FromWorld for CardActionMap { } } -#[derive(Reflect, Serialize, Deserialize, Eq, PartialEq, Hash, Copy, Clone, Default)] +#[derive(Reflect, Serialize, Deserialize, Eq, PartialEq, Hash, Copy, Clone)] pub enum CardActionKey { - #[default] - Rest, Step, - DoubleBeat, + Heal, + Attack, } -/// A newtyped `SystemId` with a `Default` impl. +/// A newtyped `SystemId` with a `Default` impl. #[derive(Reflect, Copy, Clone)] #[reflect(Default)] -pub struct CardAction(#[reflect(ignore)] pub SystemId<(Entity, CardActionConfig)>); +pub struct CardAction(#[reflect(ignore)] pub SystemId<(Entity, CardActionModifier)>); impl Default for CardAction { fn default() -> Self { @@ -90,13 +98,12 @@ impl Default for CardAction { #[derive(Default, Reflect, Serialize, Deserialize, Clone)] #[serde(default)] -pub struct CardActionConfig { +pub struct CardActionModifier { /// Remove component after this many eighth-beats. - #[serde(default)] remove_on_beat: usize, /// Remove component when this timer finishes. - #[serde(default)] remove_on_timer: Timer, - #[serde(default)] attack: Attack, + heal_percent: f32, + heal_flat: f32, } diff --git a/src/game/card/attack.rs b/src/game/card/attack.rs index c8f080a..ea1b4c0 100644 --- a/src/game/card/attack.rs +++ b/src/game/card/attack.rs @@ -9,7 +9,7 @@ use crate::game::cleanup::RemoveOnBeat; use crate::util::prelude::*; pub(super) fn plugin(app: &mut App) { - app.configure::<(AimTowardsFacing, DoubleBeat)>(); + app.configure::<(AimTowardsFacing, AttackOnBeat)>(); } #[derive(Component, Reflect)] @@ -37,26 +37,26 @@ fn apply_aim_towards_facing( #[derive(Component, Reflect)] #[reflect(Component)] -pub struct DoubleBeat(pub Attack); +pub struct AttackOnBeat(pub Attack); -impl Configure for DoubleBeat { +impl Configure for AttackOnBeat { fn configure(app: &mut App) { app.configure::>(); app.register_type::(); app.add_systems( Update, - double_beat + attack_on_beat .in_set(UpdateSet::RecordInput) .run_if(on_beat(4)), ); } } -fn double_beat(mut attack_query: Query<(&mut Attack, &mut AttackController, &DoubleBeat)>) { - for (mut attack, mut controller, double_beat) in &mut attack_query { - attack.power = double_beat.0.power; - attack.force = double_beat.0.force; - attack.projectile_key = double_beat.0.projectile_key.clone(); +fn attack_on_beat(mut attack_query: Query<(&mut Attack, &mut AttackController, &AttackOnBeat)>) { + for (mut attack, mut controller, attack_on_beat) in &mut attack_query { + attack.power = attack_on_beat.0.power; + attack.force = attack_on_beat.0.force; + attack.projectile_key = attack_on_beat.0.projectile_key.clone(); controller.fire = true; } diff --git a/src/game/card/deck.rs b/src/game/card/deck.rs index 1f22266..1b8f0a6 100644 --- a/src/game/card/deck.rs +++ b/src/game/card/deck.rs @@ -100,8 +100,8 @@ fn play_card_from_deck( } let action = card.action; - let action_config = card.action_config.clone(); - commands.run_system_with_input(action.0, (entity, action_config)); + let action_modifier = card.action_modifier.clone(); + commands.run_system_with_input(action.0, (entity, action_modifier)); } }