From 6a62c845958465226f0140a6da5ecfeed687cddb Mon Sep 17 00:00:00 2001 From: Kienan Stewart Date: Sun, 3 Apr 2022 16:19:49 -0400 Subject: [PATCH] Basic powerups --- TODO.md | 9 ++-- assets/export/powerup.png | Bin 0 -> 8932 bytes src/Game.gd | 90 ++++++++++++++++++++++++++++++++++++++ src/PieceDetails.tscn | 6 +++ src/Powerup.gd | 20 +++++++++ src/Powerup.tscn | 32 ++++++++++++++ 6 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 assets/export/powerup.png create mode 100644 src/Powerup.gd create mode 100644 src/Powerup.tscn diff --git a/TODO.md b/TODO.md index 038d82f..b7f45ab 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,7 @@ 1. Power ups - * a chance of having power ups spawn on an random unoccupied square when a unit dies - * +health, +attack, +speed, +jump, (pawn only) remove "attack_only", spawn a new (random?) piece, change movement type + * spawn a new random piece powerup 2. Visual polish + * a visual / title in the left sidebar * multiple square tiles to add variation * make the help text indicate (flash, etc.) * visual indications when damage is done but a unit isn't killed @@ -9,7 +9,10 @@ 3. Sound effects * on hit, especially when the unit isn't killed * if possible, a small bit of background music -4. New units +4. Gameplay additions: + * powerups: change movement type, remove pawn's attack and movement restrictions + * new units + * choose difference board sizes 5. Further visual polish * animate the piece making the attack, and returning to it's spot diff --git a/assets/export/powerup.png b/assets/export/powerup.png new file mode 100644 index 0000000000000000000000000000000000000000..af1391cbb8512d31038dea9fa85e8e83a81263b5 GIT binary patch literal 8932 zcmeHKc{tSV*B@lxTSWE|A!BCDjD5>K7<)*z*)ZA0%wX(96-k&e>cJD_+U-KH&44i*$UD3W_Ixm__ zVdgn_Hg(&jVsW=FVxuv3s%W`-BI$8H(Pq{?X+5~jKRf=rnyDm4xS7qtT<>}2i0^ad z@}l*xa7N>ZV{niK#>4qls4JTl$pMb)82}14s-Ygtm7MD_3EwNakveGq4!(QgH)VH* z?k30TXf1ZZ(Mk@dBmu4o`TNa7xrY^Bmc}@&*_99qW+JTgh5Yx*SQugzw$Q{mlU%iM zx-$Hrn0I=SCD602PLt3Dyuj`px9G(U793EE6)#tT@Tkb&PIgZra?|&zamnzxT=T5rVbv63Tx*dGU z#zH^nxydJJ{*7@jUMKIx50z^sxdkj7H|U?~aaX#8FDDVpMXY62Lq{H$iQ`qG@wNMLw@o7G-2xCiI9^ zmR{}w=S&A7k^icJfOkSgyMXV-E4Jsl)je;&{~~moG%DbJo1EiF>^oiF^m$NiHEa#~ z;;zLLly(l2sLo|xV~LZ7>cUX5_LHf`s+qV{6HP{As6=RGx766j${z6!V7#o+8Yceq zlbFM0#ViG-WhJ%sA3TdI#NT9HsLyn}l{bIh!%x@y+4h&8^a!YBs<4d6qT(Ck+uzQ{ zOp`GDFfpkbz%*Ae9rTbQww9V(gPY@rZAjo^lOg>OWqk-n+rmy9bwn`Wh)T-mJ5R4= zuRea+3^e4J(4BMkYtVf_%y=POk$man8-4K|V)M3i*xa}6Z$@{R)HQbZ4k3o9!IKUH z4jeKyQo1vqlIMCl{Mb23<89WVcUI+PBP1|Jchz{O99r)!PG+rY=r^yKmX22|%TY~_ zi9fcL8NJ$gt=6Slveef9<&QFh(+;56p40(OrxNp12$lf(w5!^vf|4#gKQ0ZK?ng~$ zUYc<*a8$ZJ==c6@g}eLR&%jmb%B2%MFNT@<@_BBBEB?3;IB-)*k2UtzvpKH4-ZX^U zjq1{Zvk5&ib*?FuwdMm?^L5@`F>cR0AMu9naNpat-V!EEMt0$eIh7BSYyG`wBAv(y z)xt0*=86=X^z)9lrg-K0bkr|cdKQ11y{b@C<-~AmAo$D1B3tKc)+5n=3c2v3oPh(E zx!zQzOrtcpyA?C1vo#CYaM{KHX?hoCwzM;cLIb@Hmq+Z{BezI-W&(SPRvVa$t$<$N2d{-N)+D7hQ*lg82b?KQ=~r&fAuAR(u?#^0M*V zO%KlQipyYm$C_PgEMd{c_$A-(qmE3!lvn^!G)7T^$(yrq`>nE}gz=cwQ6i*r;Vhz_ z-K<@EiLS8Z0{vTT$!P|wH@P21Ap5Q)Yd!$-w)$as4@$gpA_k^u&ZKi6c)1z7L+fY&*U6lx1zQy-lc3P1eGM5g`{h zPkK!5Ud@6M{wUX+cx1tqF{6 zzkSYr+FAPU>T}pPMLXuM+t-&vLt5`nQ4&UOK*nr>*m#mJ_lT^;JdYG-S9SH$(&cNF zt0~68XXr0LV>zn>=)E%@X=&w%Tn-#x+=7#@{S2~r^QznB%wrKd3;19|mw{=lhstQq z1>u0}(=lG0rL`8uPmS-kVS^lM>1*Z}jgn2S)u$J4=U4Z7+{yh}5U{LoL(;Iqo2y)o zK-J$$!;Zq9{$Sd*vEJ#jS|s;s)3%j0 z4`i=ohhFC;e48gc z{>*^9$&zK8`FMh-auqCVb&yA~Ejw)rn=Y}J}11(6ku`4yG!4eOia&dX#b7Pqo zsvcK}AC)4w&vND8F2t)5rZ}wKTgS~Q8nW9Y?EC)UAa??M>WqO)rt`VU>Y<7xe%>zM z(Lw(CV<(^847{1+U6|b|!Str9#vr*r`t`TD8ePl@N`O;f)cale_y?A+)yu)(A;o{@hz{{v^MA`(}7^f|#>msIvjb zz0D&>Hz*M+1$HjLoXOZ9b-WRinv|rL9fWVdxA4*7y!GzMiQ37k714Tky=c+K=xr`S zu+F*Xo!2LWLM~rnY#QlRvrHf0Th=;~6i0NhU4Sy`tWJ>^=blRBhEDWkQ$Fx#ZB&~& z>aJ&9p`>PMt?a>;W~lg@D3D=YOa2Gx-NEAvtChPJspXPE3O62H8wh0Y?jAHV^_INw z+;pWeF?duztUkG@grRgbAiW&0mjIri9}kqu@%sA7px?jYi`VqJR~|Qe%(Yh$SyCF8 zXYVvTRqywd`;rx&s6RaTa!n+jBb>jl*+2q(VRX#HacEa}!4om97-Hy8|4 z8eRJ-sEBFvmEO6-x-*UzI&X94ySj6)_~+h{2J`J>wo|S)$g_Eyb_?0B&2B5IK5;pu zy8UKZRJdYBqVIZHJJxRsRw^U`%9a3i)mc+g9~B`r!yafKA9-gg@h5www6L zi8u0OP16O4yIakw`fQsLQdh}#w{&;FMev2;nQ;-5mdHJN!Jsh4)~}_$wAR`6KlaQ7 zA_cqOGixAUaz;WpcHG$vj4%?T{zh6qwp}C8vQeP(njfmR%lua3lF zbe|Or$)Gg~7W7w4A+x%k&HLspKC4>g~B1pv@R6LfVgkh;2m^yf4W*foGZ3E-T}T&G_{6g=^UKi+L`@+6tS>|GX&0iM$%0H|;=N!&ZElp1EHZT_(m7 z9;vLVB2#a4WzU2Sgi%-i)X@-<*bo?L0fxP1yGEDgbE`zpu?uI{)@>KVqX&*8WS(o! zJ}LQ5?a3$J>1C$`_wRRh$Q#8f@pN>_)O3MDRO1=-8iHW<<`s$i(q+#Vp65w9C2b`y zU+wVCW|wDIhhYk>*PruZDtg=9e<2!q+N*F$K z86KC^0!$Y>6LV44Si039!S?o1cA3${oh@dkWM@a}t?k+uNXQ2fw|Kd2~2}H+t&4BE7R-RC%ha2h5R?Kdi$nu)%Mc&>zPDjT&IG+3QI2}_C z$4Hu!jFI(=g{V!~cA;Ev1UscXs0p#@w++ZIDVyUY5?Ki6%`dQL;Q_(~)R2~BM_6Gmmf=tm5pn?1z(0{Zb z+t8*?uoa%{>rcYs^#kxe6p6n>;IMz%6a7hE2kGFjV7wRJo2E*pd4>MNr6Ce!@u$T; z1?~iI;(-;7?0;xd2yTCo^^e&0R}RwodmuFPKXLz|{YUNx$}}w$N>$Gn>%Si!QcnZ8 z?_U+?izVPx5B@@7IAvux6bHg$ln@}eA{qixc7xzRPy_~p!$9y#FdX`CP)Hv#1?_{y z??chR=Ukf#saAURFH@KC9&{AQ`~3<8bDKmk3aRV1sj4l-kO5mXA`OjSAjqg za3u%~qNJdr_?MC`od)e!t#+9RV-G!IGHRLD{OJvA>*<(E)he zfg_sTuO+Mp+Q%JFJKw(-)E{!ff7mQ6S_zB5BQPKY42l84;Se+kt*DF!;jm~G3<836 zQ-S{4??2JWzHXF2Gzovkot7yr8(IM!WFsbhK&8w-V+r)Y@ACwqooxsl1cBK=5vmBN zDilI{RfRx+;NKGl@1N>FGFAuwFHY1C6#jM%(CmK6Xx9tvwgUfoUH#74K8^p6pWpZ5 z|Iq^t`d=si6~F(|^)Frj6$Ag3^1s#fFJ1o?1OJuszt#1BMi<*(0}tMZ)&&L9#+mv4 zOdZ-N#Dp<1)B^|tQUDeqiDH*%5>}$oIokXrFR}m7Q46#JXhLQR5~a^Pe~94-jO`up z6(3C`K+(6S==yr^_sxKVb`Fmd3nWlH#P-`cyC|;XG_y^l-WeO}=*q2-M|NkAbu^M zB^v^9OXJ9u^v!wse$%Fd z=jt6B{bOfsEcK7=)v-7=MQd{-i%d?)lpw9Nkj#$XF7YU~FZQItE&C541LJrC7G|gN z;#otk=Kq$`jyxewxS21J;+$0N+)oyd@#fuDowj1XCG%54F3_aD!Q?!ESds6XlEWol z&2Y*j3s`ct|Bfz;Z`Q+x{EFTBBa)~TiY=XhVk}ShN@-!3;@Y8AwALDc7|ykQI`R%Z zv(Y7}6Kd^gi>|iebuKNBdbOz6Ek9fEA|mwlbfWY=47-5p;}$Lb4}nzhwC(hY`t7je z{Pb{Kt|xO2^Cy7(p$lDgq7Vjqu8*&tkv;8rc1hE3fn8r43Y*JWMkQLxBX32Lqo(Wg zB4fidEN7T^?Jja(yGCXU{h8ZBXt7M01w1-&bEUvq+uT(ak~`BWwq}VeJNfqbIXs>P ztwb!hi`5xEy>x@hD*n-Lhco4<4wZ@DrVr0^6GSM;|DK(zf!Sq0mk^}GQ5}1GUUtB|NiZarl(D^h2fWmt&>|ia#{1+e zpU1`gAm_<;;}c2I3tc?V!l#j^9|E!Aepf3(OrF0#1_9jUaAXe^r1E)~y;$#Ae2rpPmyt%r7?OC8)TKoC&suZG!41DM# z*qExl<*rf4Odo-?@MY{hm8iXkc*6c%sI^l(G%zl&Z3bC>xHakl>w|f3^U5h1 z?K;`{wYg`JBCpeywb7DaaU0xLe5ONA>z;$ zC4HfctgJq=W}wm)aqjw|=NNZC#sntYk*ZrvjzuYP+~1)4Qux7c)6G0)M`1xz@6M^L+Np!<-30 z*I-V*sASs>lFTzD`&n$L7USaVly0P`{j}G0(_EWj=rqAqvv*N-b^XxxEu-2^x1v|7 zksYYb%tNhZYbrO`qXOwlSWH99N*llgp z#a2Rdc$i*%Y7{p^#Ayh_)avGr@sAJ7kpr)ntyZ_HsVR-8#mn)8V{1?twQn=CdMIDL zPaR4`4m%fv?T7n8?^sNY{- zl4&VAyw>z2jrGw8GGR=DI1_zM=D(7Hh&SlDtzh8L^l{cMUIs>Qo5F9x-p# z3&tB#$hRl22K$_LEFbQzYn{Z4b_fp9#l_zbIYKnxrE{ncy{jZW7TP4sKJc|L-i_)O z#B%g~4t*-H;WuPzS)7LWq~)QNYB<|tA!=81L`L*y>1lHE4)68dFS(rdY}s>S?#N^p zsHaFT?}8`eqEw+}%WchAs3!Mp$as{lwwvL%^WQ^BuGvePEMBtFsqnTU!!KyB6O3|S zzlJa#7DKdbN}LpWeF5x8=s$;a~(wyTJCiLw7)W8t6_s&xV5RX03x9)fGb7 z_|ZAm@sJ_7{oK2Z)921-1RRrYzZ3DSIxH$4d+y#ya#bkzK#+%@^IEOYs%O9K^m|}N zWp2d_zhj!obdF0W3GUb%KW}VxlRO>X6`l0>;rXx%SP2^g{786(DV@EvXEb&!1u?{$ z>=|ZN1+ty|3Qad9d>wH@*2~8bIc`cWX(Ihg zOo%8VUg92`_Q<{;o3blkl9->N!!m1qx`prvnZji9VMW(mBXq5JuxHfCL2@N!BP(Ax zB_M`}%Wvk#%MM9l4)MkmUlVXlWNGoetFooV dz*D=N=3|g|f~lohv_1iV)Hl<6sN;I^e*gi16A1tS literal 0 HcmV?d00001 diff --git a/src/Game.gd b/src/Game.gd index 60d2151..e8c5fe2 100644 --- a/src/Game.gd +++ b/src/Game.gd @@ -261,6 +261,7 @@ func _ready(): get_node("/root/Game/EndMenu/VBoxContainer/Fail Game").connect("pressed", self, "_on_fail_game") get_node("/root/Game/EndMenu/VBoxContainer/Win Game").connect("pressed", self, "_on_win_game") get_node("/root/Game/PanelRight/VBox/PieceInfo").connect("stat_change_requested", self, "_on_piece_stat_change_requested") + get_node("/root/Game/PanelRight/VBox/PieceInfo/Vbox/Powerup").connect("pressed", self, "try_spawn_powerup") reset_game_state() func _on_piece_stat_change_requested(piece, attribute, value): @@ -308,6 +309,7 @@ func reset_game_state(): "y": y, "piece": null, "reinforcement": null, + "powerup": null, } y += 1 x += 1 @@ -535,6 +537,8 @@ func _process(delta): target_square = square square['piece'] = null target_square['piece'] = self.ai_piece + if target_square['powerup'] != null: + apply_powerup_to_piece(target_square) self.ai_piece.set_position(Vector2(target_square['x']*128, target_square['y']*128)) self.ai_piece.at_spawn = false self.ai_target = null @@ -608,6 +612,7 @@ func _physics_process(delta): dest_square['piece'].queue_free() square['piece'].kills += 1 get_node("PanelRight/VBox/PieceInfo").set_piece_info(square['piece']) + self.try_spawn_powerup() var c = self.rng.randi() % 100 var index_to_play = null for idx in self.on_ai_lose_piece.keys(): @@ -624,6 +629,8 @@ func _physics_process(delta): dest_square = square square['piece'] = null dest_square['piece'] = piece + if dest_square['powerup'] != null: + apply_powerup_to_piece(dest_square) piece.set_position(Vector2(dest_square['x']*128, dest_square['y']*128)) piece.at_spawn = false self._on_phase_end() @@ -671,3 +678,86 @@ func _on_StopThat_finished(): func _on_SkipTurnButton_pressed(): self._on_phase_end() + +var available_powerups = { + 55: { + "attribute": "health", + "value": "increase", + "description": "Increase health", + }, + 65: { + "attribute": "damage", + "value": "increase", + "description": "Increase damage", + }, + 75: { + "attribute": "speed", + "value": "increase", + "description": "Increase speed", + }, + 85: { + "attribute": "jump", + "value": "set_true", + "description": "Allow unit to jump", + }, + 95: { + "attribute": "special", + "value": "spawn_unit", + "description": "Spawn a new piece", + } + # @TODO remove attack_only from pawn + # @TODO choose a new movement pattern +} +func try_spawn_powerup(): + print('blah') + var try = 0 + var i = null + var sq = null + while try < 10: + i = self.rng.randi() % (self.height * self.width) + sq = self.board_squares[Vector2(i % self.width, floor(i / self.height))] + if sq['piece'] == null and sq['powerup'] == null: + break + try += 1 + if sq == null: + print("Failed to spawn powerup after 10 tries") + return + i = null + var c = self.rng.randi() % 100 + print("Chance: ", c) + for k in self.available_powerups.keys(): + if c >= k: + i = k + if i == null: + return + print("Attempting to spawn powerup: ", self.available_powerups[i], " at square ", sq) + var powerup = ResourceLoader.load("res://src/Powerup.tscn").instance() + powerup.initialize( + self.available_powerups[i]['attribute'], + self.available_powerups[i]['value'], + self.available_powerups[i]['description'] + ) + powerup.add_to_group("powerups") + var pf = get_node("/root/Game/MarginContainer/Playfield") + pf.add_child(powerup) + # @TODO Set position + powerup.set_position(Vector2( + sq['x'] * 128, + sq['y'] * 128 + )) + sq['powerup'] = powerup + # @TODO Play a sound when a powerup spawns + +func apply_powerup_to_piece(square): + print("Applying powerup ", square['powerup'], " to piece ", square['piece']) + # @TODO Play a sound + if square['powerup'].target_attribute == "special": + print("Special powerups not implemented yet") + else: + if square['powerup'].target_value == "increase": + var value = square['piece'].get(square['powerup'].target_attribute) + 1 + square['piece'].set(square['powerup'].target_attribute, value) + if square['piece'] == self.selected_piece: + get_node("/root/Game/PanelRight/VBox/PieceInfo").set_piece_info(square['piece']) + square['powerup'].queue_free() + square['powerup'] = null diff --git a/src/PieceDetails.tscn b/src/PieceDetails.tscn index 14b3fe5..e28259e 100644 --- a/src/PieceDetails.tscn +++ b/src/PieceDetails.tscn @@ -145,6 +145,12 @@ margin_top = 455.0 margin_right = 190.0 margin_bottom = 495.0 text = "Jump" + +[node name="Powerup" type="Button" parent="Vbox"] +margin_top = 499.0 +margin_right = 190.0 +margin_bottom = 519.0 +text = "Spawn powerup" [connection signal="pressed" from="Vbox/UpMovement" to="." method="_on_UpMovement_pressed"] [connection signal="pressed" from="Vbox/UpHealth" to="." method="_on_UpHealth_pressed"] [connection signal="pressed" from="Vbox/UpDamage" to="." method="_on_UpDamage_pressed"] diff --git a/src/Powerup.gd b/src/Powerup.gd new file mode 100644 index 0000000..700fa23 --- /dev/null +++ b/src/Powerup.gd @@ -0,0 +1,20 @@ +extends Node2D + +var target_attribute +var target_value +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + +func initialize(attribute, value, text): + self.target_attribute = attribute + self.target_value = value + get_node("Control").set_tooltip(text) +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/src/Powerup.tscn b/src/Powerup.tscn new file mode 100644 index 0000000..8b39779 --- /dev/null +++ b/src/Powerup.tscn @@ -0,0 +1,32 @@ +[gd_scene load_steps=5 format=2] + +[ext_resource path="res://src/black_hilight_2px.tres" type="Material" id=1] +[ext_resource path="res://assets/export/powerup.png" type="Texture" id=2] +[ext_resource path="res://src/Powerup.gd" type="Script" id=3] + +[sub_resource type="RectangleShape2D" id=1] + +[node name="Node2D" type="Node2D"] +modulate = Color( 0.270588, 0.858824, 0.792157, 1 ) +material = ExtResource( 1 ) +script = ExtResource( 3 ) + +[node name="Sprite" type="Sprite" parent="."] +material = ExtResource( 1 ) +texture = ExtResource( 2 ) + +[node name="Area2D" type="Area2D" parent="."] +scale = Vector2( 3, 3 ) + +[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"] +shape = SubResource( 1 ) + +[node name="Control" type="Control" parent="."] +margin_left = -27.0 +margin_top = -28.0 +margin_right = 27.0 +margin_bottom = 28.0 +hint_tooltip = "Powerup" +__meta__ = { +"_edit_use_anchors_": false +}