From 92fd76f4b8912bc1cf289960b5a1a016ade37fe4 Mon Sep 17 00:00:00 2001 From: Yogi Wiguna Date: Mon, 23 Feb 2026 12:31:42 +0800 Subject: [PATCH] feat: Introduce an enhanced gridmap addon with procedural generation, pathfinding, and initial core game scripts and assets. --- addons/enhanced_gridmap/enhanced_gridmap.gd | 32 ++++++++++++-------- assets/models/meshes/start.res | Bin 2780 -> 2854 bytes assets/models/normal.tres | 2 +- scenes/main.gd | 16 +++++++++- scenes/player.gd | 18 +++++------ scripts/managers/player_action_manager.gd | 14 +++------ scripts/managers/stop_n_go_manager.gd | 24 +++++++++++---- 7 files changed, 67 insertions(+), 39 deletions(-) diff --git a/addons/enhanced_gridmap/enhanced_gridmap.gd b/addons/enhanced_gridmap/enhanced_gridmap.gd index 26d8e98..91d8e23 100644 --- a/addons/enhanced_gridmap/enhanced_gridmap.gd +++ b/addons/enhanced_gridmap/enhanced_gridmap.gd @@ -52,7 +52,11 @@ func _ready(): if auto_generate: generate_grid() if auto_randomize: - randomize_grid() + # Safety check: Don't auto-randomize if game mode manages its own arena + if not (ResourceLoader.exists("res://scripts/managers/lobby_manager.gd") \ + and get_node_or_null("/root/LobbyManager") \ + and get_node("/root/LobbyManager").game_mode == "Stop n Go"): + randomize_grid() validate_item_indices() # Core grid management functions @@ -276,9 +280,9 @@ func randomize_floor(floor_index: int, custom_rng_callable: Callable = Callable( if current_item_on_floor in immutable_items: continue - # IMPORTANT: Only place items if Floor 0 has a walkable tile + # IMPORTANT: Only place items if Floor 0 has a valid ground tile (Walkable, Safe Zone, etc) var floor_0_item = get_cell_item(Vector3i(x, 0, z)) - var is_ground = (floor_0_item == normal_items[0]) # Assuming 0 is ground + var is_ground = (floor_0_item != -1) # All tiles on Layer 0 are valid ground if not is_ground: set_cell_item(Vector3i(x, floor_index, z), -1) # Clear item if no ground @@ -564,25 +568,29 @@ func find_path(start: Vector2, end: Vector2, floor_index: int = 0, clear_path_vi path = astar.get_point_path(start_point, end_point) + # TEMPORARY PATH VISUALIZATION - Moved to Layer 2 (Overlay) to protect Floor 0 and Floor 1 if visualize: if clear_path_visual: - clear_path_visualization(floor_index) + clear_path_visualization() - set_cell_item(Vector3i(start.x, floor_index, start.y), start_item) - set_cell_item(Vector3i(end.x, floor_index, end.y), end_item) + # Always use Layer 2 for these temporary markers + set_cell_item(Vector3i(start.x, 2, start.y), start_item) + set_cell_item(Vector3i(end.x, 2, end.y), end_item) for point in path: - if point != start and point != end: - set_cell_item(Vector3i(point.x, floor_index, point.y), hover_item) + if Vector2(point.x, point.y) != start and Vector2(point.x, point.y) != end: + set_cell_item(Vector3i(point.x, 2, point.y), hover_item) return path -# Path visualization -func clear_path_visualization(floor_index: int = 0): +# Path visualization - Standardized to Layer 2 +func clear_path_visualization(unused_floor_idx: int = 0): + # We strictly clear Layer 2 (Overlay) and reset to -1 (Empty) + # This ensures we never overwrite Layer 0 (Floor) or Layer 1 (Items) for x in range(columns): for z in range(rows): - var cell_item = get_cell_item(Vector3i(x, floor_index, z)) + var cell_item = get_cell_item(Vector3i(x, 2, z)) if cell_item == hover_item or cell_item == start_item or cell_item == end_item: - set_cell_item(Vector3i(x, floor_index, z), normal_items[0]) + set_cell_item(Vector3i(x, 2, z), -1) # Cost calculation and updates func get_cell_cost(x: int, z: int, floor_index: int = 0) -> float: diff --git a/assets/models/meshes/start.res b/assets/models/meshes/start.res index 10be0b3b4fed16315056b8d8c0f39e339fe57faf..5cd4a13fdd05f3ee53f8c7ec672e1156690c93af 100644 GIT binary patch literal 2854 zcmV+>3)%EiQ$s@n000005C8y-7XSdZ1^@t51ONaiwJ-f(01ss~0NO{C4nLssqyvRh zP8rOjFXR4r0xoE#b8`wZe>Ce_0ZRxWTbk6Ca#<(|*=ftu>K#znTzrR|Dv!UAT%QO?=dJ7zAx+-5uIpmLA``+qm)R{?9Sx6sN5 zTsPNdL)-A{tP#fizQ1Ud_M0)*3f!vP0lu!5obXbYTG!C0))vC|{Gxl-?Z!7UlP91L4p_QFeu-0iVAg!CXy8DK9f`BSHyewVm5@iW$ zW~jstCT3>p!Muc}42&fx3q+RI_#wdzfP_3sB;tNwyRy!K3G0|Al26IuTY2C1^*M8AsL+iE6 zx}ZDBc|G~js3}Uzv?a852weZ2d&(;=Ai7#PR8nc zoBa1zg|Es*=wzq#8Rh+UaH*`GJ4p*Sk4cVxwQC5g-(uzg0ZQIAg zXqEvGwFS+fGdR-NG4hA|qa=%Vs0f548vtS8m_*^wxCCNC0>{j(C!7g^q!2Tg@cU`< z@9l_yhZ`w8uqIJ7c3=?12eF1@NsDZ6fXl7(Y zBuP>zba4cPU{Fejb`k(pF^EEkkQy41q@bXnR;JDJ1`VUSol7i0Hg3+BAe<~Ob%fUZ zh+A#yC#KK1OxoUbx)@J=MNI^G<#f@?!F$_QNH$vaOEN3jO3i`RM=lmIXS6VNI|>*C z7TTypFF7oExMMXuzz(!zZTC!K%ee4#PaJRP=6SD1G}PlK)Xui!OM_5y{GgHjzysi* zH?w=oNRZ6JPF{_55a?B-U{OtjvUrmskuztDsG|5$u+Pu^Fh$f6(Q!54Q(g&0l5}^C z*yw^sh2>C)BItv&?plQ8P2WtAw*sCxSZ_kKf0F<=pY$A!j~uF$b!5w1kl~K{Co_Bx zb&}oG zS+u_d!v&i|N~jd={00t~-X;HIuHqpvCfpG?5*%$>99?7O7g!(18o-8HExL(QU|^fZ z2YU@8C4Skkw8p@#z?{Ae2nc92&>9x>tt0sr9E5guogTzAo#8m?=={Su+pxi9MRWUH zy6p#hw1{6ptFsfa{725P{7exp&~FB`XrWBEueFOWU&sew1#6b{yk>^#K%aUb8JR6y zBg4nZ;%&-ny3h;)*+}YWC|%q!z{)-5UdrOvwW^UnI#qv2R@HiqG81e+W!7&M;e)0g zAN~!TKw-PTxg^sKj|^_&C0C%AJH3E`ysO001AL`9Q1V6 zE6#^>MY=CA@PfmqEt13JfvE+03^3vhc|mI{v1fZ0g#gYf zcQzjvLQhMpKk^W;=^v2CJcK$B*DD9M#)S|qoGf^p=pgUKr?0#@_7=Y|aIPTiW4&20 zRjUS4#POXgg$f+tM-e|LCN^tj1{+elW6rNnd`rQ2+?FEZK_tfSY%%Q441=zfl${zf z`H7E4N8RT>3 zS#@B{nzg>Sz3thZ0@47z0Hgp?zswIa^>sx_;%iHS5GtIkiJ;)-0II^91rg9JAe?k- z?a~e^2cRst{V+9M<6?+)@oDkp1tP?eXAD; zk(DFwYxS1ZU}Ae;V5qd21cf9O z^~V%Z8`Kd2hiXMsAD8M$B$0|2Kh>2UoX#dpie2?f456{3s~=}pGwP~FTDq!Qandnf zmEc*Bn-`fJk)tvtL^@cZpy+aDxPnuHyIO9j&fs#=S@C2TfYHkE(UPHgB`&Fy6_;ZJ zliQJ##~cQ%BH1D=>yWpZGla|0@bB;^Z%&&}BWXYo__Q@ZrKgc+4^r z4+%RAX@J{|32LPUg`8;!#Z19DKcV7m+zfg-$+Mt{|;6m{l4}$UbsC>Xm zdsinG;--()+o^?HD8%Fs%Y%-$(mxMof-k$NH`A_z{s&4;d1hPei6uaf?SoA1HyMGW zk-pq$6Y#3kaCRq!$kr7;lxPRSfNaOYY~rwGN5;VMYABY=3Snh$Z`J>joVqMX-td1^ zTC?vbN$X)0)2cbZP|%VteB$kbR|7!34Z_W4FgeDksXezZB)qE`C?2GX8@6)g#!^#5 ELnBdnWyvA zwHH#P1y7GYycpMR$^S3#qsU3xK#x?y+imur?Ft^`ZBF@h@LIGWu9R20HP#{h*}g5- z|0g|9j|aZ@co);2?FGq7Ee0!puq!r0TXM_Ial9fgU$ORh=eARweRYep*Gns6Y=&0U zBo(v8;Qt%=tT5YMOP=fQ|Bv7~uO;n2o3r}e`tFi$D`wqWvgQPDvkf`bo#Gm5Ol`PL z&F%jG2>)+BSBfhFqhzbj{|opYw=J^j-X#7%_x}V2{0HUTVbQPBe3NXxxSQJYa@`c$ z-z_P>qF6_o)h~H}dY2qui^JP@ZP4@8rL}Q6747ei+0mgdz|i?D=zQu-STnNP*~=+Srt<(Q+LHH zd26>~(t;k=J=&eS3M<&T)?kwjbM5_-81lX9bzZi+^KE+{x5+`1U$AG(%eB+;;t|6C zD#mr!l9twr5z0#1-v1vl(6xtl94pm2T~^Yk@n|5c)VphbGlN{OI^5ObFyBtzP2P=b z$PwU5Zk?k7-30IMy@m*Kpn;p?Q_{8qM}2(nP-|72E;s0wq6bBB}f@TSt zwP<;j+?8^q0aIvvQB~3Mgo^Ae)FD^>f0d4ZDl20rsK_P|p(>L{>OX+gHA;KxyLP_g z_JV#Z`~j*P{goJ+Sk#1+xT~0Jhq2pDEu|Q}&LL4Wgm`Xuf7)@ph1Spr7LODo73rnTb~>pBa>RU`@_E>zy^ zgiO-(ENQhl-?Y+BK1Wsn>9kUroU0*ofmcp>G^}cX4>g?%=j#-G*^@hj)85!NwmyRPkVOfy6zKp#sjiIsiym0h5 zyNKvx<~)0xWlXHr&Qmv4#)Q?{|0_XRvgQ{+HW@H7D)2_1`v9LK@BqH(iN0un02N}s zQCMab9mE78gPB(q_)AXsE~oBus7<#;!IQV3xP4BWPjHiX>*kkwO38!3Kd{s6jD8%*@P)NRp&b=z#=; zP!dWf?-HOzEl4_M5F(NhO+i6HtxTH%z+rKl7)G}Mk0(Es#h?zJFRxe)nwXvlvJFE^ zy%6loPz96ohK-}LX(I?g5RC-=2?h8^)=Zjm-%%4`WEj6kn@ndkclA_o#F$Yfc^?hz#Mmf%`l z1{zHu$+^^x^hDFCZ4Q9m-YNkPL;~tnV5vu8K$r6{3b#0bD4UuiSk?uB~^j z{>1Bc_zEpye}^*w@u#zdP70kXQ?i7K&5%vu($2LHNRC}jHC2W_aY|?;BZ^qC!}WR& zfD%#E(O_uNOC*Klyp&*!I!|PaE{AueZXrgp`EObEMk zCPdg==vp(A$lc_B9u*82<8C0R=LthNS$c_)3^bC~0;d3h+JfqtKSaM(%kV`mw+^w~ z-2xo2I5w;Az`3x!U#Y$gJJkN^3GU{bOq1nd8TI{B_?Qv|3Snmh^fP?dUTKhl>Ih;Z?#p| zAlo8^!(-d3KgZAdcfab^h}5|W^04iZ-T5~@6HtRJaoDm&)ksu_N48aq31+xCrkxu% z?bqkJVZYX$TlYEc+~>7z)8@D~?bNC}zMZOlyJOq8W1GkR*RVI9{fa$%W7)G;o2x%{ zYuBn%yJqdW^=j6wUxtEr-fEltvIYK#Ns^PvVqLe@7 z&&f#XeW85H-}^3=KPC5lmk;H8mrh2vCMTm;x-}_(@2mVl`IK%=?)$#~^D2KiCjJvM z6}vNRhsEJ>!5R@yw6JpFz=Fm2N<1X-{>ZfJlnR( zvw4U7@j360cY6$S@7*Aa?Alzn$mXp(uKlfRw{z3JjoXHMb_;fE)~aQ{Uak6d?9}G2 zW1B!nyA8A`BpNX3xkA%31`xW^fI-(4impgLNiOM0LPdHe1%QUA@f{>25|9K*K~j=R z2cUwfDpCg$fcI!84Fy_8Nqy_b7<9n=Awxz6+A{5oBz1>G=NXA*eAQ55=b%0#ZBo;K z#f8Ko;xMs@I82-r(GCN&C!{l2)V3@nolozXhPj#dkjYsm_8xBb>i@v!vL8dfphZl6 zcx%VKa9qOyL{5)!1DEMNP3>h bool: """Check if movement is illegal (during STOP phase and not in safe zone).""" if current_phase == Phase.STOP: - var main = get_node("/root/Main") - var gridmap = main.get_node("EnhancedGridMap") if main else null + var gridmap = get_parent().get_node_or_null("EnhancedGridMap") + if not gridmap: + gridmap = get_node_or_null("/root/Main/EnhancedGridMap") if gridmap: # Check FROM position. If you were safe, you can move? # Rules: "If a player moves during this phase".