From 38a7ed85b0111722a9aa8701b8b0d2285bb42a22 Mon Sep 17 00:00:00 2001 From: Bo Thompson Date: Thu, 31 Jul 2025 08:44:26 -0400 Subject: [PATCH] New art assets, work on implementing more adventurer behavior and making them work better together, and steps towards completing the first quest loop. --- .gitignore | 3 + active_scene.tscn | 47 +---- adventurer.gd | 30 ++- ai/icons/stopwatch.png | Bin 0 -> 28597 bytes ai/icons/stopwatch.png.import | 40 ++++ ai/tasks/actions/get_quest.gd | 103 +++++++++++ ai/tasks/actions/get_quest.gd.uid | 1 + ai/tasks/actions/go_to.gd | 48 +++++ ai/tasks/actions/go_to.gd.uid | 1 + ai/tasks/actions/use_guild_service.gd | 111 +++++++++++ ai/tasks/actions/use_guild_service.gd.uid | 1 + ai/tasks/actions/wander.gd | 50 +++++ ai/tasks/actions/wander.gd.uid | 1 + ai/tasks/conditions/has_quest.gd | 7 + ai/tasks/conditions/has_quest.gd.uid | 1 + ai/tasks/conditions/is_unregistered.gd | 7 + ai/tasks/conditions/is_unregistered.gd.uid | 1 + ai/tasks/decorators/busy.gd | 22 +++ ai/tasks/decorators/busy.gd.uid | 1 + ai/trees/adventurer.tres | 145 +++++++++++++++ ai/trees/receptionist.tres | 34 ++++ basic-sprite.png | Bin 0 -> 1526 bytes basic-sprite.png.import | 40 ++++ fsm/interact_with_employee.gd | 39 ---- fsm/interact_with_employee.gd.uid | 1 - fsm/machines/newbie.gd | 27 --- fsm/machines/newbie.gd.uid | 1 - fsm/machines/receptionist.gd | 23 --- fsm/machines/receptionist.gd.uid | 1 - fsm/machines/state_machine.gd | 43 ----- fsm/machines/state_machine.gd.uid | 1 - fsm/machines/test.gd | 22 --- fsm/machines/test.gd.uid | 1 - fsm/nodes/advance_queue.gd | 6 - fsm/nodes/advance_queue.gd.uid | 1 - fsm/nodes/leave.gd | 1 - fsm/nodes/leave.gd.uid | 1 - fsm/nodes/queue.gd | 51 ------ fsm/nodes/queue.gd.uid | 1 - fsm/nodes/state_node.gd | 17 -- fsm/nodes/state_node.gd.uid | 1 - fsm/nodes/test.gd | 13 -- fsm/nodes/test.gd.uid | 1 - fsm/nodes/wait.gd | 34 ---- fsm/nodes/wait.gd.uid | 1 - game_manager.gd | 6 +- guild.gd | 5 + guild_employee.gd | 2 + guild_queue.gd | 25 ++- guildhall.gd | 7 +- guildhall.tscn | 202 ++++----------------- main_panel.gd | 10 +- main_panel.tscn | 132 ++++++++------ open_shift_panel.png | Bin 0 -> 2729 bytes open_shift_panel.png.import | 40 ++++ project.godot | 4 + quest_board.gd | 17 +- receptionist.tscn | 43 +++++ speech_bubble.tscn | 114 ++++++++++++ styles/open_shift_panel.tres | 10 + styles/working_shift_panel.tres | 10 + test_adventurer_sprite.tscn | 117 ++---------- test_limbo.gd | 4 + test_limbo.gd.uid | 1 + working_shift_panel.png | Bin 0 -> 2705 bytes working_shift_panel.png.import | 40 ++++ 66 files changed, 1112 insertions(+), 658 deletions(-) create mode 100644 ai/icons/stopwatch.png create mode 100644 ai/icons/stopwatch.png.import create mode 100644 ai/tasks/actions/get_quest.gd create mode 100644 ai/tasks/actions/get_quest.gd.uid create mode 100644 ai/tasks/actions/go_to.gd create mode 100644 ai/tasks/actions/go_to.gd.uid create mode 100644 ai/tasks/actions/use_guild_service.gd create mode 100644 ai/tasks/actions/use_guild_service.gd.uid create mode 100644 ai/tasks/actions/wander.gd create mode 100644 ai/tasks/actions/wander.gd.uid create mode 100644 ai/tasks/conditions/has_quest.gd create mode 100644 ai/tasks/conditions/has_quest.gd.uid create mode 100644 ai/tasks/conditions/is_unregistered.gd create mode 100644 ai/tasks/conditions/is_unregistered.gd.uid create mode 100644 ai/tasks/decorators/busy.gd create mode 100644 ai/tasks/decorators/busy.gd.uid create mode 100644 ai/trees/adventurer.tres create mode 100644 ai/trees/receptionist.tres create mode 100644 basic-sprite.png create mode 100644 basic-sprite.png.import delete mode 100644 fsm/interact_with_employee.gd delete mode 100644 fsm/interact_with_employee.gd.uid delete mode 100644 fsm/machines/newbie.gd delete mode 100644 fsm/machines/newbie.gd.uid delete mode 100644 fsm/machines/receptionist.gd delete mode 100644 fsm/machines/receptionist.gd.uid delete mode 100644 fsm/machines/state_machine.gd delete mode 100644 fsm/machines/state_machine.gd.uid delete mode 100644 fsm/machines/test.gd delete mode 100644 fsm/machines/test.gd.uid delete mode 100644 fsm/nodes/advance_queue.gd delete mode 100644 fsm/nodes/advance_queue.gd.uid delete mode 100644 fsm/nodes/leave.gd delete mode 100644 fsm/nodes/leave.gd.uid delete mode 100644 fsm/nodes/queue.gd delete mode 100644 fsm/nodes/queue.gd.uid delete mode 100644 fsm/nodes/state_node.gd delete mode 100644 fsm/nodes/state_node.gd.uid delete mode 100644 fsm/nodes/test.gd delete mode 100644 fsm/nodes/test.gd.uid delete mode 100644 fsm/nodes/wait.gd delete mode 100644 fsm/nodes/wait.gd.uid create mode 100644 open_shift_panel.png create mode 100644 open_shift_panel.png.import create mode 100644 receptionist.tscn create mode 100644 speech_bubble.tscn create mode 100644 styles/open_shift_panel.tres create mode 100644 styles/working_shift_panel.tres create mode 100644 test_limbo.gd create mode 100644 test_limbo.gd.uid create mode 100644 working_shift_panel.png create mode 100644 working_shift_panel.png.import diff --git a/.gitignore b/.gitignore index 0af181c..c026d40 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ # Godot 4+ specific ignores .godot/ /android/ +#limboai ignores +/addons/limboai/ +/demo/ \ No newline at end of file diff --git a/active_scene.tscn b/active_scene.tscn index 1ac2f5e..57f5b92 100644 --- a/active_scene.tscn +++ b/active_scene.tscn @@ -1,56 +1,28 @@ -[gd_scene load_steps=9 format=3 uid="uid://dfa6ep4o53s08"] +[gd_scene load_steps=7 format=3 uid="uid://dfa6ep4o53s08"] [ext_resource type="Script" uid="uid://cci652umkym1f" path="res://test_scene.gd" id="1_8p2cu"] [ext_resource type="PackedScene" uid="uid://cd08dp16bixfv" path="res://guildhall.tscn" id="1_fcxuj"] [ext_resource type="PackedScene" uid="uid://c8ofw6na082gv" path="res://main_panel.tscn" id="2_8p2cu"] [ext_resource type="PackedScene" uid="uid://dly7in8ql1fn4" path="res://quest_log.tscn" id="4_tro8a"] -[ext_resource type="Script" uid="uid://blo7tb5135vfm" path="res://quest_board.gd" id="5_46fpu"] -[ext_resource type="Texture2D" uid="uid://bldpiytpdrge6" path="res://icon.svg" id="5_eenn6"] -[ext_resource type="PackedScene" uid="uid://drrtypncppjps" path="res://quest_board_window.tscn" id="5_uh7v7"] [ext_resource type="Script" uid="uid://bnbljf6u2d3kh" path="res://visitor_spawner.gd" id="6_d0hfk"] +[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_d0hfk"] +radius = 15.0 +height = 54.0 + [node name="Active Scene" type="Node2D"] script = ExtResource("1_8p2cu") [node name="Guildhall" parent="." instance=ExtResource("1_fcxuj")] position = Vector2(421, 161) -[node name="NavigationRegion2D" parent="Guildhall" index="0"] -position = Vector2(-8, 25) - -[node name="QuestBoard" type="StaticBody2D" parent="Guildhall/NavigationRegion2D" index="2"] -position = Vector2(942, 31) -input_pickable = true -script = ExtResource("5_46fpu") - -[node name="Sprite2D" type="Sprite2D" parent="Guildhall/NavigationRegion2D/QuestBoard"] -scale = Vector2(1.84375, 0.4375) -texture = ExtResource("5_eenn6") - -[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Guildhall/NavigationRegion2D/QuestBoard"] -polygon = PackedVector2Array(-118, -28, 118, -28, 118, 28, -118, 29) - -[node name="QuestBoardWindow" parent="Guildhall/NavigationRegion2D/QuestBoard" instance=ExtResource("5_uh7v7")] -position = Vector2i(0, 36) - -[node name="CharacterBody2D" parent="Guildhall" index="1"] -interaction_range = 100.0 - -[node name="NavigationAgent2D" parent="Guildhall/CharacterBody2D" index="1"] -path_desired_distance = 100.0 -target_desired_distance = 75.0 - -[node name="Queue" parent="Guildhall/Receptionist" index="3"] -position = Vector2(-6, 186) -direction = Vector2(0, 1) - -[node name="StateMachine" parent="Guildhall/Receptionist" index="4"] -starting_state = "Advance Queue" +[node name="CollisionShape2D" parent="Guildhall/Sprites/CharacterBody2D" index="0"] +shape = SubResource("CapsuleShape2D_d0hfk") [node name="VisitorSpawner" type="Node2D" parent="Guildhall"] position = Vector2(505, 870) script = ExtResource("6_d0hfk") -total_visitors = 5 +total_visitors = 3 [node name="Timer" type="Timer" parent="Guildhall/VisitorSpawner"] @@ -62,7 +34,7 @@ offset_top = 23.0 offset_right = 1903.0 offset_bottom = 185.0 -[node name="PanelContainer" parent="UI/VBoxContainer" instance=ExtResource("2_8p2cu")] +[node name="MainPanel" parent="UI/VBoxContainer" instance=ExtResource("2_8p2cu")] layout_mode = 2 [node name="Notices" type="Control" parent="UI/VBoxContainer"] @@ -70,7 +42,6 @@ layout_mode = 2 [node name="Quest Log" parent="UI" instance=ExtResource("4_tro8a")] -[connection signal="input_event" from="Guildhall/NavigationRegion2D/QuestBoard" to="Guildhall/NavigationRegion2D/QuestBoard" method="_input_event"] [connection signal="timeout" from="Guildhall/VisitorSpawner/Timer" to="Guildhall/VisitorSpawner" method="_on_timer_timeout"] [editable path="Guildhall"] diff --git a/adventurer.gd b/adventurer.gd index c01b6fd..92ff0ce 100644 --- a/adventurer.gd +++ b/adventurer.gd @@ -1,19 +1,25 @@ class_name Adventurer extends CharacterBody2D -@onready var state_machine : StateMachine = $StateMachine +@onready var bt_player : BTPlayer = $BTPlayer @onready var movement_speed : float = 400.0 @onready var movement_target_position : Vector2 = global_position @onready var nav_agent : NavigationAgent2D = $NavigationAgent2D var data : AdventurerData = null var interaction_target = null +var last_position : Vector2 = Vector2.ZERO +var stuck : bool = false +var stuck_time_remaining : float = 0 @onready var bubble : SpeechBubble = $SpeechBubble @export var interaction_range : float = 75 @export var stop_range : float = 25 +signal navigation_finished() +signal navigation_failed() + func _ready() -> void: - state_machine.actor = self - state_machine.start() + nav_agent.navigation_finished.connect(_on_nav_agent_finished) + pass func _physics_process(delta: float) -> void: if nav_agent.is_navigation_finished(): @@ -23,15 +29,26 @@ func _physics_process(delta: float) -> void: #clear the target #try_interact return - var curr_pos: Vector2 = global_position var next_path_pos: Vector2 = nav_agent.get_next_path_position() velocity = curr_pos.direction_to(next_path_pos) * movement_speed move_and_slide() - + #If they virtually didn't move + if !stuck: + if (global_position - last_position).length_squared() < 5: + stuck = true + stuck_time_remaining = 1 + else: + if stuck_time_remaining > 0: + stuck_time_remaining -= delta + if stuck_time_remaining <= 0: + nav_agent.target_position = global_position + navigation_failed.emit() + last_position = global_position func approach(pos : Vector2) -> void: + stuck = false var rid = get_world_2d().get_navigation_map() var point : Vector2 = NavigationServer2D.map_get_closest_point(rid, pos) set_movement_target(point) @@ -57,3 +74,6 @@ func set_movement_target(target : Vector2) -> void: func show_speech_bubble(bubble_type : String) -> void: bubble.try_show_speech(bubble_type) + +func _on_nav_agent_finished() -> void: + navigation_finished.emit() diff --git a/ai/icons/stopwatch.png b/ai/icons/stopwatch.png new file mode 100644 index 0000000000000000000000000000000000000000..860d798ff70f6447b9930f7812ed97b33f2de6ed GIT binary patch literal 28597 zcmd?Qg;$i{7dQG$NJxhwT?0rXEjdcfkP-?=N=k=x4k}8=&>*3XfJ(RI7=R-w(jgBbXu65U%wGf$o_Bs3P^VuDHOJ9rXBFjYp0I1L?bt3?Pg8zg9WF+8^ z?V#a9@CW39k=9M1qMvOE0Js3O`VEsH>y>=+rof-WUF(W!Hy!j1RUAZe=8S&{W*7-w zGUB#pmeeS{nkp!mxrlHtKqYMIY(>vPS<~1kNH=` zwXHiVcQ_Z;jzv7FC(9$x#{Byr{o!U-$usvDBq0C$$O9W{wov|mpG)-Kz^xxeEj|DH zm7fUU2mVKfAvZzcA;{=QYhro-{SORKh5h%vTig&*;1YFni~D~IQ3J=6|A%2ToDDFM zUtFvCZwnwpssBGPjD;ht*zpyBEX?~7U~08HK*f;9Qafw_IcCETOcw6%tpoC@3-9dL znvR^HR-ohu`8*nBw4qqfi$v?yfj-R%!VkYcB7i_Q4MCi`TQt-T8n1kE?3p{@jG}|xKNlp6i-FE;?!3WPJ!n}%o<9;_h#Vyd_=(3 z$f&*IE)**UA&LS#KowOXJ{DNh*?Rb+#g#^{NEJ#A9NMpEGGQ<{VTk+%d^r=|s%75` zT7ARY0^1?M$RH6l!r%=M1wO(@kw_!9pGPrr2cj#yzSNk|l;gt>yZEF$yCy{NLBbHh7`tw6IIh|&_MR433kYp98@1XVdRq=+sql$&VAdL?=Xt110}0R#5o$iA_hL+z_;Z*DjvTlZ_uBE+GnC z=>Ok8wlD(EAjHdE_n<&O*SidKHqrwW%CPL*npfC~4J9%?X6Ntv?;jt?xv~AwCFkb~ z&{LS%OiIf~tn7u2@HB}iN4P9^a7Ao3QtzBjdU9=fX!~px2>T+hYs(zvfr=Pa*Dc}) zuh5mnW6xg@XcEWBF+U|2;jI!NH0H*T51(s*-pkc?u?qkxO#Xjl-DzR%|M!wcfVUDx z>&iLV1`js*8XZGvEGXh!&8cv!i@L>50rX-p1B7q zF$o*6&ny8cxw#|tA9NmmvD&4?e@O`I{7e=^V(S3=vsR`HzRoWRLaiUpao0LD3%s>c zxXF0rIn;vR4*;qpd2Oyqg1j_ki`M$TfFdjFE&U+;4{qxNCm_gG17!3`;5npMPCJqU z!ctq8czMD1{Qt@25p5Un9Ktr&$Au%HL^hxUvOx-Tc%5Az=}0^F-@Y|O0*JwgHLI#) z+v{$JXY;3efTc&(r#k_?=TbVCn>=u30@JK0%y4Cc62A@{-=7!=etWRanRa~irETT( zB8Y|F{s3#EDy!(x-p{kC!m&&kuhkmw^KP$Xg7Lz4_@+mFOpWg*=nB(TxrD1Inje|AcR zJ-a%cA+*3(4kMEEJbd^HPmGHN*Z{;4mNI!o|4e-N%_H==2iVx}1F{~*>RMt?#|!B?-^_VA4tMW6xDWF& z3;4OC!MB8nO80B~^^+qnrh(LZ{*pr^gvh?BCfT1orHhB3!vdDa^y3;30HGa02-NSV zgzyu_bVD9hT1bIV`9OsoJNIn!!6c5iw)Es8UJ;^{w-D$=x1oIQGD-M>=Y$fG01b@x zOeHy77)pk9?&CE&Y6Fc^5EP-@{<`pV`a0rH+YTR4pfBk}=KhcDA{0B<8R_@;IYVbb zjmSmMRW(T`V-G1%IV50pO|P!29fts+13^cVo<~#|UbGX*NkHID8?Huo0 zFuNVUTJb^H+|mx~ZKei_*=A(h7W06W>p#oCS#v}?1#mI5l6su8tGWe8bRM3%K`bj^ z-JEJ$8tipaZ}`~&-RsY=->GdI1-SxFNnMH2Wi4>-zZ0o^$p|cYKz;IVS!Y%xv1A!*MNc&%;tn0x3Nq8L)P<$(d# zm^?3@;IpWGNi#VR(jD(lZap{T30Q_C5`|GJ4#?B-j7$tJyM5Ma!T|C3Za3x^&&HlC z?LH;OIM27e(6iv|?=Pe6z9l$9xy`(QWs=fyWo+^hZb(sy{st-Fb_IoA*767fEU3K8 z*x}nsS62&CP|!=_$7Hngh1Hr~!Un`?*(+ujFZS~=htjw!)81D}pZn~)pw9dvf4Wy_ zb<&+W0Xfug5!CXx!3adB*q_o%k?|1KYhGLj7|4;F!Wd!(j#mcUE%q({E{g zcpKFVnrcIic}zVsfcp2X{dbyCP9ix5#1`QD*xJm2JVE}$eI0(TrA~kvl_|={RQql! zEy4J9LneqXj>$LwBD-_`lq%GdiJ$Qe%#Qr}w99Dvp|Tz~Ue~z&p~K@r<^erMNB^W zRMen`nh#9}?`An|oBHBVojM?E4V?wN?T%B9=Ym?yE1a>`-_sXoIxHzPGE~Rh5p5KN zQr=r_!6d}O;1jvHnNAO?KN{gz?FK$5D|gm!ZPc^w^T-9`gc9rDQ<=8+m?oqk5m)1w z>&VDd=4a-Flf54d{qzSehp!vLBLaC2S~5bF)`Z{C00@sE_r*BzGd(Sd;cFxB@=Kb; z6tEsDPqQbJvrd&EpEM2f$VKR4*x=RnN)MxwLu5VbJJjrh4#fRMe08VW2`pDS$KKSx zfnj#11HulpI^R@}J5Tvnj5Axcq2uO*k2-^i{AjfMpV}O}HvC2Z4aVaTJ^~75(uO`P zq`p|>-*<49Yr7sG<6KlG3#2eEna=l|xmv0Ev)2WNwDjNp$!MDA8aTV#$vN*X6=hDY ze!JgP?se`gYHO@EPUKHG`yJI)imwx?A77%`kN>u_E!NHm!2qu_S!>h+WOOTXL>n#t4^=FE6vY>6Lb5FA*>4z*N0@yxz1cOOZ_L(CuT zN>e5P)hvifmK%99*LpTC`Vga-c06LHD6}-G=Q3HET$Mbw)2;C3(XuIyCkaUm!Wxd> zPai!lPxw=^$Kv=~Z1VMIvEZkZNwIe>feSh2ec$uVP#XT)S6NRJQ0A7@g_xm6nsCHd zM*N=Q?E5TcqQ&!Cw=9uUPjWO(>z;C^%6gs+Jm4Awtz+5SDpx3YBDds2tKzuSlL7s% ziQn1eX8VF-=<1wxa+tw4%OAXV!n1h4P5(t}D$GU8qEk&Bj-uB-t@L+WW5%zTX(%iS zflE}6a(1h@ijC4Q8P31AZqjze+I8{MCo8?l2}!iilV!Lf6qW50%8e-}B4!J^jcn*%>pH#Bt+svlhm2LmR$YIElm*maGwh~Wjz z4qifxFR2Um#bUoPpcIxu9q`-4UH9iL3k7YiL`dmV1 z-}q-Bd&^x{@vwuGR^x$PA)YIlu0j0Fthwo9T|Vo<&QVI(N%oPM8nE#*yPx?lSN~vR zQ0k`w%s8vW6*mSc<#Oc?)hitr73pn$q~=QNyMN00JFdI?QN!|$Icte*X*`lEPP8-P z*{j0+t+Mw#dtnQMs&Njz)RbL_a1kdG()mGewgVCZD|L5%n1LocAf0F4;3``i#?3kP zLAWdamo?}s)&{2e%@iX(J_mN862JZ)ZPuT5tb(Xt=scGDs9jHzp|cTmqTo7bY=7xy zuIe4vIGO*PK=7V;ua9yhCNX{%d+h)9YZEDfW>*Cj&2}Xe*jNdmdPmzHot`K|(4u+& zSC;$Rw<+m1HE+SGr{h6~ImId;e?!8O78+|gR;Y_$uKi?QZjE;>beBR$Jaf=pog%r3G=f7n8E)JVVHbJR zMuE3KQh77g-`x6c?lH2buuwGD5mPDl2UaiJ!44$&n4C?N$ip~n7`;|%<5#a$|E{w+ z4R4mzner)C$<(!bG+crvF`mMcqvC1?=qOhxZB2pr?877Tz9-|(yC=Qq5FX6_N%;hi zvbV@`Vt*G0@X05SB`rfew#O=0{c>tXnOquU&QZZv2hDgY&3L=tKn%}SuRYV#7nBo| zC+U8B0WVz`8{Q2;cZ7UZKDi@xyZ4;1cIz4@7p6<)1P(pGQ1WD}u-qS=y5dyFDnE+k zJ2g{>#>)pz$Je{XR9>KU%wl@aV;fg_%z!=|U*t&`r&MX^ruLfZzxc^>4`o(IcKHa( zG5)&-shGwToxIjehR24t-YHy3JKEy(wJ(Ikw2msK!{sGbVQ9_6uhzOoVOE{Pj_aY+ z{NPO5CcVSl1BDk?tZ$aEt#Yg;E8RxZ&O;`6Ipth zdH*{=d{v)*!1f18IU|ntc}RQ@?6L(x-kALf^|L`gM$Ehrth&4d>uT@*^O)cN!GbXJ zt3(ALhAxfqcYXI=^x8Im&vZaI<71b=yWLD@yrjo@bjC;G?pwhf{&^0W$*Y!OD>k!&J;qLpU zYxA(T!YMLvV9e7x-G{|iH(Z$nf5XbTAdPY9M&ZP8YUIsYy8HPR97E(&vAl(b4t&{w<_kt*(KScQ0?+1swz5 zerleijU&c`X+;F-NjkfhtH=9LnmKDr2{K_?6Q2#$(vvK0(*VaE< zeNz*3VF2>Pj$&uVHaj{^om;n^mE(5Eu!cp1OfaVi0jQY=XLIB^T7?NxY0dJf3Anua zZutCxrF1AAp<5*PTkXDu9zg32I?mrU4(DQL+7zW}?1yvLdl8+R?E?Oz#7WjTs%M*X z$1Y$sbY5%+Fi06b`Eot_VKdEKMZhN~|(NxJ8+L7t2|7xFU8U zg2A#=`q*RA-Z=H1$f>+_Wl5Q9GU5Q+duqNs3!m(JNC*EkKr50Nrl3qebE+46VyZT! z)LOjRq)afNxmVS^@w^!*qJrA-&M3D4O7^Uq6t&6(3a8e{KU0VqM&z)5jQ^R6sPQa|D9y;;Jm-7R+=_imN?@$tSVp7``-GG*DPP zjMhWN{TwrpJ%aMMEv9(vP0C&xV*yhj=|NnLEW~g7U&-_pPPdZhlzpDGd&Sp>vO zoK5Qe7Lj*V(0bP}O-1`P_0Q-I*G4v=S8CAsyRe{Bn4RX^b>@b@Q(QzT;2B^?Kwng)c=%wm|q} z&A*L@&>(3H!du?UzH!=ZlRdqHy*4!(TYm$|c&!;NK&Ag3C6jl0N5jYi7$kxC@NjW_ zZjYqHwX#XYE!Qq4B#%si++cFZ@^ zDmr&!M;ro=FZ}*zZRUv%p6>M zFr3v%_g>y(dtQv~%3uM;RCC`Y^sj%jNs7ZlpjD zTP@`a+#PkePUk75+)HHJeA=!)H`_=;*ZCPtBuaF6_)oyRn|+M7+`FBj|Sz$&%i1v^@?zQp(N%iY6=zsNj?&#ro|(z}NR`TMI^)wW-Hnl%W9 zo42_d2#P#pSKnQ)=mGUbl3}8WC&PX0vdxJh_lg8IaEeT#eg}(q%W>vu32wi z;BO&lA-rs`?D8VEkxaU?pf=+;)4IZYrD~b)! zpdIXd+S}gO^>eKEYe#olg8e{4J?-L_M)e@7-rX6B0IWwg zdsK@_Ue=5+)$TtFH#nM07947iFLwwmPcMLBj2sjPGwMu_6gfNlnrmhoSYh!3l&-SN z98|WM^`RZd0%0s*8js9%NfPZ<$YZD_5M0d1KFoiRQzQ4l>huP%=SJ`PsX4N8v>+fx z{8Z)J>)kK5U0rQ(3ErmX)1zYK&&X_Rsl(&?+I+CDgJf=?*Pm@&U3ia}U##|kg5?N) zOx-b7_N6sqWWq7pLY3`^1m*gLzqr|Q=w;sa^G@e0nb$8lAJMqUUg0or_7aXt@%tzn z{%2R%YWXa(9u7+AA?ZuyQI;JzkE6fo<)d7lco!2BQKwaoGI@pY9&(oJ7zYQVIz6x; zjelHphXJmBseJr)yMiJG-b0&nZ~4bhPS)c9-h~|yY)h5A1`H|R|GR015pgAefMsuSAwyKgn?j6=?`BUbN z|0Q_Y>c3T~8(@(H$LDpNe^Wq5-n zcvrr`)SBgem7G$LREn1r@rhBXvilT#tZ8+}LBvzUJgiri7fkd?J+#=7MK_AJ3Eu%d z9P4KbTL?*m#lK-4xDpw+ur z-bunFLo)3Zul(fqx#ga%+{F8ohpdU0aJE{iEGI>Jo@K``|G9&1fdyG;t>)9%9;slD zP|cK>-_V$y2#a9wbYG-6)G4qWP@*IIb%sba&k>DPOwys$q!SxJ8Frt~W5m5G_A#p! z+iL6=n?U}9nTl#u+=F(*k40}2b*ut?VpfA`@U&X5QVc*Lx*#N%=iq&f5Or6F=y3Q)8 z2IJ(?oY$A%lSUsR+0}oqe$qIvTP><_3nsPXliQ|ITOK1Yq1c4{)_n6ctsfnem8aQ1 ztNabXGRIzTsF&f;&eXi$*a|);Fts(1bhRm#8KlpK++DJmbhRmgG?_0oA%G>Q#bi z`4Fd+-_p;F+hSC0#DJl8EQwo#N0}66LAseI%vXDiHv2| zNnyrhqvOS9Z|8YB3qilbBra9>*oZ9E053Ap4s#+doZP{USSqv7^9n5gyvd3XI+ZBU zf9PdhmKu4n5Gna5I?xVl*L;QoBDxf~Rg8H-YfnBE-ps#wqo5}Oz zmN4xG=kEf})TB87*4zan!rTkxOvZuXP5s{%j1MxKU>FfB?@+4WyW*PJ638^pyKzlV zQkH8nga@pS32b~V!*xr4n->>Z`LLY#Z2E}NbN=Q*fR+!AB{BVF!w-fHdi+LrDH9E! z6=)T;f06GqV9q@0FXWHt2+Wk0I3I4 z6dLzaACYsbIXyDHq zV?C;Y`yiTmZAVlJ+#6`s%srQFXU+xyPc=#3i;Q5@l_ckSxy+)DJ3b2miWo7I>Y}62 zbPz6{qjGEs$o**+TKfFN<;@zXzZb_=m~`SCKtgiIc^JkyeRr?9Wry1J^sZFIlkZk?(m)lu%^iv!HAe41G`;#etMC|>q%7y z^UHo^ltL$ycm;%_QEtz^$n)arKKlM> zPX~38iEKG1tm!(TFn#3-?kd-IE7rrTh3WjYUpSIy$zWtwwRfpaSAOc?u2gsFTu*7o zQ#>x7C{Z98I|c92F?VO3E%ANIl0NxqgY{gW1nI)bE>A(wPi2+m%WjFEa%jY&G>4=u zAfW6nB0X$Q4N<(s)uV#LpHvVwHmD=e@X^EzJ>;9J3aA86wjCGAmdNy-cpPb%9^(Lq zH8_BD*eJ0h-%}wBD-$--C++9DVRT)V^(l>4%~2c9fpv5(ACm=ya6aq|L>jHYV%ku0 zBExwf(V4l9R~NSIJ}UrMCG@d#_Yz-M(_cnMc$!P{WHSEtp8ciF!}rANR&D|0%CNUc zg%tJ$H41zgCQ;U(NPcHuh&eH7PzRaQ-+Pjd8{gQ=xQX_SAho5ys-gmpY6c@qBKPSwy?OiF3@&&tJDZ5kany#w3OsZYfQj4vk*i*KhDH4*_MSX+2aA zNe_|e7|GmAq%>dRcX_ni(_zy7(63N5`zAgQFqXLMa24S?@Upnsq^U;= zpkIDh+FtkKI1EJ)%7qwQuEpm^dk7unU*yt0n*75`Z%1ve})ja{3_?9#i{67%ULs=ev4_kHaUQB1h@l11Pkc)OG#L6@hlqYL5QN6@wy z%F;3JgA(ZEZL|WA{h*0Y13kTd`R?DtD}p-$-QjI?VsIo-#Y~6^_*SmG#zc46In*iIbQNSO@&zSY zT8QPiNPKl+I@x4V4q@&(dmEDVRA33PO}ds^cduo0edxjGvZYZw);fe047noMWC!UG zeJ6iT-ESsZR)STbD*DvbMw8Zh^x+{hW*&6UuE5b=9!ag!&eX9oGk4uf-r_zFU%K#E zR-D+##}p54tCOWNdi%~0KhO@bZG*BmF%bfp2Fq^_fvp`MMV68P6_xo_;hD>$P->JEbPA0)d2uxv=J{c-*l22S{aC|TK#eE<6lq?K{1Sw>^MQ+%^tGE-T+=XhX z=K9g8izReHoImNz%8@L(t3lJ_%uwgBAuvw@=o_)+#m_&O2v8tcIL0?Xdi8x-T#=e?}m zIE`^&%R|dl9+k|orI}SH7TZ5uXkP%?x&FD1py~fxN6kkH7$?=@V0klt`HB|{wYJEO zo29<~#3qq$#Kem2YRJ%SP=ZZe%9!?sVB@((Yj?`tI@NA1W_7@-)QQ81xB6aaje(~t{yQ3h{fSZegq(rX+$Bz^o{BorOFsC#V)Y<$4n_C9p= z!g@XXkP$1EQRh=TuPQ67SILB2(qy!Re*?B3 zo@Z>c0S3=Dw$S1X7*TYD;}9!yRzSO0m*PaQ=-w`DR7!us2PR^h}az1g$MeINZ;|A74rRDT|%W-Lt6=_0! zd$B9%nK>18tSr1!02zqto+Nz9kv3&$KGDM9m115hD_kv-@#( zS(Rs4I?az2DAZ%9yF~?tm$yD%6-RRN%`oG&(yS6cxw6XKK&~{_l%F>;$tYdMKGaKJ z=<7e|FfeZ4+Q~7n&$E`IKebdf9=rQe0BoMyR%?}KPv1rZjRw2>x3CjBO$4!B0q~0Z zAjsH0Kf}e}PZ0CRk-6wNo-10f$nTb32G8iqymVo)1Xm7(aZilMJ6@^<42ALkdMLn< zljr)tFM>gD1;U_rINgs5m=*HY=KiMVMwJHc=w6aez4ax94`Bdd<<+!dLMjY1LirNc z0@=T{MOKL3`bEf1VT5#wO*D_beTb2R+_}~p{|$|{06wd9oV7Vk>`cb1Jy$ef2g+1{ zASTR;t`T4R={kgXGNUZ!>EZxNIl&#-J;;tW6qFDmahg;{7hnbDNkENxoA3hnwmvp; z6wOAgMO%v-uHSskzce7%x+$LLdOO4#TI$-w^s*M~2_Yspc+KiaDwd)Gsza}n0!&l@ zwa016N9&tN69eedp$JKoXR9AjmGB^R zTU=7hBRl4-+e7nBhqH@z+(hi>{XHA=+|k$n>w*p6&-bKtz<8>FsJa`Lz_oQC|*xv)&XBXRC=hQauVvqR#bXIqOakJR@0YQ}qUoB0?U#u7fmrzYb z*5WD{NEr-Umsj|2(*Bv^(1|kK!=nB%G~O z!!XA$`I&&Gi-cK6WlOBx*qh`E2S|NCJ!q>UE?<6#!3CLf<}JFXlebF}KGT|&Uk5&m zD{U%ZbCz#kJBd`lSll^EZ=QbzI?q=%Mw?%QmZ)Ne@`_Z0c>_CPrOn2?-T#HLKe#Ix zKu7L$_s=92R}OiWyHr%KTf|2+1|k?QKf&O}AVJ6%AHBG8US}=dl{2a*1!z3_hdZR{ zcH~gsB@D&ePiHA@D|PkUa**fX{y(BA$iB&oj~&S`XAx)VrSEQ?lWj_Ls%1DnO$ob` znT->M#vH?$28QaA!2aU%p6-t~=~5WAo>%59ZgU`JGfNw98I6zt*g5XFr-I*3-$pUelN*P>)-Hv|Dy z778?S=mt0AkPynTb(e1zHvmLiK#MP_ zHy;(jqhl~64yZ%8^2q&efa+^?D}c3=O!{?{fvXX0R=7H<2Yamc;(O66R|?=eDVJM! zga}`m!4@YougH=tppy68k%}QZ1>^j$Irs@0Y1EtD)$5WulenN&^XW;2u^uSj!$S)o zOOGWz5IZf379Kq-gb-cKL%=&BKTk>lSaD`C2$~hPfA7W90j}Wt|F~TQ8sHnRK7Ac8 zToA6^zUa{K#kWsko{z|f*-Y|~QBF(Gkzaj@uzzsx(j8;K+qSkn!hNpPy3j%UCO6s? z>K*aI3lswSyh)y3yWMFJo;xWh00fy~(;}11?XZSKk8O}{Ll$TeNL&<0cj+j0B9sCA zve73IJ7^jRl@iy%9`jpJ>@IZUm-^mm3t{c>K)vm~_6Q^3uvQhRNH}sxe1mHQ#(8xH z6!<01Cz}`^ZaIGB8)PeN4|x!#@TSCRVjk@@%KUjt*s3HBC_)~5hM_nLWmvEgBRGNY zT>sInL$Ybp#aU$`XhSBhKQM=JaDaqB%hId~R?EYzx=jNzXC5z@N`69U%*Bd3+&BLS zFGhedl3>)q);;7 zCmSyf8e?6xo-yi7WR&E3AmV`VK0uyO4SxRtU?~+lF^_8JLJKVhxrgU(x`%*wid9ZOv1KRLi@kk!U%{#!vNG5l85^^9+)7 zUD#?7x%AO%eV1KhkHUooVf0!dPR1;U1&UFG?g!10xg)pam_zh73s=BKQ&01k93a^I zVP5{aXJYiry7C+PyX(rJD;dBs!&a@x@4_{}{mun@NB69Q9eGzdN~ELA_&oJ7Lb%KeqwmrI;QUoa?Z5M!Cx7@PY*Z}4c5E6V zYb;0ct5Ab&!P{@10K|B}vp{_{NAF;^#Q8p0a2Kj}>2!jI(}8nZOu>zL`bFjYEborR za}W`n*lRk9ci(aYx8@dCwYNS|Dx(8QH{MfW1wo6GrqqX?^&!^f@Ser* zq;~P!+L}K;%(#$91*{eRQ-LT@1(=HtGC>vCy{%j`Vd`&*eOi(_t#HoEo(8b{ zYvT^>tujV`msPtejmW=X8~+asDbF_u^fgjuVQ^Eh&tHgp##r;%XcBUd6$qXVphokY zkzi>)4`Tg%04BgpKy849U*dlyfxjLf5nL|zfU54cr!uy>+B;o#7a;ZlyV@-8oKuvf z)pUk3f%f!&K=KIO-gV-^D5%-nrod)u#=X3>Mk&@TVwz#z#(qEA)Ypc@g2Y;fPAuwl8hrH4uJ&6l=$0N%{6L-YQ}Ru!K6%FFTcaS zeWEL9XG#MWyQh56oIsU_5e=u_);Oa4Jt5(|HI=|+m#^Fd&KG$;$uE zXlPDdL#H~cKEzNeK3w=F`52*b{YRkVIn?|*cLMY=?cv#Q#0d;JdgKv~?cj7W`2AOi zVld2_v8hE6zWt_{b`X|^`*3n5i{*ubgOgoT?gYp;<4&afuWp_rLx z3pt>k%mrz)8CT~ZXF&ztR)%_ZfFqFtkS0^?{&&P|HcsYh4oJ~K;(dUa%rOU4N7LW7 z8e?rTuSEr)+oq=l>+B*BbR~SF2tmrJvz3h~zd=a24&35d(n&eCcv66qhhEWwc<>L( zfl3mdjF}P#+X)?@2?-eH0EfSOXRn!Ws(riS2-;|Epx@x(NhlUXWsS@D(%bAZZ~u`M zLKj2f(-Cw~EH!lF7_rHKQsF_n-IBDY0wfu3Jk#+_D>F1Uz9^y71DY8D@Wy+|2ODWX zoCt@s@)KI*u+xhFeZ69GrS8myeu*=s_0E$!Y0nmi^n72a{xcc$;9*dh`>{XhQtE^; zfr#MUH7ACk(I+1eS-uWkEP(p+{HslA_kO2LORJ%bMEH(n)p}U?Q^2wZ5~{94nT)}e z&S3rh*5?uHO0CxY>tD@am_%@NDnf}#2qy|bHH%1H4X$?x?>~kc+)*sx_gZ#4vfv7$hkpezIJ#=x z%iztKBg&<~p`uaPMz=@_Drw8=`WJmZgR|qu4$p+Lr$FdS9E83DHE3b0ZW2R=0{vcp ztYxzj;cGq-TruT3Y(olb+7lF$yPclpI%Iq*_&@OxUm>h=Bq2DyCt64&C*|x!v=h51 zCuLbR36K*EL}+dKn)CkB#em$?)QK~|E>DiERqjHTqpqzOIKuPUpRKLG3Usj1PX<$@ zLHRk1LYpuSVed+^aUIa6ptx)eU9P9d^#1P!3ylvJ%Iu&g;A99BkcHY>h(knX;AF1k zfSg`4?@7vGP;n;sRQhozs2UILz)uy#>~%!RN<4Y5Hdk=NP7OjUt1G+=f^P;+m6jjX z<{pWmCEKS#Thjsej(!&{VheR7Yi&ZChTpn#uq-KdcLYAFUxbf%TZi3HV`(uY0U+|% z4=q6N3(ASEPD-zN?TwaNvXEl4Un1UdYG|Hw z^c;(^&8XuW_b9hE?2=G8C1m)#b0$Fj&Qv5_(Y2ESy)1W^#MR@vyvJj z_feMTV4jj2UH#)v^FK)V0H0&q`G(>+FWBWFg&^phC1RwS?;{gZQXbh~0Feo($o>>; zj1{cEkgG6aQAc5-lj!Vp5@^v5v zMEz- z-4A@vc)Uc3wcvB1(st^F;I$yr*JA?^sNnD?cZ^^CxvrP-M!@MD+(Qtwq2@diDves4 z({LUGOeMOeVYifwXd|y(Pf+AM-O1zy1?<0r{t5ycJrr z%0nvZJy@A=00y*u7pV}ODgV)S!-CZ5S6`x3_&^H}_M+sUTlgygM5bOe>He{N!h$LZ zG1*EY3I%84bWhg1x%r`(apMO1?jtNHH*a}NiNMzgjkHUv+#revz-cdyyYox%Lkryv z$P+4TzhslV&TL1;@lCa*9fpz-$|fHFgEBU75|V2x*Lge^5!gqI^>YIXdj@NskW(h$ zX}~_dgs20@Kp|ePrSwwooZ;0IbXV8d*9p)fx8?pl^3rFiHb`p?f0BtygnZ)E&LdAq zMdFANlmv#Z@#}jo*TAH?{Zymw*6w#itv(~-T{WG=7 z&!vG6GY4-0D8(#rrumCHLxt&6(sM|E1t55%rWW17OX&lSy@p~=Vi#Ve)!9AzBFEce zn_1wmYg+_w=lE8I=uo|Nwlaz$M;)?a;`#j7pCCF?{}bzk@v13za75Rl%n`uTc&IFS zt`abTjVXSCqZ4$yGcjVaEtM7}24^%Gdh?!|YV$q}1BfnF_R+nH7r4HuLdV}lOByd?;w68EK|?7-?L9lkq_r3tg}3R_1aAO(7AiawfiwF=dL7!tvg9?m4I9- zu~zCaVwIZc@lSCs@NO^w)o%~$F8rNZ69dih0DNN@5jd;oTh}=SdTp(Yc(pW+$62Ym zISpBU6o86wzO+Opm?KISI5>{pp4O+y#o*+iO*YuHmwnJHVIT<`C9xDo`a`YHw5Q?R z=BvNw{3jL)T`ozxwVy8^QYbxy`B@o>$jtB)>a|jPwXbF^7!~x6!!TD#(rY|t)zh8R zbQPNg1d}o>RlTm3J3uMW#Fbx7Yx?%ePW36gHAH=#!)q9-v}T`yVn%O=OaJRP*S(cW zC)9~5-o$RJ0=v3Cy*&I?<8V7!5iE)0h2?m?kKYG$iv%0nt&KgEr4EMgKLFqhbxf1J zymvMLZ=cpv>%vmW0# z%1c?B)gPec9c6nLe_!Io2g<3JX!2(@p*BX0Z?3Ek8lKxBLC>ZDPuzTY!^jGobRi>rS^I>J78!stKKrQ0srR9qbbi3#s z?(T5n8+ef+#ZLqSOUpe#5KuzW=b=jwJBAdINEAe@=in~YGIRjmo&Umv7_ws+{u`R( z`U{nJ!qK4GN@J$@Wgdj3)d_w1l6=mS8k*w&eIJZd9h9lCDrCg9e+d9O`WVNWqtxR* zvZG&Oe4zDG1QP|=88GHgt0NIKRs&MZFUyl`#v$zEd_CR1KshI4*kl`1F6i1$!~0$I z|E?gn-p;QThsx1F(5bu1LmkfMcTciJp4Rw-EGqzFRxEK%SMt@Mx|EfFmQ(W|-q?2Y zFYqpHA{01EO_;BhWoQBwumzC6M%TyJ6~W`U4M8eVVtLN?N3a|T^2L6-AQ<>hNxfZm zSOgJMh>KRkngcBfh31hT$766G?PpQ+STC9PzZMzlN9X~Eiu#U%1r;=nIb5KS)cftZ zY>*e={qQO&f*DIy4n7)=&~RO1PxEfgcW}V6pVKHY;pf3@PYa?l4R?uVm4fF0eU1c0 z^w4TSZ&NI1Ij-aXY40olqI$x<&n}Cku#|{|#8Og9NT<}2A_&qUg0vtZy%=;ZC5^Cj zhyo(LDoTeS(xHHez=BBUJ^b$b-SaOzygMH_=ggV8=9-!78xVexBe0T?LVY+LA5dlm z5yCB zD%+^CXox*Gaxn#8M#hN>CdU6V)vpHaQ-LeGrXx60YpO)SUgeo<0?z#`d+{z9Hz7k% zSs{b`G_SGF7No*TLGY{r9(Rl9SUccQm&=ZgdMzm#h;SB>yI*jg6sBZ%khzW*LZ zEj;i3U6l#3tKS)BgiXsi84YqaKEN99rv)3`=#>B!!veZUI~#q@gFUs4$dh)yuwMxL zU=|%@qG$Kd7CTD+utErWVjwnp3UU>7H1g)_F@X|G zmV=%1PMrr^NoNX3Mh}(CgGShoGfqhwDjtaWN#$qWp!N!hAf3+QxYOc z-rg`}YRf6tinbx#M8|!p^_<8g*S*UCb==}y$%3lWxADhe_O8M@H$aIl@;T29ZyIn$l?h_un45?xhHTrbc3M6OGtAN|6U~)XDtb)oA zPmMZ!&Lx37{sUq z4|Pty&|2%LIDMP~j-k{T`H~hlxAeJ8`@3a07fMKY0!MKogz-sc%l1fW3Bei*8n{C2 zzSpb;wMS$?3<=Oi=F5uW)nsg^;GjxSQv4QMk~4=(Z0mu0%Z`5j1IOg^@{7XN9q@uv zv5O709jIVZ{LKG0_&QD4{$Y$EoL?i5*ZC`BziPhH;kIOA5MF0Ma8nl)v=f{-JNqmK z%N#Yh<&pS`OZ$y)S9xkm5uDt6!l?Tq@oxFR#sz`@L^spyA(qUnO@7z33Z|3|j~sza zcYUyuJ+v;#aJ5N0;JgGJTBx`WVnZ^0D+B-*(2FxMTWR7yJrhWb<$h6K*#jc)JwLmr zyZx3n%X${}*efj;XF@bCa$ZQZfg93Aj>tD-W94tX3qvN>$zu#@XUYisbF|HwM3@Cg zPV_HFfSzH<_Pn4xx&gj3tTSqT&EVh?N^F%3 z)nsg34i4^Y`K6qxY26}Q`^j=bE?p>j1ittGdX+J3EHUoKd7~RVlyvZbY*!V4b(0W{QLHT{V zT8-qOI|Z{U=utLERT$GnmiR!C*MC&-%}vd21p;;@7oa)n@EgRfjNN_htP)9JDl)_*S2&rM;V%wbN+0Qt8)6@i{?zcq(1wP?IgSwBgYmDhOAVRo7g?6Q2#as&4U`W?~7X^9$$eA&gFw8(H>@i&RSf z?x@`v=MYX~@Kly{a;#K-{qYW1nuvA(%t);U_IJ!RoR`iFM1o=!g&X?5)un;(xe~_5 zxh;jgQTU(Sy&l>{r^wgyFN911#3IED+8l)DO`+Uusi%q;YCP!>Ks^|Zo@Bx||5x+o zxgCv{o!t7EB#Tc|QW`#7Pg<`eul_O0rJ0*JKdYiG1?@XRNdM#ZG&!tnQjmUeF|O1a z=|g$$IPr;l(+B!{lxNK0{oYb&!!)cvG&CV@PU6?8wND)oZm6PifZb12!oR@GwL7xh zf7J464Q*~PIEcaMF5e8BgN>&zMt$;qygw_^9r|-Yuxk7YCONZ7sF|{Tc}d;?t-zH1(PGPaAF%d2cm^rC`JS)r7! zrgSrQJ`1<<%L=6vt%p4?f>HZh%4Uz}U__=_G4M5aD+4~*!Q_2c&fStz%hYh- z380E)iT|maA=iO|Oa#P*%|7?CmnFwoF zEao6ryLNS*B*W3ptN^HU{Oib5=Ht2);}NG4tNdy73%j9^dt#9jD@eKnq%F-EpPQ|J z_1QS)`h82pUCc@krMGB$VwcQ|ot7~0_))|HS%^b?22UlOqps#1)M-XrR?gaHlZ~43 z46%m2oQ&^(IQP4{`?C{zm;$o*$em7GjJOn`;tx>&^ZVW~Z5}0kYT{?1UDh9|L{n`S z@kkG)IX%533Zwgt#pg}plsDGietp%zy|M*yW=sY|wFUf}bG8AbkBcb|hy3wGU*6z# zrm_~9#fZ6Q81NBd|0Rnd>97Sf+mL?+k=yNI+y1bUZ$^LCXJZ_x>v~%ommnJu*HN@B z)?AJLyPDbovY45-K2?rzo+19Q@gNrB7a`+L6+|vN!w;tF&o0th#?K!pxs$>Dj(0iMxD+A$aY60XQu`|_T3 zPDb&J!@}GWlua@(Ix^kxvHruqNmOWJsq__qp1UyhIFy{EXXWg^VM%nN<~b`yGdeq1@D83(;&@l}yU`RY;EAd@KM=(N>!GkkTRzlg~*45A=i#6TxeEO4{8F z$TwQx?c|^MS8O3YO}3r!xGNK|g>>0|lqC>rvbWo1mc9V*4_BJ+?`PZ!L7j;r97Tf@ z>pYKkLf`1jIH+&Cqwe#6es=*BmyM|)fDFg~>Y%?{%&M|wn(-7=-M=@V^8Q~F==Qam zQOMrN!W-z<3C}gVSr4yu3t=TRc$XoYryQx<^pJ+$qZRS=Z+W;;zC1XKT3mvOR{#gPwSo;`t+=a7<84;vyHYN0X2W+=qj z{;nUPW7C45LitY@c~EKw~~sUqx_DtEbKO+b^5yS{BH5V^jV5HE2KlFGkgN! z(stY|rOKrjm`g4W>kjwA*7Ag1mBFldMH6|VDw`A=#Qsbiy>X%DK5Y42DTj+4k0hYy z4X4oe*_p}9Zk$?AnPRrZ+SX5B)It^>J%mHA^I6HY8R2XCSN_&x%i$bYP#wk^B(8c4 zp_H2y>bu^8^@Ts$qHL)4?$tog`V_@D9Gr2_TvqzVGB{8#A0yia7UF!lFh+GxR&1!i z+_xT~x~rU?svaY$uXF!Im+mump0-JhTDDyV;+!B-R4^O9%AqCLtzq5z+C~GetDaT5 z;rvA5gN%gRHYXjU=VsjQq_&gd3(5EYUc*ug=gS6w(G#Qctc~~i=fJueBR1RiZYqS) zaHlB5mOJNiXE^!38yb9uE$u!NW(FNnF0zMGdz+_unC$jyhMbV;HhGF8#pR@5lpkHFkE^zGF{%jKuhm@4KIW z#1GniHq1Ku3q@V2#EWkCiMk!){H~B%;GOsGA&I&$0kRo@xhE5;NmMZR^Vc^`0ln-X zyopikQn|Ygd={$D84J~20ZQP(k7L2)FoLVy(R zmHyM`_P6I)FSlofP!}6;rOpg1k|H^%MvGq*C=W{|zm@bIXNdE)vhUOQJHqB;U@rN> z0s0xRJ2e(kg4++I?JY3jANt~lPP=!9Z~o6F2uxIb5>C^LrdwF+-pWdo6caMbr`qVF zzYFLA%BM;x^R2|)dU+_lCHWi*6B) z`BYRzLy}@%;@n`_@OeA6D>bEHuXhzupfu!$4kN4ldJPG2LzKD`!(E0N^CPA&3Hb?s-Xboa)kVe3q?Cl@in+V5=LK)`y# z|86Ddg#JA;??cTL^2eOEsg#9$+E~{N$-hT(jnNlK4q%D&%eImt-*j*j)6w>>oBY5U zw@a?Qb+(Pt zqqH0mgIHq|aS;$7Q`}XpEhg^f;Y+)bf5Q9(C*tdM@rYlXw~v?RLg+i{&U_#HH~q>w z`)+h?CUbG+#kSBCU>FR2Eo5I|?Z1&>NpZ7*u6vLETS5jV@~|*YHr2Ir5{#c1%@b62 zdY|_)y(Bt-2UDWw*;|*ckYQhDuQGBd`ezkLWW-z6r6)9z-u)`NUlcHBK>4I{2!=5l zq2amM*$d-VHlIT9@FK1I_BalzyFD`2wb0G5Cr7S+`rc!XnIpOlS--Wc#m}M4$6VPK zO2bu?M$M}_A!9}+r*#uafdbfN9iOojpkrC)@nzf)TdHcC1|6HOl=1}}uBexLtc-N; z^c{Z|wTUY1|7v3|Gm~w9%v$Sn4kMBzrb}}07Z2ExSEZ<_eUxI_T)lHqa78P?^PhI0 z(u!}T2dEC1!T-v#9VkV=PStMmG`}I92GgFf)C{RidG8~l1s+1JuSSOsrNysP+&pO< z;yoC9>SnNO z0I*L9cp{2&oBq|`rt;yJKFZW<0<}6GC34 z9}^k>&V-{x%>Ux+Ksp^A)5^OBXnOc?f^3_^w(!t}10>FMrlxus$oMue{ z23cN_ZN2euq@YIM)}$$$Eb@N*YebFp4+Ya%#1}pG_=EM?%A~wuH4X01H0{YUPY&9v zCqB({-nXO#=jB}f*F!aUgUwCFN#TePxcLu z3A&rUT|0QQxLr^E@she6QH^M!UiI&XhBn(pwHcU)I(OCx!IGGZval6(9UB&e!c5z7 z;hLYPOZ)M{QfR}+IR6oATl`2DkP(I(|8U`!FV7(UZC7=A9UH+&7-(MvdbRFNhI(X+ zNWQ>tcSi#

VLuU1K3`JDpYIoqW)>=exO;(1M!sPI_NT;eP+&Cm0^DZg8hEN3oQs zAy;>+o3*Z14#{V!it8o37ozLpL3Ri4vL8gb{*YKfn^7yZ9B)i3XYKJaW#zgN0Rvte zcA__n;ka=nMvWE1WS9$YVvs7yx*#>20H1g3|Jy0xJ5fC)8Wu(u$#S&EeGpT9?5e+} z+I%*nob_2d&2K2;tHck;26Jl?(BvfWSw8c#t7u=dZzVI^motdCF4trLDg+hh!AD^Z zaUZ$rZ#tbCuvfyTUs^Kl8EZ2wIa$=q&vjz4*lP0mP?+lE{O~2m5I-)a2WqlnXzB}_ zK~VZ?rGcb9{1XSVEXa?WseL&o16M&58Gy?28G1;+*T~#GK4rsv8H4~4bK(*~Gx~VS z`uA_*gRfnOYFmSroK9z#TiXh`6NH<8z0G55mte`f+Fax#~50k2Y` zThVtYE$ij~a*BNXwFBj@TMeZD&Y$5sq*+o69aAu8y?Yw&Izzt`_4w2hG2ZUcetb5#py&#w zdbqs8*;e&JWq_h{a$@!b2^%^PE=8r}YVrAjjd7;?>Rpf-f}0^d~!9h6-M=buioix|7Vcft_*B3#MUg7hm#?>=1<{s6Q?&~ zR$2$D`i*@rV|aaM-!qGct&pl#AMqv!je0jMSqiN*xuFTni)Gb!`A>yA$O@#k9L?E5 zH(YvHlh!dR8lqWR#vfHK#M?3v{eGf0k-;zg`q6g z*Y#}v^MM0kpX$z2LeyML8jgWt=yd13?zOM4=t2(sNSloesUWSS_1h+QD&sU3=Zae6 z7uzgvzE4w{w}o;i4JH>kyeAa4wb^g(vg(OyS?mGByT`7$t=YG?H0(ZE3zGO6*VlY% zyE_U9>q(RiI1+K$r9!-(5#3r(+w>_%WDBe{6ZdjAmg||mQ(JiTXoZ-2P$i;`RwM-C z1=iZ4;J30bMEYl+U6k=gl{3ty+Gl&!2uXo3rBJ~1&ZO7f`p3Ol9Y1_QM1nOG=?m-; zIPzVI!b;trkYdiRJk{T|{Xy2j7|QY@xD#o0tZX=(oK=6yB}27;pJ)^8UL1dDd}Do| z2zV_?@}yY8q#l`7(?Yd;(&A%T_s3QJXyC6=1HJ#1c>Gp`;@14?x>4w||IwJL=AEGR zPMx^{R>Nb5tRJt(;+Efu*+USu_WAz^h-cmN-|m-&F8@GkPnK8h%&5(7EFl*7Zle@e zg3&gq8A(TV(ukkin0|yY0CJ1r%M_aGr!gPyF;8pUsT9_FF0$e0>NTBa-?uxV4!pAQ zkry7Prdy@Z#xr_-J0%Qk*N#b|_NhWEmS< zfBNBGbFbpf1Ge!`m2SA5xa~IK71@`(oP#tZkiQ^F35vhCO_7rQX;`(;fVyIeJp%De z6g}qtuTZg6TK>&!es-;xC0*p}NvYugi>nORP5xBkvKqqB_Is<7vlBSc*{W6b87n^! znBJXD>1mS^pOP~tFtXe8N`k~|+FM-mb**;EZXaHa^CCM*TWuey*%dZ{82LPQx*9Pl zfcC80$&f$rqwkh7xX*k8j3yV`^pd5^@b52^wrlYlpE%W=jZ|Y~et=`HpHl+OtVbf% zWEmy=2J?;#|x3*;|tkbNOEWR`t0a zf$wd}@Lu(A<*xROi8q9h`_#cB52z8>p#aRRV>*pz%YfJ(->1S0_J(+UEP&>xZ)L6~;b?F5ork<)!=9 z?s?z!3L188NZ?FZt*vWcAw=_A`9zVbnHZ%>Jm5%CuJIU!Cm6mb8Cly2l%|_iBUCe* z?QqNDay=YGRt)aBMRbj{%S6nuWyBV^P+|;9{d<*v(ZT1$Yl#9?H)X|SKhG@T#&x>+ zO(gD{yEs&2(geMHYL(HtDB`ylXvSoxFv-g+OI-e^Ht53)gL<~83j8v}Wpwy4@n6DF z`c~yTecG|i2{a+(ah}SW<{Zsmd$DAqR}PQL^{113-#a?PGmETp3oZW?&3!xAjvVqJ ztUkVMEiW6KO47F`PpEby>Cq&!fntsRCVz^LH2jARniKa%t)38sBR=qGt3Fg)`s`4w zDx{G)v5>{0DX%h@{^Z)~v`;zV^jUyvmM%7O$iSlY5p~x3z)zF2i9V}mwbq{1{SuL| zq3oVtT#r;MyE8uTX6REJHk32XOlWzm5%%y-7pJ$&&MOQgsb(3;5N=J>BcZm@N}T;e1@Y7})hK5}U7Dn2#4+6i+wFYaS}@ zQTi#qhMPu5BWW~VPWR4Y32_QP)tCY&jvZ*x`%j3%6e79Cw=*;KkK z*>_DG7v_^5uTVCV3e5e;@^{6X#N%l#WxkQHB7}>v8>LV46j>BCsJ^#oDzA_n`d~xIqN8C zs~{MBxXmEQ8!oh2CF!(A($X|9zeI@AUn)<_sZT9zznbNk zPc2qEj*!S8WD0t8VUo$f4adC7MVCQX>zSEbB~L)%FFMwSiX`C0f9~ETj?XCZ}dBZ^Qh-bqjDntc9!UEdH}u^JlN&VQYAQ!L9OmRk19F4?u~U(BJX z;6T#Iym@tUGG_cF#c)b8x*UC}-8uK=A@K*O)LLT{eVL{cr{hmPS(tI#O^t1E%Uo(| zMsk#gWvfn&-6M>Dtv37UP;0PR{vkPb`+}dzLpO3nF%O6~iEF~yC?riF4{vS4a!qml z$3}J0rlT=u24v$ORATx;Dy>=XaecVo_sTPIKg9;UXwAE_V7MnGj2eSzUYULk?|C-y z`$=Y+x+JcHSLTvh82%E%>$^skd(O+B^esJo#zwK|3X77aqr7WrG+(cQ0KeV%)C?)Y z=`Ay#gZ{q5UxJA*9yR0aOf@+i)t-7$$>!5(Whjia`&HRQ-vJCM#81RO~V)H>Su5$hU;oR^m_J*@hD zFV&0Mq9@lyw!D|u==-mKhnXu4#`GP_-hN}(t`Nf?bAjQJtP__*vva0w8K1&L+*10i z`_|0)<6f&!TmK+LN9mVglvIEF>6E4J42SybIa(g&o__Cg@;FP@;#ecd{L~1;TY%Kp z#~>0X!h@taOfnY#;3%%6Q9|a9Y$^y3#$X< zyG@HVvWT`=vaPoQz6y+g8!7g96(!&?;8eAAUnNXQ{@>FE7caWOaQ*rG1JM9+MtS8c1re_cSwf3(q3U2}A(*orx27aQrd zsy+U`M<^Lh(o3oI+oLFH4O?Zu?g0k$ACJzF7+sf0jM(Fc-z^>7Z7xgleQAyj6LOB@ zMS9t{rXFy=W<0SEF3*q;y6l|cPamo&O{`$&u-tqU>d=>H=SX8d0bR7V51mMxu_)f~HaJPwads%5O+efIM+d15N`N#I_5!J^RJ zt4WT3j&Oz9J@7Kq=C+L-#hupF(f~_&%IHbI_~y{c3aS+ncr7g+dYO88%ukP3Nuy~@vwf<`21VE`InL8 zV--wi^|!7HE-+Jp9{lm!OPs4aX^#Hq-A)o~@ysx>p-Iw*6ibg+IzE~bs^6c`lZvZB zMEU$a9BX!Pn!lAnL7P5YzTyiXey8C*`dx2ry^tE5VL(K~!+1b!h?m`bJ{!$Z6R3B( z^&O@bb?fU6^8H+&@XcC^nUkh~4i#F`H7W2~R>#hqRN6>VwK&2yX_Tmd;vcKP`Y8FjwAFoug%L`luO`L#!RlC>1mC*KLp zB^spOw?G@22eyaB!Xk&HeVAaKMbG6sfhEhML0s0lRnnob_Nz#Stg~i&KUd=fQUxN= z1|}QNmFuL7c*!1Sk^A!uMB1w2l-xdI(dJteXQF;4TRh|lb@1snMt>Y?V#riGs-3?0 z8Qr|_eW}YAb43_N{Kx-c@diPwM>P!pf7608NZ<=z&%yV7MpggL1ftjZRJw7nug%TD zIwE@K}ff`bnk%>r-De z_#*Ae?NRZt$a~3gFgGSXNBJTuc&IK7$Lkxl6~p8M41^FzRyz)2#2=9SZ#RS_R^Ne3 zi+uRkzZPj>ZR3zoZ8ZHVYDYk9AI6FivHp#q5mgnP6Fc`P% zNkb5>*X9Y8HzXRTYY@Z#aexeWwYrWxj2rY-IlbAgl9;R@^93!p7B5wE(#gVhp(Xcm z@xO1+%9`n%)6XQ4zZ1bWCZcAA96rUFNCZv>i8u0_&N}=~S{;cHOP=i$eeRNC{l9ml z4^H&_&OC?~lvGJ6b3vo#@Ag3vs_dM*VzsSXNgb{K{Fp8rHoR!kpz^6?*GTqhh-$wo z@nI>?Vb?=!B&1n^@z3I1Pq?3lR%_+S-V2$7y<2lLmU;A~O8GD_Z7=eX(QrU8QY8pp z1R^+vM=KDCfe`Fa*#E9kDAniZS1{6)^Ip#6TUUnQ=YMd89rPpyi=_GQiv4yb_!_5z zI+FjMgnWnrmqc1Bs^`x|Vw9Y~n~I`_+5UUd|9|oS+ttU^k!ahZQ3+Z(2>hVc^i-== HY@YrPor}WF literal 0 HcmV?d00001 diff --git a/ai/icons/stopwatch.png.import b/ai/icons/stopwatch.png.import new file mode 100644 index 0000000..1045bbb --- /dev/null +++ b/ai/icons/stopwatch.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ho4mpdraykbv" +path="res://.godot/imported/stopwatch.png-693f4af9e4bcbeda164482669808a0d8.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://ai/icons/stopwatch.png" +dest_files=["res://.godot/imported/stopwatch.png-693f4af9e4bcbeda164482669808a0d8.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/ai/tasks/actions/get_quest.gd b/ai/tasks/actions/get_quest.gd new file mode 100644 index 0000000..b2aada8 --- /dev/null +++ b/ai/tasks/actions/get_quest.gd @@ -0,0 +1,103 @@ +#* +#* use_guild_service.gd +#* +@tool +extends BTAction +## Moves the agent to the specified position, favoring horizontal movement. [br] +## Returns [code]SUCCESS[/code] when close to the target position (see [member tolerance]); +## otherwise returns [code]RUNNING[/code]. + + +enum Phases { + ARRIVE, + QUEUE, + WAIT, + OBTAIN, + COMPLETE +} + +var board : QuestBoard + +var queue : GuildQueue +var wait_time_remaining : float = 0 +var phase : Phases + + +func _generate_name() -> String: + return "Get a Quest" + +func _enter() -> void: + var brd = Guild.hall.board + if !brd: + printerr("Get a Quest: Board not found!") + return + board = brd + queue = board.queue + phase = Phases.ARRIVE + queue.add_member(agent) + agent.approach(queue.get_last_position()) + agent.navigation_finished.connect(_on_navigation_complete) + agent.navigation_failed.connect(_on_navigation_failed) + +func _tick(delta: float) -> Status: + if board == null: + return FAILURE + match(phase): + Phases.ARRIVE: + if wait_time_remaining > 0: + wait_time_remaining -= delta + if wait_time_remaining <= 0: + agent.navigation_finished.connect(_on_navigation_complete) + agent.approach(queue.get_member_position(agent)) + Phases.QUEUE: + pass + Phases.WAIT: + pass + Phases.OBTAIN: + if wait_time_remaining: + wait_time_remaining -= delta + if wait_time_remaining <= 0: + board.interaction_complete.connect(_on_interaction_complete) + board.interact(agent, "quest") + phase = Phases.OBTAIN + Phases.COMPLETE: + return SUCCESS + return RUNNING + +func _on_navigation_complete() -> void: + agent.navigation_finished.disconnect(_on_navigation_complete) + agent.navigation_failed.disconnect(_on_navigation_failed) + queue.advanced.connect(_on_queue_advanced) + phase = Phases.QUEUE + +func _on_navigation_failed() -> void: + wait_time_remaining = randf_range(.5, 2) + agent.navigation_finished.disconnect(_on_navigation_complete) + +func get_quest(): + phase = Phases.OBTAIN + wait_time_remaining = randf_range(2,5) + agent.show_speech_bubble("busy") + +func wait(): + wait_time_remaining = 1 + phase = Phases.WAIT + + +func _on_queue_advanced() -> void: + if queue.front == agent: + queue.advanced.disconnect(_on_queue_advanced) + if board.busy: + wait() + else: + get_quest() + pass + +func _on_interaction_complete() -> void: + board.interaction_complete.disconnect(_on_interaction_complete) + if agent.data.quest != null: + agent.show_speech_bubble("happy", 1.5) + else: + agent.show_speech_bubble("angry", 1.5) + queue.remove_member(agent) + phase = Phases.COMPLETE diff --git a/ai/tasks/actions/get_quest.gd.uid b/ai/tasks/actions/get_quest.gd.uid new file mode 100644 index 0000000..c4cdd6e --- /dev/null +++ b/ai/tasks/actions/get_quest.gd.uid @@ -0,0 +1 @@ +uid://ders6t7axct24 diff --git a/ai/tasks/actions/go_to.gd b/ai/tasks/actions/go_to.gd new file mode 100644 index 0000000..acee1f5 --- /dev/null +++ b/ai/tasks/actions/go_to.gd @@ -0,0 +1,48 @@ +#* +#* go_to.gd +#* +@tool +extends BTAction +## Moves the agent to the specified position, favoring horizontal movement. [br] +## Returns [code]SUCCESS[/code] when close to the target position (see [member tolerance]); +## otherwise returns [code]RUNNING[/code]. + +## Blackboard variable that stores the target position (Vector2) +@export var target_position_var := &"pos" +var wait_time_remaining : float = 0 +var goal_position : Vector2 + +var done : bool + +func _generate_name() -> String: + return "Go to Position: %s" % [LimboUtility.decorate_var(target_position_var)] + +func _enter() -> void: + done = false + goal_position = blackboard.get_var(target_position_var, Vector2.ZERO) + go_to(goal_position) + +func _tick(delta: float) -> Status: + if done: + return SUCCESS + #If we were interrupted, wait a little bit and try again + if wait_time_remaining > 0: + wait_time_remaining -= delta + if wait_time_remaining <= 0: + go_to(goal_position) + return RUNNING + +func go_to(pos : Vector2) -> void: + agent.navigation_finished.connect(_on_navigation_complete) + agent.navigation_failed.connect(_on_navigation_failed) + agent.approach(pos) + +func _on_navigation_complete() -> void: + agent.navigation_finished.disconnect(_on_navigation_complete) + agent.navigation_failed.disconnect(_on_navigation_failed) + done = true + +func _on_navigation_failed() -> void: + wait_time_remaining = randf_range(.5, 2) + agent.navigation_finished.disconnect(_on_navigation_complete) + agent.navigation_failed.disconnect(_on_navigation_failed) diff --git a/ai/tasks/actions/go_to.gd.uid b/ai/tasks/actions/go_to.gd.uid new file mode 100644 index 0000000..f02eb45 --- /dev/null +++ b/ai/tasks/actions/go_to.gd.uid @@ -0,0 +1 @@ +uid://h113xg55h4r8 diff --git a/ai/tasks/actions/use_guild_service.gd b/ai/tasks/actions/use_guild_service.gd new file mode 100644 index 0000000..c2b7164 --- /dev/null +++ b/ai/tasks/actions/use_guild_service.gd @@ -0,0 +1,111 @@ +#* +#* use_guild_service.gd +#* +@tool +extends BTAction +## Moves the agent to the specified position, favoring horizontal movement. [br] +## Returns [code]SUCCESS[/code] when close to the target position (see [member tolerance]); +## otherwise returns [code]RUNNING[/code]. + + +enum Phases { + ARRIVE, + QUEUE, + WAIT, + SERVICE, + COMPLETE +} + +## Blackboard variable that stores the target position (Vector2) +@export var employee_name : String = "" + +## Variable that stores desired speed (float) +@export var service_name : String = "" + +var employee : GuildEmployee +var queue : GuildQueue +var wait_time_remaining : float = 0 +var phase : Phases + + +func _generate_name() -> String: + return "Use Guild Service (%s) - %s" % [ + employee_name, + service_name + ] + +func _enter() -> void: + var emp = Guild.hall.employees.get(employee_name) + if !emp: + printerr("Use Guild Service (%s) - %s, '%s' not found!", employee_name, service_name, employee_name) + return + employee = emp + queue = employee.queue + phase = Phases.ARRIVE + queue.add_member(agent) + agent.approach(queue.get_last_position()) + agent.navigation_finished.connect(_on_navigation_complete) + agent.navigation_failed.connect(_on_navigation_failed) + +func _tick(delta: float) -> Status: + if employee == null: + return FAILURE + match(phase): + Phases.ARRIVE: + if wait_time_remaining > 0: + wait_time_remaining -= delta + if wait_time_remaining <= 0: + agent.navigation_finished.connect(_on_navigation_complete) + agent.approach(queue.get_member_position(agent)) + Phases.QUEUE: + pass + Phases.WAIT: + pass + Phases.SERVICE: + if wait_time_remaining > 0: + wait_time_remaining -= delta + if wait_time_remaining <= 0: + employee.service_provided.connect(_on_service_complete) + employee.interact(agent, service_name) + Phases.COMPLETE: + return SUCCESS + return RUNNING + +func _on_navigation_complete() -> void: + agent.navigation_finished.disconnect(_on_navigation_complete) + agent.navigation_failed.disconnect(_on_navigation_failed) + queue.advanced.connect(_on_queue_advanced) + phase = Phases.QUEUE + +func _on_navigation_failed() -> void: + wait_time_remaining = randf_range(.5, 2) + agent.navigation_finished.disconnect(_on_navigation_complete) + +func use_service(): + phase = Phases.SERVICE + wait_time_remaining = randf_range(2,5) + #TODO: Make them both do the talking emoji + agent.show_speech_bubble("talk") + employee.show_speech_bubble("talk") + +func wait(): + wait_time_remaining = 1 + phase = Phases.WAIT + + +func _on_queue_advanced() -> void: + if queue.front == agent: + queue.advanced.disconnect(_on_queue_advanced) + if employee.busy: + wait() + else: + use_service() + pass + +func _on_service_complete() -> void: + employee.service_provided.disconnect(_on_service_complete) + agent.show_speech_bubble("") + employee.show_speech_bubble("") + queue.remove_member(agent) + phase = Phases.COMPLETE + diff --git a/ai/tasks/actions/use_guild_service.gd.uid b/ai/tasks/actions/use_guild_service.gd.uid new file mode 100644 index 0000000..c20a81b --- /dev/null +++ b/ai/tasks/actions/use_guild_service.gd.uid @@ -0,0 +1 @@ +uid://bsq5dxul0uto diff --git a/ai/tasks/actions/wander.gd b/ai/tasks/actions/wander.gd new file mode 100644 index 0000000..b51e1a4 --- /dev/null +++ b/ai/tasks/actions/wander.gd @@ -0,0 +1,50 @@ +#* +#* go_to.gd +#* +@tool +extends BTAction +## Moves the agent to the specified position, favoring horizontal movement. [br] +## Returns [code]SUCCESS[/code] when close to the target position (see [member tolerance]); +## otherwise returns [code]RUNNING[/code]. + +var wait_time_remaining : float = 0 +var goal_position : Vector2 +var retries : int +var done : bool + +func _generate_name() -> String: + return "Wander to New Position" + +func _enter() -> void: + done = false + retries = 0 + goal_position = NavigationServer2D.region_get_random_point(Guild.hall.nav_region.get_rid(),1,false) + go_to(goal_position) + +func _tick(delta: float) -> Status: + if done: + return SUCCESS + #If we were interrupted, wait a little bit and try again + if wait_time_remaining > 0: + wait_time_remaining -= delta + if wait_time_remaining <= 0: + go_to(goal_position) + return RUNNING + +func go_to(pos : Vector2) -> void: + agent.navigation_finished.connect(_on_navigation_complete) + agent.navigation_failed.connect(_on_navigation_failed) + agent.approach(pos) + +func _on_navigation_complete() -> void: + agent.navigation_finished.disconnect(_on_navigation_complete) + agent.navigation_failed.disconnect(_on_navigation_failed) + done = true + +func _on_navigation_failed() -> void: + wait_time_remaining = randf_range(.5, 2) + retries += 1 + if retries >= 3: + done = true + agent.navigation_finished.disconnect(_on_navigation_complete) + agent.navigation_failed.disconnect(_on_navigation_failed) diff --git a/ai/tasks/actions/wander.gd.uid b/ai/tasks/actions/wander.gd.uid new file mode 100644 index 0000000..5cb2892 --- /dev/null +++ b/ai/tasks/actions/wander.gd.uid @@ -0,0 +1 @@ +uid://767b4fdlrgr diff --git a/ai/tasks/conditions/has_quest.gd b/ai/tasks/conditions/has_quest.gd new file mode 100644 index 0000000..967c7e7 --- /dev/null +++ b/ai/tasks/conditions/has_quest.gd @@ -0,0 +1,7 @@ +extends BTCondition +var invert : bool +func _tick(delta: float) -> Status: + if agent.data and ((agent.data.quest == null) == invert): + return SUCCESS + else: + return FAILURE diff --git a/ai/tasks/conditions/has_quest.gd.uid b/ai/tasks/conditions/has_quest.gd.uid new file mode 100644 index 0000000..58cf852 --- /dev/null +++ b/ai/tasks/conditions/has_quest.gd.uid @@ -0,0 +1 @@ +uid://xom38ohdwfms diff --git a/ai/tasks/conditions/is_unregistered.gd b/ai/tasks/conditions/is_unregistered.gd new file mode 100644 index 0000000..c7a0eb8 --- /dev/null +++ b/ai/tasks/conditions/is_unregistered.gd @@ -0,0 +1,7 @@ +extends BTCondition + +func _tick(delta: float) -> Status: + if agent.data and !Guild.has_guild_member(agent.data): + return SUCCESS + else: + return FAILURE diff --git a/ai/tasks/conditions/is_unregistered.gd.uid b/ai/tasks/conditions/is_unregistered.gd.uid new file mode 100644 index 0000000..7971b09 --- /dev/null +++ b/ai/tasks/conditions/is_unregistered.gd.uid @@ -0,0 +1 @@ +uid://bcbfnm21rtkuo diff --git a/ai/tasks/decorators/busy.gd b/ai/tasks/decorators/busy.gd new file mode 100644 index 0000000..810acf0 --- /dev/null +++ b/ai/tasks/decorators/busy.gd @@ -0,0 +1,22 @@ +@tool +extends BTDecorator + + +var prev_busy : bool + +func _get_task_icon(): + return load("res://ai/icons/stopwatch.png") + + +func _enter() -> void: + if agent.get("busy") != null: + prev_busy = agent.busy + agent.busy = true + +func _exit() -> void: + if agent.get("busy") != null: + agent.busy = prev_busy + +# Called to generate a display name for the task (requires @tool). +func _generate_name() -> String: + return "Busy" diff --git a/ai/tasks/decorators/busy.gd.uid b/ai/tasks/decorators/busy.gd.uid new file mode 100644 index 0000000..d25fda1 --- /dev/null +++ b/ai/tasks/decorators/busy.gd.uid @@ -0,0 +1 @@ +uid://b2vuw12mttm40 diff --git a/ai/trees/adventurer.tres b/ai/trees/adventurer.tres new file mode 100644 index 0000000..1f83901 --- /dev/null +++ b/ai/trees/adventurer.tres @@ -0,0 +1,145 @@ +[gd_resource type="BehaviorTree" load_steps=42 format=3 uid="uid://dght2flegv70i"] + +[ext_resource type="Script" uid="uid://h113xg55h4r8" path="res://ai/tasks/actions/go_to.gd" id="1_s3kkm"] +[ext_resource type="Script" uid="uid://bsq5dxul0uto" path="res://ai/tasks/actions/use_guild_service.gd" id="2_1441p"] +[ext_resource type="Script" uid="uid://767b4fdlrgr" path="res://ai/tasks/actions/wander.gd" id="2_fe6jf"] +[ext_resource type="Script" uid="uid://b2vuw12mttm40" path="res://ai/tasks/decorators/busy.gd" id="2_mtixs"] +[ext_resource type="Script" uid="uid://bcbfnm21rtkuo" path="res://ai/tasks/conditions/is_unregistered.gd" id="3_mtixs"] +[ext_resource type="Script" uid="uid://xom38ohdwfms" path="res://ai/tasks/conditions/has_quest.gd" id="4_1441p"] + +[sub_resource type="BlackboardPlan" id="BlackboardPlan_6h604"] +var/pos/name = &"pos" +var/pos/type = 5 +var/pos/value = Vector2(0, 0) +var/pos/hint = 0 +var/pos/hint_string = "" +var/speed/name = &"speed" +var/speed/type = 3 +var/speed/value = 0.0 +var/speed/hint = 0 +var/speed/hint_string = "" + +[sub_resource type="BTComment" id="BTComment_fe6jf"] +custom_name = "Walk from the entrance to the designated start point of the guild." + +[sub_resource type="BBVariant" id="BBVariant_1441p"] +type = 5 +saved_value = Vector2(900, 700) +resource_name = "(900.0, 700.0)" + +[sub_resource type="BTSetVar" id="BTSetVar_mtixs"] +variable = &"pos" +value = SubResource("BBVariant_1441p") + +[sub_resource type="BTAction" id="BTAction_0kac8"] +script = ExtResource("1_s3kkm") + +[sub_resource type="BTWait" id="BTWait_s3kkm"] +duration = 1.5 + +[sub_resource type="BTAction" id="BTAction_nqy1p"] +script = ExtResource("2_fe6jf") + +[sub_resource type="BTSequence" id="BTSequence_s3kkm"] +custom_name = "Enter the Guild" +children = [SubResource("BTSetVar_mtixs"), SubResource("BTAction_0kac8"), SubResource("BTWait_s3kkm"), SubResource("BTAction_nqy1p")] + +[sub_resource type="BTDecorator" id="BTDecorator_nqy1p"] +children = [SubResource("BTSequence_s3kkm")] +script = ExtResource("2_mtixs") + +[sub_resource type="BTRunLimit" id="BTRunLimit_1441p"] +children = [SubResource("BTDecorator_nqy1p")] + +[sub_resource type="BTComment" id="BTComment_0kac8"] +custom_name = "Always try to register as a guildmember as their first action" + +[sub_resource type="BTCondition" id="BTCondition_s18yy"] +script = ExtResource("3_mtixs") + +[sub_resource type="BTAction" id="BTAction_700su"] +script = ExtResource("2_1441p") +employee_name = "Receptionist" +service_name = "register" + +[sub_resource type="BTAction" id="BTAction_s18yy"] +script = ExtResource("2_fe6jf") + +[sub_resource type="BTSequence" id="BTSequence_1441p"] +custom_name = "Register as a Guildmember" +children = [SubResource("BTCondition_s18yy"), SubResource("BTAction_700su"), SubResource("BTAction_s18yy")] + +[sub_resource type="BTDecorator" id="BTDecorator_700su"] +children = [SubResource("BTSequence_1441p")] +script = ExtResource("2_mtixs") + +[sub_resource type="BTCondition" id="BTCondition_mtixs"] +script = ExtResource("4_1441p") + +[sub_resource type="BTAction" id="BTAction_fe6jf"] +script = ExtResource("2_1441p") +employee_name = "Questboard" +service_name = "get_quest" + +[sub_resource type="BTAction" id="BTAction_mwsop"] +script = ExtResource("2_fe6jf") + +[sub_resource type="BTSequence" id="BTSequence_nqy1p"] +custom_name = "Get a Quest" +children = [SubResource("BTCondition_mtixs"), SubResource("BTAction_fe6jf"), SubResource("BTAction_mwsop")] + +[sub_resource type="BTDecorator" id="BTDecorator_s18yy"] +children = [SubResource("BTSequence_nqy1p")] +script = ExtResource("2_mtixs") + +[sub_resource type="BTProbability" id="BTProbability_s3kkm"] +children = [SubResource("BTDecorator_s18yy")] + +[sub_resource type="BTComment" id="BTComment_mwsop"] +custom_name = "TODO: Make them talk to a random other adventurer" + +[sub_resource type="BTDecorator" id="BTDecorator_jq6fo"] +children = [SubResource("BTComment_mwsop")] +script = ExtResource("2_mtixs") + +[sub_resource type="BTCooldown" id="BTCooldown_mtixs"] +duration = 5.0 +trigger_on_failure = true +children = [SubResource("BTDecorator_jq6fo")] + +[sub_resource type="BTProbability" id="BTProbability_1441p"] +children = [SubResource("BTCooldown_mtixs")] +_enabled = false + +[sub_resource type="BTWait" id="BTWait_8lwgx"] +duration = 3.0 +custom_name = "Idle" + +[sub_resource type="BTProbability" id="BTProbability_gc1l4"] +children = [SubResource("BTWait_8lwgx")] + +[sub_resource type="BTAction" id="BTAction_jq6fo"] +script = ExtResource("2_fe6jf") + +[sub_resource type="BTProbability" id="BTProbability_8lwgx"] +children = [SubResource("BTAction_jq6fo")] + +[sub_resource type="BTProbabilitySelector" id="BTProbabilitySelector_mtixs"] +children = [SubResource("BTProbability_s3kkm"), SubResource("BTProbability_1441p"), SubResource("BTProbability_gc1l4"), SubResource("BTProbability_8lwgx")] + +[sub_resource type="BTComment" id="BTComment_y4ura"] +custom_name = "TODO: Make them wander to a random location after the interaction" + +[sub_resource type="BTSequence" id="BTSequence_4w6ij"] +children = [SubResource("BTProbabilitySelector_mtixs"), SubResource("BTComment_y4ura")] + +[sub_resource type="BTSelector" id="BTSelector_mwsop"] +children = [SubResource("BTComment_fe6jf"), SubResource("BTRunLimit_1441p"), SubResource("BTComment_0kac8"), SubResource("BTDecorator_700su"), SubResource("BTSequence_4w6ij")] + +[sub_resource type="BTRepeat" id="BTRepeat_s3kkm"] +forever = true +children = [SubResource("BTSelector_mwsop")] + +[resource] +blackboard_plan = SubResource("BlackboardPlan_6h604") +root_task = SubResource("BTRepeat_s3kkm") diff --git a/ai/trees/receptionist.tres b/ai/trees/receptionist.tres new file mode 100644 index 0000000..94fa9bc --- /dev/null +++ b/ai/trees/receptionist.tres @@ -0,0 +1,34 @@ +[gd_resource type="BehaviorTree" load_steps=9 format=3 uid="uid://dxyx7tjsd7khq"] + +[sub_resource type="BlackboardPlan" id="BlackboardPlan_1q5ck"] + +[sub_resource type="BBVariant" id="BBVariant_68j5j"] +type = 1 +saved_value = false +resource_name = "false" + +[sub_resource type="BTCheckAgentProperty" id="BTCheckAgentProperty_tkyhk"] +property = &"busy" +value = SubResource("BBVariant_68j5j") + +[sub_resource type="BBNode" id="BBNode_1q5ck"] +saved_value = NodePath("Queue") +resource_name = "Queue" + +[sub_resource type="BTCallMethod" id="BTCallMethod_xsfkt"] +node = SubResource("BBNode_1q5ck") +method = &"try_advance" + +[sub_resource type="BTSequence" id="BTSequence_1q5ck"] +children = [SubResource("BTCheckAgentProperty_tkyhk"), SubResource("BTCallMethod_xsfkt")] + +[sub_resource type="BTCooldown" id="BTCooldown_qle3k"] +duration = 2.0 +children = [SubResource("BTSequence_1q5ck")] + +[sub_resource type="BTRepeat" id="BTRepeat_aurho"] +children = [SubResource("BTCooldown_qle3k")] + +[resource] +blackboard_plan = SubResource("BlackboardPlan_1q5ck") +root_task = SubResource("BTRepeat_aurho") diff --git a/basic-sprite.png b/basic-sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..f3b7b8f19a2b12a77c83229ff1146083dc7a247a GIT binary patch literal 1526 zcmVPx)ut`KgRCt{2oV|-1M;OK*g%oK*5;u`lEh>~O$b~=z7UQ7vUtnS|oWYF?fk1yw zu)&2Jg9U~dL;6@)7&Qmi2xL?oR~>5d0dCx_i+IFpZ$D<;@DKTxZZ_Qf5dQ!D>J+8sX&5Exdm9%zEH?DI@Ow@~HLZ zk9TY)uo;jYJm3yWK{+ z-9Gr;db7prSI^RuJGTzrWhk;Tz{TK;9s_(PkR#BGM)HP-} z@$>E50C@2?)q1nVAnvE%eEWlOq>Tx1RsDR{bwr_n6aiIzX%(4JX3ToC)%v29m(?Vw z@Rw9}z!WO#WNd(s$#1vYX%Bul92i~OcoKAlKSgRXgu&+<>yN_6u3&)g8}KbQ0~U(~ z*QJ~)5a9a;e9Ov!x69?h@iE3A5MX*j)El*4zIa~x?>;FQ#C?oU?iqa}G&bPxzdjrs z=VRbo*^ZKqL?UoZa{xaBTtwe}G`X#pT(x7?jDi3Fqf)+?YVE zK0q{}i~^q~P^u4DPJ;a(lWT8@RVGLnq51;U^R0S=+2%-ok)&?9%w`o?89AFytb2qU z&Czr|pJO(iz|;gK9W(Ou%%&6k`OgRRqEXAHL26|{9LLyfHtBpm-``ZxavAsH>1;Z| zdb35R(?OCXt<`EpzLqTk`@v^#u58WF#t1dHynONeVB_HD z0qB{LolwuDpM$+5J0YekvI*YP+;^?IF4hJr+ZP7 zBu39SC4ja10RP4cQwp>RIELygnNVOt0DJWTnXNS@6lf7}Ox0J?r9hVek?I3-o2zsw zs3qVStFNR(fery;)dys^*XdADNx(5zU#X6QIs!zi56Ew@tfQckfL=8E*tFJ{i580m zdeP`()pIJp3|(BFeFglqUzl*QFOWmo^}~P1P_9Y>y4`N;$>YcSva<(J-1 zPfroYab?Ua3AnntD*S!Zh^Xo})O~fY{Tz^|AS>TQR5e?4st;%^h?G%~m1`n&J4`wY zH{`z;D3Y`h60J3@FGE!^C=z!xO#6zu_yd{*=)|B%wnW%eTzB1)H3DTaHNxe_3hfmk z(-;(~E*cyybQAmm0|KZqD3bJBr^&Lt(W)>91(GtYK4547Ck0Y6ZQ6vbvZg0AH3k&? z0fGTdjsc}-86rSAscA8w;tvoFXkrYgEqihVnnHn1^#Kb5nnZ!khK(=@+MMh=2DbPE zmIgE-1~&Ku3=!}}0Y~)#1_OLjU|W44OoBWHxQ+oA{s5B!K4QRuKM*3oXMn31aN-Xz z8sIVpT=)ab5s;>UyZQjL0WK)utUeGXL4E_IVjzJ(AYg!G47l+JLIh+C;EsV5{(z7H z5;2g#9}tWH7X^~l2Luh^q(G|rK$rw&4X}-YH2#3F0UR-q#2;`F0V)M9st-6Yz=i_p z>H}dCbYp;N3|!$4I5L0|0~h!MAp-6U(2aph`~imsn8d&p{($2M)KTEN`ha5tbSQ9H zeIQJN?hPo5fe-uv4+d1lz%~9rh=3mh@-gs*Kj6uLq8RwV->bUaE&!we(*MH$Q$SVv c`Nx|+0d^+45TLjq>Hq)$07*qoM6N<$g1geczyJUM literal 0 HcmV?d00001 diff --git a/basic-sprite.png.import b/basic-sprite.png.import new file mode 100644 index 0000000..8dd85b7 --- /dev/null +++ b/basic-sprite.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cg6ptmynq0aq0" +path="res://.godot/imported/basic-sprite.png-8651af0edadac4b9f3511ab9d4ca3c8a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://basic-sprite.png" +dest_files=["res://.godot/imported/basic-sprite.png-8651af0edadac4b9f3511ab9d4ca3c8a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/fsm/interact_with_employee.gd b/fsm/interact_with_employee.gd deleted file mode 100644 index 1541041..0000000 --- a/fsm/interact_with_employee.gd +++ /dev/null @@ -1,39 +0,0 @@ -extends StateNode - -@export var employee_name : String = "" -@export var speech_bubble : String = "" -@export var wait_duration : float = 1 -@export var interaction_args : Array[String] = [] -var wait_remaining : float = 0 - -var employee : GuildEmployee -var actor - -func exit() -> void: - actor.show_speech_bubble("") - -func _process(delta: float) -> void: - if wait_remaining > 0: - wait_remaining -= delta - if wait_remaining <= 0: - wait_remaining = 0 - employee.interact(actor, interaction_args[0]) - complete_state() - -func execute(subject, ...args : Array) -> void: - wait_remaining = wait_duration - actor = subject - - if len(args) > 0 and args[0] != "": - subject.show_speech_bubble(speech_bubble) - - #TODO: Possibly an error later with preexisting and extended lists - for arg in args.slice(1): - interaction_args.append(arg) - var emp = Guild.hall.employees.get(employee_name) - - if emp == null: - printerr("Employee %s not found!" % employee_name) - complete_state() - else: - employee = emp diff --git a/fsm/interact_with_employee.gd.uid b/fsm/interact_with_employee.gd.uid deleted file mode 100644 index e079014..0000000 --- a/fsm/interact_with_employee.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://bewrajxqdutsu diff --git a/fsm/machines/newbie.gd b/fsm/machines/newbie.gd deleted file mode 100644 index b59c986..0000000 --- a/fsm/machines/newbie.gd +++ /dev/null @@ -1,27 +0,0 @@ -extends StateMachine - - -func advance_state() -> void: - var last_state = curr_state - var args : Array = [actor] - exit_state(curr_state) - match(last_state.name): - "Wait": - if last_state.next_state != "": - if !states.has(last_state.next_state): - printerr("Tried to switch to missing state %s" % last_state.next_state) - pass - enter_state(states[last_state.next_state]) - args.append_array(last_state.next_state_args) - else: - pass - "Queue": - enter_state(states["Wait"]) - args.append_array(["busy", "Interact With Employee"]) - "Register": - enter_state(states["Register"]) - "Leave": - enter_state(states["Leave"]) - - if curr_state != null: - curr_state.execute.callv(args) diff --git a/fsm/machines/newbie.gd.uid b/fsm/machines/newbie.gd.uid deleted file mode 100644 index c178394..0000000 --- a/fsm/machines/newbie.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dthatmb3if73u diff --git a/fsm/machines/receptionist.gd b/fsm/machines/receptionist.gd deleted file mode 100644 index cbd7199..0000000 --- a/fsm/machines/receptionist.gd +++ /dev/null @@ -1,23 +0,0 @@ -extends StateMachine - - -func advance_state() -> void: - var last_state = curr_state - var args : Array = [actor] - exit_state(curr_state) - match(last_state.name): - "Wait": - if last_state.next_state != "": - if !states.has(last_state.next_state): - printerr("Tried to switch to missing state %s" % last_state.next_state) - pass - enter_state(states[last_state.next_state]) - args.append_array(last_state.next_state_args) - else: - pass - "Advance Queue": - enter_state(states["Wait"]) - args.append_array(["", "Advance Queue"]) - - if curr_state != null: - curr_state.execute.callv(args) diff --git a/fsm/machines/receptionist.gd.uid b/fsm/machines/receptionist.gd.uid deleted file mode 100644 index 8f94348..0000000 --- a/fsm/machines/receptionist.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://cggu0yihq0unt diff --git a/fsm/machines/state_machine.gd b/fsm/machines/state_machine.gd deleted file mode 100644 index 1f7a77a..0000000 --- a/fsm/machines/state_machine.gd +++ /dev/null @@ -1,43 +0,0 @@ -class_name StateMachine extends Node - -@export var starting_state : String = "" -var states : Dictionary[String, StateNode] = {} -var curr_state : StateNode = null -var actor = null -func _ready() -> void: - for child in get_children(): - if child is StateNode: - states[child.name] = child - child.state_machine = self - child.completed.connect(_on_state_completed) - - -func start() -> void: - if starting_state != "": - var state : StateNode = states.get(starting_state) - if state == null: - printerr("Starting state not found! Expected %s" % [starting_state]) - else: - enter_state(state) - curr_state.execute(actor) - -func exit_state(state : StateNode) -> void: - curr_state.exit() - curr_state = null - pass - -func enter_state(state : StateNode) -> void: - curr_state = state - curr_state.enter() - pass - - -func advance_state() -> void: - pass - - -func _on_state_completed(state : StateNode) -> void: - if state == curr_state: - advance_state() - else: - printerr("Wrong state completed! %s when expecting %s" % [state.name, curr_state]) diff --git a/fsm/machines/state_machine.gd.uid b/fsm/machines/state_machine.gd.uid deleted file mode 100644 index 617afd7..0000000 --- a/fsm/machines/state_machine.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://u81fhi8157bg diff --git a/fsm/machines/test.gd b/fsm/machines/test.gd deleted file mode 100644 index 06e8cf6..0000000 --- a/fsm/machines/test.gd +++ /dev/null @@ -1,22 +0,0 @@ -extends StateMachine - -func advance_state() -> void: - var last_state = curr_state - var args : Array = [actor] - exit_state(curr_state) - match(last_state.name): - "Wait": - if last_state.next_state != "": - if !states.has(last_state.next_state): - printerr("Tried to switch to missing state %s" % last_state.next_state) - pass - enter_state(states[last_state.next_state]) - args.append_array(last_state.next_state_args) - else: - pass - "Test": - enter_state(states["Wait"]) - args.append_array(["busy", "Test"]) - - if curr_state != null: - curr_state.execute.callv(args) diff --git a/fsm/machines/test.gd.uid b/fsm/machines/test.gd.uid deleted file mode 100644 index 01c3f2e..0000000 --- a/fsm/machines/test.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://djd8pv5xbgud3 diff --git a/fsm/nodes/advance_queue.gd b/fsm/nodes/advance_queue.gd deleted file mode 100644 index 9173724..0000000 --- a/fsm/nodes/advance_queue.gd +++ /dev/null @@ -1,6 +0,0 @@ -extends StateNode - -func execute(subject, ...args : Array) -> void: - if !subject.busy: - subject.queue.try_advance() - complete_state() diff --git a/fsm/nodes/advance_queue.gd.uid b/fsm/nodes/advance_queue.gd.uid deleted file mode 100644 index 9f9e8b9..0000000 --- a/fsm/nodes/advance_queue.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://csicx3fpxv7xt diff --git a/fsm/nodes/leave.gd b/fsm/nodes/leave.gd deleted file mode 100644 index a350eda..0000000 --- a/fsm/nodes/leave.gd +++ /dev/null @@ -1 +0,0 @@ -extends StateNode diff --git a/fsm/nodes/leave.gd.uid b/fsm/nodes/leave.gd.uid deleted file mode 100644 index 15b310d..0000000 --- a/fsm/nodes/leave.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b0ewnwcibhu21 diff --git a/fsm/nodes/queue.gd b/fsm/nodes/queue.gd deleted file mode 100644 index 1f8c630..0000000 --- a/fsm/nodes/queue.gd +++ /dev/null @@ -1,51 +0,0 @@ -extends StateNode - -@export var employee : String = "" - -var target -var actor -var in_queue -var queued_at : GuildQueue -var next_state : String -var next_state_args : Array = [] - - -func execute(subject, ...args : Array) -> void: - actor = subject - #find the receptionist queue - var queue = Guild.hall.employees[employee].queue - #join the queue - join_queue(queue) - reposition_queue(queue.length-1) - - subject.nav_agent.navigation_finished.connect(_on_navigation_finished) - -func _on_navigation_finished() -> void: - actor.nav_agent.navigation_finished.disconnect(_on_navigation_finished) - if !in_queue: - complete_state() - -func join_queue(queue : GuildQueue) -> void: - queue.add_member(actor) - in_queue = true - queued_at = queue - queue.advanced.connect(_on_queue_advanced) - -func leave_queue() -> void: - in_queue = false - queued_at.advanced.disconnect(_on_queue_advanced) - queued_at = null - -func reposition_queue(idx : int) -> void: - var queue = queued_at - #if zero approach the receptionist with the intent to use her service at navigation complete. - actor.approach(queue.global_position + idx * queue.direction * 75) - -func _on_queue_advanced() -> void: - #find our place within the queue - var idx : int = queued_at.members.find(actor) - #We aren't in the queue, time to advance - if idx < 0: - leave_queue() - else: - reposition_queue(idx) diff --git a/fsm/nodes/queue.gd.uid b/fsm/nodes/queue.gd.uid deleted file mode 100644 index 5978983..0000000 --- a/fsm/nodes/queue.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://y85swbbk8kbd diff --git a/fsm/nodes/state_node.gd b/fsm/nodes/state_node.gd deleted file mode 100644 index 5f815b3..0000000 --- a/fsm/nodes/state_node.gd +++ /dev/null @@ -1,17 +0,0 @@ -class_name StateNode extends Node - -var state_machine : StateMachine = null -signal completed(state : StateNode) - - -func enter() -> void: - pass - -func exit() -> void: - pass - -func execute(subject, ...args : Array) -> void: - pass - -func complete_state() -> void: - completed.emit(self) diff --git a/fsm/nodes/state_node.gd.uid b/fsm/nodes/state_node.gd.uid deleted file mode 100644 index bed885e..0000000 --- a/fsm/nodes/state_node.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://c27ctn874rdns diff --git a/fsm/nodes/test.gd b/fsm/nodes/test.gd deleted file mode 100644 index 8f0c587..0000000 --- a/fsm/nodes/test.gd +++ /dev/null @@ -1,13 +0,0 @@ -extends StateNode - - -@export var message : String = "" -var target -func execute(subject, ...args : Array) -> void: - subject.approach(Game.player.global_position) - subject.nav_agent.navigation_finished.connect(_on_navigation_finished) - target = subject - -func _on_navigation_finished() -> void: - target.nav_agent.navigation_finished.disconnect(_on_navigation_finished) - complete_state() diff --git a/fsm/nodes/test.gd.uid b/fsm/nodes/test.gd.uid deleted file mode 100644 index de75bbe..0000000 --- a/fsm/nodes/test.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://e8we6nmaob1k diff --git a/fsm/nodes/wait.gd b/fsm/nodes/wait.gd deleted file mode 100644 index 0d14d77..0000000 --- a/fsm/nodes/wait.gd +++ /dev/null @@ -1,34 +0,0 @@ -extends StateNode - - -@export var wait_duration : float = 1 -var wait_remaining : float = 0 -var next_state : String -var next_state_args : Array = [] -var actor -func exit() -> void: - actor.show_speech_bubble("") - -func _process(delta: float) -> void: - if wait_remaining > 0: - wait_remaining -= delta - if wait_remaining <= 0: - wait_remaining = 0 - complete_state() - -func execute(subject, ...args : Array) -> void: - wait_remaining = wait_duration - actor = subject - - if len(args) > 0 and args[0] != "": - subject.show_speech_bubble(args[0]) - - if len(args) > 1 and args[1] != "": - next_state = args[1] - else: - next_state = "" - - if len(args) > 2 and args[2] != "": - next_state_args = args[2] - else: - next_state_args = [] diff --git a/fsm/nodes/wait.gd.uid b/fsm/nodes/wait.gd.uid deleted file mode 100644 index 87fc662..0000000 --- a/fsm/nodes/wait.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dl3b5aywu1hf6 diff --git a/game_manager.gd b/game_manager.gd index 11b3ee5..ee5412a 100644 --- a/game_manager.gd +++ b/game_manager.gd @@ -9,9 +9,9 @@ var end_shift_confirm_template = preload("res://end_shift_confirmation.tscn") func _ready() -> void: end_shift_confirmation = end_shift_confirm_template.instantiate() add_child(end_shift_confirmation) - var file =FileAccess.open("res://name.txt",FileAccess.READ) - var text =file.get_line() - var nmnames = text.remove_chars(" ").split(",") + #var file =FileAccess.open("res://name.txt",FileAccess.READ) + #var text =file.get_line() + #var nmnames = text.remove_chars(" ").split(",") func _process(delta: float) -> void: if active and Input.is_action_just_pressed("switch modes"): diff --git a/guild.gd b/guild.gd index 869efbf..667ba39 100644 --- a/guild.gd +++ b/guild.gd @@ -20,6 +20,11 @@ func register_guild_member(member : AdventurerData, first : bool = false) -> voi if first: Game.notice("%s has joined the guild!" % member.name, 5) +func has_guild_member(member : AdventurerData) -> bool: + if member == null: + return false + return members.has(member) + func add_quest(quest : Quest) -> void: quests[quest] = false Game.quest_log.add_entry(quest) diff --git a/guild_employee.gd b/guild_employee.gd index 6b2ed1a..ce7c4af 100644 --- a/guild_employee.gd +++ b/guild_employee.gd @@ -4,7 +4,9 @@ class_name GuildEmployee extends Adventurer @onready var queue : GuildQueue = $Queue var busy : bool +signal service_provided() func interact(interactor, type : String = "") -> void: if type == "register": Guild.register_guild_member(interactor.data, true) + service_provided.emit() diff --git a/guild_queue.gd b/guild_queue.gd index aa44e8e..4914554 100644 --- a/guild_queue.gd +++ b/guild_queue.gd @@ -5,11 +5,18 @@ var length : int : return len(members) @export var direction : Vector2 = Vector2.ZERO var members : Array[Adventurer] = [] + +var front : Adventurer : + get: return null if len(members) == 0 else members[0] + signal advanced() func add_member(member : Adventurer) -> void: members.append(member) - #TODO: Instead retrieve the array length with a getter + +func remove_member(member : Adventurer) -> void: + members.erase(member) + func try_advance() -> Adventurer: if length > 0: @@ -18,6 +25,18 @@ func try_advance() -> Adventurer: return null func advance() -> Adventurer: - var member = members.pop_front() advanced.emit() - return member + return front + +func get_last_position() -> Vector2: + return get_index_position(length - 1) + +func get_index_position(idx : int) -> Vector2: + return global_position + idx * 100 * direction + +func get_member_position(member) -> Vector2: + var idx = members.find(member) + if idx == -1: + return Vector2.ZERO + else: + return get_index_position(idx) diff --git a/guildhall.gd b/guildhall.gd index 2940b80..b96be44 100644 --- a/guildhall.gd +++ b/guildhall.gd @@ -1,10 +1,13 @@ class_name Guildhall extends Node2D var employees : Dictionary[String, GuildEmployee] = {} +var board : QuestBoard +@onready var sprite_node : Node2D = $Sprites +@onready var nav_region : NavigationRegion2D = $RoomRegion func _ready() -> void: Guild.hall = self - for child in get_children(): + for child in sprite_node.get_children(): if child is GuildEmployee: register_employee(child) @@ -14,4 +17,4 @@ func register_employee(employee: GuildEmployee) -> void: func add_sprite(sprite : Adventurer) -> void: - add_child(sprite) + sprite_node.add_child(sprite) diff --git a/guildhall.tscn b/guildhall.tscn index fbb1bfb..12241a8 100644 --- a/guildhall.tscn +++ b/guildhall.tscn @@ -1,191 +1,65 @@ -[gd_scene load_steps=19 format=4 uid="uid://cd08dp16bixfv"] +[gd_scene load_steps=9 format=4 uid="uid://cd08dp16bixfv"] [ext_resource type="Script" uid="uid://ccorfvcfa84gf" path="res://guildhall.gd" id="1_lsinl"] [ext_resource type="TileSet" uid="uid://6im0g3eg6sr4" path="res://test_tiles.tres" id="1_qel1r"] [ext_resource type="Script" uid="uid://dolqtw1ye4ras" path="res://player.gd" id="2_5n4iw"] -[ext_resource type="Texture2D" uid="uid://bldpiytpdrge6" path="res://icon.svg" id="2_w7eqs"] -[ext_resource type="Texture2D" uid="uid://cbamfadh7wwr7" path="res://speech-blip.png" id="4_2wofw"] -[ext_resource type="Script" uid="uid://b2unuudq5qfl" path="res://guild_employee.gd" id="4_g7jyq"] -[ext_resource type="Script" uid="uid://b0q2233msdtgo" path="res://guild_queue.gd" id="5_13vc8"] -[ext_resource type="Script" uid="uid://cggu0yihq0unt" path="res://fsm/machines/receptionist.gd" id="6_13vc8"] -[ext_resource type="Script" uid="uid://csicx3fpxv7xt" path="res://fsm/nodes/advance_queue.gd" id="7_hph4e"] -[ext_resource type="Script" uid="uid://dl3b5aywu1hf6" path="res://fsm/nodes/wait.gd" id="8_bog1h"] -[ext_resource type="Script" uid="uid://w57riwplc00t" path="res://speech_bubble.gd" id="10_50x1e"] -[ext_resource type="Texture2D" uid="uid://chnk20ey5qxfh" path="res://speech-emojis.png" id="11_50x1e"] +[ext_resource type="Texture2D" uid="uid://cg6ptmynq0aq0" path="res://basic-sprite.png" id="4_l3mu1"] +[ext_resource type="PackedScene" uid="uid://cf6nnjyp8kv78" path="res://receptionist.tscn" id="5_l3mu1"] [sub_resource type="NavigationPolygon" id="NavigationPolygon_w7eqs"] -vertices = PackedVector2Array(814, 70.03906, 1070, 68.96094, 778, 138, 778, 54, 814, 10, 10, 10, 246, 54, 10, 630, 246, 138, 458, 630, 1070, 28, 1078, 28, 1078, 630, 566, 630, 566, 886, 458, 886) -polygons = Array[PackedInt32Array]([PackedInt32Array(0, 1, 2), PackedInt32Array(0, 2, 3), PackedInt32Array(4, 0, 3), PackedInt32Array(5, 4, 3), PackedInt32Array(5, 3, 6), PackedInt32Array(7, 5, 6), PackedInt32Array(7, 6, 8), PackedInt32Array(9, 7, 8), PackedInt32Array(9, 8, 2), PackedInt32Array(1, 10, 11), PackedInt32Array(1, 11, 12), PackedInt32Array(2, 1, 12), PackedInt32Array(2, 12, 13), PackedInt32Array(9, 2, 13), PackedInt32Array(9, 13, 14), PackedInt32Array(9, 14, 15)]) -sample_partition_type = 1 +vertices = PackedVector2Array(808, 168, 808, 58, 1048, 58, 1048, 600, 40, 600, 216, 168, 40, 40, 216, 40) +polygons = Array[PackedInt32Array]([PackedInt32Array(0, 1, 2, 3), PackedInt32Array(0, 3, 4, 5), PackedInt32Array(5, 4, 6, 7)]) +border_size = 500.0 +agent_radius = 40.0 -[sub_resource type="CircleShape2D" id="CircleShape2D_5n4iw"] -radius = 35.0 +[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_l3mu1"] +radius = 15.0 +height = 54.0 -[sub_resource type="Animation" id="Animation_bog1h"] -length = 0.001 -tracks/0/type = "value" -tracks/0/imported = false -tracks/0/enabled = true -tracks/0/path = NodePath("Sprite2D3:frame") -tracks/0/interp = 1 -tracks/0/loop_wrap = true -tracks/0/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 1, -"values": [0] -} -tracks/1/type = "value" -tracks/1/imported = false -tracks/1/enabled = true -tracks/1/path = NodePath("Sprite2D3:position") -tracks/1/interp = 1 -tracks/1/loop_wrap = true -tracks/1/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [Vector2(0, 0)] -} - -[sub_resource type="Animation" id="Animation_13vc8"] -resource_name = "busy" -length = 0.7000034 -loop_mode = 1 -tracks/0/type = "value" -tracks/0/imported = false -tracks/0/enabled = true -tracks/0/path = NodePath("Sprite2D3:frame") -tracks/0/interp = 1 -tracks/0/loop_wrap = true -tracks/0/keys = { -"times": PackedFloat32Array(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7), -"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1), -"update": 1, -"values": [0, 1, 8, 9, 16, 17, 24, 25] -} -tracks/1/type = "value" -tracks/1/imported = false -tracks/1/enabled = true -tracks/1/path = NodePath("Sprite2D3:position") -tracks/1/interp = 1 -tracks/1/loop_wrap = true -tracks/1/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [Vector2(0, 0)] -} - -[sub_resource type="Animation" id="Animation_lsinl"] -resource_name = "talk" -length = 0.40000334 -loop_mode = 1 -tracks/0/type = "value" -tracks/0/imported = false -tracks/0/enabled = true -tracks/0/path = NodePath("Sprite2D3:position") -tracks/0/interp = 1 -tracks/0/loop_wrap = true -tracks/0/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [Vector2(0, -3)] -} -tracks/1/type = "value" -tracks/1/imported = false -tracks/1/enabled = true -tracks/1/path = NodePath("Sprite2D3:frame") -tracks/1/interp = 1 -tracks/1/loop_wrap = true -tracks/1/keys = { -"times": PackedFloat32Array(0, 0.1, 0.2, 0.3, 0.4), -"transitions": PackedFloat32Array(1, 1, 1, 1, 1), -"update": 1, -"values": [2, 3, 10, 3, 2] -} - -[sub_resource type="AnimationLibrary" id="AnimationLibrary_uo85v"] -_data = { -&"RESET": SubResource("Animation_bog1h"), -&"busy": SubResource("Animation_13vc8"), -&"talk": SubResource("Animation_lsinl") -} +[sub_resource type="NavigationPolygon" id="NavigationPolygon_l3mu1"] +vertices = PackedVector2Array(117.96875, 286, 9.96875, 286, 9.03125, 0, 117.03125, 0) +polygons = Array[PackedInt32Array]([PackedInt32Array(0, 1, 2, 3)]) +outlines = Array[PackedVector2Array]([PackedVector2Array(-1, -10, 127, -10, 128, 296, 0, 296)]) [node name="Guildhall" type="Node2D"] script = ExtResource("1_lsinl") -[node name="NavigationRegion2D" type="NavigationRegion2D" parent="."] +[node name="RoomRegion" type="NavigationRegion2D" parent="."] navigation_polygon = SubResource("NavigationPolygon_w7eqs") -[node name="TileMapLayer" type="TileMapLayer" parent="NavigationRegion2D"] -tile_map_data = PackedByteArray("AAABAAEAAAAOAAEAAAACAAEAAAAOAAEAAAADAAEAAAAOAAEAAAAEAAEAAAAOAAEAAAAFAAIAAAAOAAEAAAAGAAIAAAAOAAEAAAAHAAIAAAAOAAEAAAAIAAIAAAAOAAEAAAAJAAIAAAAOAAEAAAAKAAIAAAAOAAEAAAAHAAEAAAAOAAEAAAAGAAEAAAAOAAEAAAAFAAEAAAAOAAEAAAACAAIAAAAOAAEAAAADAAIAAAAOAAEAAAAEAAIAAAAOAAEAAAABAAIAAAAOAAEAAAABAAMAAAAOAAEAAAABAAQAAAAOAAEAAAACAAQAAAAOAAEAAAADAAQAAAAOAAEAAAAEAAQAAAAOAAEAAAAFAAQAAAAOAAEAAAAGAAQAAAAOAAEAAAAHAAQAAAAOAAEAAAAIAAQAAAAOAAEAAAAJAAQAAAAOAAEAAAAJAAMAAAAOAAEAAAAKAAMAAAAOAAEAAAAKAAEAAAAOAAEAAAAJAAEAAAAOAAEAAAAIAAEAAAAOAAEAAAADAAMAAAAOAAEAAAACAAMAAAAOAAEAAAAEAAMAAAAOAAEAAAAFAAMAAAAOAAEAAAAGAAMAAAAOAAEAAAAHAAMAAAAOAAEAAAAIAAMAAAAOAAEAAAAKAAQAAAAOAAEAAAALAAQAAAAOAAEAAAALAAMAAAAOAAEAAAALAAIAAAAOAAEAAAALAAEAAAAOAAEAAAAKAAAAAAAOAAEAAAAJAAAAAAAOAAEAAAAIAAAAAAAOAAEAAAAHAAAAAAAOAAEAAAAGAAAAAAAOAAEAAAAFAAAAAAAOAAEAAAAEAAAAAAAOAAEAAAADAAAAAAAOAAEAAAACAAAAAAAOAAEAAAABAAAAAAAOAAEAAAAAAAEAAAAOAAEAAAAAAAIAAAAOAAEAAAAAAAMAAAAOAAEAAAAAAAQAAAAOAAEAAAAAAAUAAAAOAAEAAAAAAAYAAAAOAAEAAAAAAAcAAAAOAAEAAAAAAAgAAAAOAAEAAAAAAAkAAAAOAAEAAAABAAkAAAAOAAEAAAACAAkAAAAOAAEAAAADAAkAAAAOAAEAAAAEAAkAAAAOAAEAAAAFAAkAAAAOAAEAAAAGAAkAAAAOAAEAAAAHAAkAAAAOAAEAAAAIAAkAAAAOAAEAAAAJAAkAAAAOAAEAAAAKAAkAAAAOAAEAAAALAAkAAAAOAAEAAAAMAAkAAAAOAAEAAAANAAkAAAAOAAEAAAAOAAkAAAAOAAEAAAAPAAkAAAAOAAEAAAAQAAkAAAAOAAEAAAAQAAgAAAAOAAEAAAAQAAcAAAAOAAEAAAAQAAYAAAAOAAEAAAAQAAUAAAAOAAEAAAAQAAQAAAAOAAEAAAAQAAMAAAAOAAEAAAAQAAIAAAAOAAEAAAAQAAEAAAAOAAEAAAAQAAAAAAAOAAEAAAAPAAAAAAAOAAEAAAAOAAAAAAAOAAEAAAANAAAAAAAOAAEAAAAMAAAAAAAOAAEAAAALAAAAAAAOAAEAAAAPAAEAAAAOAAEAAAAOAAEAAAAOAAEAAAANAAEAAAAOAAEAAAAMAAEAAAAOAAEAAAAMAAIAAAAOAAEAAAANAAIAAAAOAAEAAAAOAAIAAAAOAAEAAAAPAAIAAAAOAAEAAAAMAAMAAAAOAAEAAAAMAAQAAAAOAAEAAAANAAQAAAAOAAEAAAAOAAQAAAAOAAEAAAAPAAQAAAAOAAEAAAAOAAUAAAAOAAEAAAANAAUAAAAOAAEAAAAMAAUAAAAOAAEAAAALAAUAAAAOAAEAAAAKAAYAAAAOAAEAAAAJAAYAAAAOAAEAAAAIAAcAAAAOAAEAAAAJAAcAAAAOAAEAAAAKAAcAAAAOAAEAAAALAAcAAAAOAAEAAAAMAAcAAAAOAAEAAAANAAYAAAAOAAEAAAAOAAYAAAAOAAEAAAAPAAYAAAAOAAEAAAAPAAcAAAAOAAEAAAAOAAgAAAAOAAEAAAAPAAgAAAAOAAEAAAAPAAUAAAAOAAEAAAAOAAMAAAAOAAEAAAAOAAcAAAAOAAEAAAAPAAMAAAAOAAEAAAAMAAYAAAAOAAEAAAALAAgAAAAOAAEAAAAMAAgAAAAOAAEAAAANAAcAAAAOAAEAAAANAAgAAAAOAAEAAAANAAMAAAAOAAEAAAAKAAUAAAAOAAEAAAAIAAgAAAAOAAEAAAAJAAgAAAAOAAEAAAALAAYAAAAOAAEAAAAKAAgAAAAOAAEAAAAHAAgAAAAOAAEAAAAGAAgAAAAOAAEAAAACAAgAAAAOAAEAAAABAAgAAAAOAAEAAAABAAcAAAAOAAEAAAABAAYAAAAOAAEAAAABAAUAAAAOAAEAAAACAAUAAAAOAAEAAAACAAYAAAAOAAEAAAADAAYAAAAOAAEAAAAEAAYAAAAOAAEAAAAFAAYAAAAOAAEAAAAGAAYAAAAOAAEAAAAHAAYAAAAOAAEAAAAIAAYAAAAOAAEAAAAFAAUAAAAOAAEAAAAGAAUAAAAOAAEAAAAHAAUAAAAOAAEAAAAIAAUAAAAOAAEAAAAJAAUAAAAOAAEAAAAEAAUAAAAOAAEAAAADAAUAAAAOAAEAAAADAAcAAAAOAAEAAAACAAcAAAAOAAEAAAAEAAcAAAAOAAEAAAAFAAcAAAAOAAEAAAAGAAcAAAAOAAEAAAAHAAcAAAAOAAEAAAAFAAgAAAAOAAEAAAAEAAgAAAAOAAEAAAADAAgAAAAOAAEAAAARAP//AAABAAQAAAARAAoAAAABAAUAAAD//woAAAAAAAUAAAD/////AAAAAAQAAAAAAP//AAACAAQAAAABAP//AAACAAQAAAACAP//AAACAAQAAAADAP//AAACAAQAAAAEAP//AAACAAQAAAAFAP//AAACAAQAAAAGAP//AAACAAQAAAAHAP//AAACAAQAAAAIAP//AAACAAQAAAAJAP//AAACAAQAAAAKAP//AAACAAQAAAALAP//AAACAAQAAAAMAP//AAACAAQAAAANAP//AAACAAQAAAAOAP//AAACAAQAAAAPAP//AAACAAQAAAAQAP//AAACAAQAAAARAAAAAAACAAUAAAARAAEAAAACAAUAAAARAAIAAAACAAUAAAARAAMAAAACAAUAAAARAAQAAAACAAUAAAARAAUAAAACAAUAAAARAAYAAAACAAUAAAARAAcAAAACAAUAAAARAAgAAAACAAUAAAARAAkAAAACAAUAAAAQAAoAAAACAAQAAAAPAAoAAAACAAQAAAAOAAoAAAACAAQAAAANAAoAAAACAAQAAAAMAAoAAAACAAQAAAALAAoAAAACAAQAAAAKAAoAAAACAAQAAAAJAAoAAAAGAAUAAAAIAAoAAAAFAAAAAAAHAAoAAAAFAAAAAAAGAAoAAAAFAAQAAAAFAAoAAAACAAQAAAAEAAoAAAACAAQAAAADAAoAAAACAAQAAAACAAoAAAACAAQAAAABAAoAAAACAAQAAAAAAAoAAAACAAQAAAD//wkAAAACAAUAAAD//wAAAAACAAUAAAD//wEAAAACAAUAAAD//wIAAAACAAUAAAD//wMAAAACAAUAAAD//wQAAAACAAUAAAD//wUAAAACAAUAAAD//wYAAAACAAUAAAD//wcAAAACAAUAAAD//wgAAAACAAUAAAAHAAsAAAAFAAAAAAAIAAsAAAAFAAAAAAAHAAwAAAAFAAAAAAAIAAwAAAAFAAAAAAAHAA0AAAAFAAAAAAAIAA0AAAAFAAAAAAAAAAAAAAAOAAEAAAA=") +[node name="TileMapLayer" type="TileMapLayer" parent="RoomRegion"] +tile_map_data = PackedByteArray("AAABAAEAAAAOAAEAAAACAAEAAAAOAAEAAAADAAEAAAAOAAEAAAAEAAEAAAAOAAEAAAAFAAIAAAAOAAEAAAAGAAIAAAAOAAEAAAAHAAIAAAAOAAEAAAAIAAIAAAAOAAEAAAAJAAIAAAAOAAEAAAAKAAIAAAAOAAEAAAAHAAEAAAAOAAEAAAAGAAEAAAAOAAEAAAAFAAEAAAAOAAEAAAACAAIAAAAOAAEAAAADAAIAAAAOAAEAAAAEAAIAAAAOAAEAAAABAAIAAAAOAAEAAAABAAMAAAAOAAEAAAABAAQAAAAOAAEAAAACAAQAAAAOAAEAAAADAAQAAAAOAAEAAAAEAAQAAAAOAAEAAAAFAAQAAAAOAAEAAAAGAAQAAAAOAAEAAAAHAAQAAAAOAAEAAAAIAAQAAAAOAAEAAAAJAAQAAAAOAAEAAAAJAAMAAAAOAAEAAAAKAAMAAAAOAAEAAAAKAAEAAAAOAAEAAAAJAAEAAAAOAAEAAAAIAAEAAAAOAAEAAAADAAMAAAAOAAEAAAACAAMAAAAOAAEAAAAEAAMAAAAOAAEAAAAFAAMAAAAOAAEAAAAGAAMAAAAOAAEAAAAHAAMAAAAOAAEAAAAIAAMAAAAOAAEAAAAKAAQAAAAOAAEAAAALAAQAAAAOAAEAAAALAAMAAAAOAAEAAAALAAIAAAAOAAEAAAALAAEAAAAOAAEAAAAKAAAAAAAOAAEAAAAJAAAAAAAOAAEAAAAIAAAAAAAOAAEAAAAHAAAAAAAOAAEAAAAGAAAAAAAOAAEAAAAFAAAAAAAOAAEAAAAEAAAAAAAOAAEAAAADAAAAAAAOAAEAAAACAAAAAAAOAAEAAAABAAAAAAAOAAEAAAAAAAEAAAAOAAEAAAAAAAIAAAAOAAEAAAAAAAMAAAAOAAEAAAAAAAQAAAAOAAEAAAAAAAUAAAAOAAEAAAAAAAYAAAAOAAEAAAAAAAcAAAAOAAEAAAAAAAgAAAAOAAEAAAAAAAkAAAAOAAEAAAABAAkAAAAOAAEAAAACAAkAAAAOAAEAAAADAAkAAAAOAAEAAAAEAAkAAAAOAAEAAAAFAAkAAAAOAAEAAAAGAAkAAAAOAAEAAAAHAAkAAAAOAAEAAAAIAAkAAAAOAAEAAAAJAAkAAAAOAAEAAAAKAAkAAAAOAAEAAAALAAkAAAAOAAEAAAAMAAkAAAAOAAEAAAANAAkAAAAOAAEAAAAOAAkAAAAOAAEAAAAPAAkAAAAOAAEAAAAQAAkAAAAOAAEAAAAQAAgAAAAOAAEAAAAQAAcAAAAOAAEAAAAQAAYAAAAOAAEAAAAQAAUAAAAOAAEAAAAQAAQAAAAOAAEAAAAQAAMAAAAOAAEAAAAQAAIAAAAOAAEAAAAQAAEAAAAOAAEAAAAQAAAAAAAOAAEAAAAPAAAAAAAOAAEAAAAOAAAAAAAOAAEAAAANAAAAAAAOAAEAAAAMAAAAAAAOAAEAAAALAAAAAAAOAAEAAAAPAAEAAAAOAAEAAAAOAAEAAAAOAAEAAAANAAEAAAAOAAEAAAAMAAEAAAAOAAEAAAAMAAIAAAAOAAEAAAANAAIAAAAOAAEAAAAOAAIAAAAOAAEAAAAPAAIAAAAOAAEAAAAMAAMAAAAOAAEAAAAMAAQAAAAOAAEAAAANAAQAAAAOAAEAAAAOAAQAAAAOAAEAAAAPAAQAAAAOAAEAAAAOAAUAAAAOAAEAAAANAAUAAAAOAAEAAAAMAAUAAAAOAAEAAAALAAUAAAAOAAEAAAAKAAYAAAAOAAEAAAAJAAYAAAAOAAEAAAAIAAcAAAAOAAEAAAAJAAcAAAAOAAEAAAAKAAcAAAAOAAEAAAALAAcAAAAOAAEAAAAMAAcAAAAOAAEAAAANAAYAAAAOAAEAAAAOAAYAAAAOAAEAAAAPAAYAAAAOAAEAAAAPAAcAAAAOAAEAAAAOAAgAAAAOAAEAAAAPAAgAAAAOAAEAAAAPAAUAAAAOAAEAAAAOAAMAAAAOAAEAAAAOAAcAAAAOAAEAAAAPAAMAAAAOAAEAAAAMAAYAAAAOAAEAAAALAAgAAAAOAAEAAAAMAAgAAAAOAAEAAAANAAcAAAAOAAEAAAANAAgAAAAOAAEAAAANAAMAAAAOAAEAAAAKAAUAAAAOAAEAAAAIAAgAAAAOAAEAAAAJAAgAAAAOAAEAAAALAAYAAAAOAAEAAAAKAAgAAAAOAAEAAAAHAAgAAAAOAAEAAAAGAAgAAAAOAAEAAAACAAgAAAAOAAEAAAABAAgAAAAOAAEAAAABAAcAAAAOAAEAAAABAAYAAAAOAAEAAAABAAUAAAAOAAEAAAACAAUAAAAOAAEAAAACAAYAAAAOAAEAAAADAAYAAAAOAAEAAAAEAAYAAAAOAAEAAAAFAAYAAAAOAAEAAAAGAAYAAAAOAAEAAAAHAAYAAAAOAAEAAAAIAAYAAAAOAAEAAAAFAAUAAAAOAAEAAAAGAAUAAAAOAAEAAAAHAAUAAAAOAAEAAAAIAAUAAAAOAAEAAAAJAAUAAAAOAAEAAAAEAAUAAAAOAAEAAAADAAUAAAAOAAEAAAADAAcAAAAOAAEAAAACAAcAAAAOAAEAAAAEAAcAAAAOAAEAAAAFAAcAAAAOAAEAAAAGAAcAAAAOAAEAAAAHAAcAAAAOAAEAAAAFAAgAAAAOAAEAAAAEAAgAAAAOAAEAAAADAAgAAAAOAAEAAAARAP//AAABAAQAAAARAAoAAAABAAUAAAD//woAAAAAAAUAAAD/////AAAAAAQAAAAAAP//AAACAAQAAAABAP//AAACAAQAAAACAP//AAACAAQAAAADAP//AAACAAQAAAAEAP//AAACAAQAAAAFAP//AAACAAQAAAAGAP//AAACAAQAAAAHAP//AAACAAQAAAAIAP//AAACAAQAAAAJAP//AAACAAQAAAAKAP//AAACAAQAAAALAP//AAACAAQAAAAMAP//AAACAAQAAAANAP//AAACAAQAAAAOAP//AAACAAQAAAAPAP//AAACAAQAAAAQAP//AAACAAQAAAARAAAAAAACAAUAAAARAAEAAAACAAUAAAARAAIAAAACAAUAAAARAAMAAAACAAUAAAARAAQAAAACAAUAAAARAAUAAAACAAUAAAARAAYAAAACAAUAAAARAAcAAAACAAUAAAARAAgAAAACAAUAAAARAAkAAAACAAUAAAAQAAoAAAACAAQAAAAPAAoAAAACAAQAAAAOAAoAAAACAAQAAAANAAoAAAACAAQAAAAMAAoAAAACAAQAAAALAAoAAAACAAQAAAAKAAoAAAACAAQAAAAJAAoAAAAGAAUAAAAGAAoAAAAFAAQAAAAFAAoAAAACAAQAAAAEAAoAAAACAAQAAAADAAoAAAACAAQAAAACAAoAAAACAAQAAAABAAoAAAACAAQAAAAAAAoAAAACAAQAAAD//wkAAAACAAUAAAD//wAAAAACAAUAAAD//wEAAAACAAUAAAD//wIAAAACAAUAAAD//wMAAAACAAUAAAD//wQAAAACAAUAAAD//wUAAAACAAUAAAD//wYAAAACAAUAAAD//wcAAAACAAUAAAD//wgAAAACAAUAAAAAAAAAAAAOAAEAAAA=") tile_set = ExtResource("1_qel1r") collision_visibility_mode = 1 navigation_visibility_mode = 1 -[node name="TileMapLayer2" type="TileMapLayer" parent="NavigationRegion2D"] +[node name="TileMapLayer2" type="TileMapLayer" parent="RoomRegion"] tile_map_data = PackedByteArray("AAAEAAEAAAASAAwAAAAFAAEAAAATAAwAAAAGAAEAAAATAAwAAAAHAAEAAAATAAwAAAAIAAEAAAATAAwAAAAJAAEAAAATAAwAAAAKAAEAAAATAAwAAAALAAEAAAAUAAwAAAANAAAAAAAKABEAAAAOAAAAAAAKABEAAAAPAAAAAAAKABEAAAAQAAAAAAAKABEAAAA=") tile_set = ExtResource("1_qel1r") -[node name="CharacterBody2D" type="CharacterBody2D" parent="."] -position = Vector2(241, 364) +[node name="Sprites" type="Node2D" parent="."] +z_index = 1 +y_sort_enabled = true + +[node name="Receptionist" parent="Sprites" instance=ExtResource("5_l3mu1")] +position = Vector2(512, -27) + +[node name="CharacterBody2D" type="CharacterBody2D" parent="Sprites"] +position = Vector2(202, 389) script = ExtResource("2_5n4iw") -[node name="Sprite2D" type="Sprite2D" parent="CharacterBody2D"] -scale = Vector2(0.5, 0.5) -texture = ExtResource("2_w7eqs") +[node name="CollisionShape2D" type="CollisionShape2D" parent="Sprites/CharacterBody2D"] +rotation = 1.5707964 +shape = SubResource("CapsuleShape2D_l3mu1") -[node name="NavigationAgent2D" type="NavigationAgent2D" parent="CharacterBody2D"] +[node name="Sprite2D" type="Sprite2D" parent="Sprites/CharacterBody2D"] +position = Vector2(0, -64) +texture = ExtResource("4_l3mu1") + +[node name="NavigationAgent2D" type="NavigationAgent2D" parent="Sprites/CharacterBody2D"] path_desired_distance = 30.0 avoidance_enabled = true -[node name="CollisionShape2D" type="CollisionShape2D" parent="CharacterBody2D"] -shape = SubResource("CircleShape2D_5n4iw") - -[node name="Receptionist" type="CharacterBody2D" parent="."] -modulate = Color(1.7602391, 1.7602391, 1.7602391, 1) -position = Vector2(518, 32) -script = ExtResource("4_g7jyq") - -[node name="Sprite2D" type="Sprite2D" parent="Receptionist"] -modulate = Color(0, 1, 0, 1) -scale = Vector2(0.5, 0.5) -texture = ExtResource("2_w7eqs") - -[node name="NavigationAgent2D" type="NavigationAgent2D" parent="Receptionist"] -path_desired_distance = 30.0 -avoidance_enabled = true - -[node name="CollisionShape2D" type="CollisionShape2D" parent="Receptionist"] -shape = SubResource("CircleShape2D_5n4iw") - -[node name="Queue" type="Node2D" parent="Receptionist"] -position = Vector2(-6, 133) -script = ExtResource("5_13vc8") - -[node name="StateMachine" type="Node" parent="Receptionist"] -script = ExtResource("6_13vc8") - -[node name="Wait" type="Node" parent="Receptionist/StateMachine"] -script = ExtResource("8_bog1h") -wait_duration = 3.0 - -[node name="Advance Queue" type="Node" parent="Receptionist/StateMachine"] -script = ExtResource("7_hph4e") - -[node name="SpeechBubble" type="Sprite2D" parent="Receptionist"] -position = Vector2(39, -42) -texture = ExtResource("4_2wofw") -script = ExtResource("10_50x1e") - -[node name="Sprite2D3" type="Sprite2D" parent="Receptionist/SpeechBubble"] -texture = ExtResource("11_50x1e") -hframes = 8 -vframes = 8 - -[node name="AnimationPlayer" type="AnimationPlayer" parent="Receptionist/SpeechBubble"] -libraries = { -&"": SubResource("AnimationLibrary_uo85v") -} +[node name="EntranceRegion" type="NavigationRegion2D" parent="."] +position = Vector2(448, 600) +navigation_polygon = SubResource("NavigationPolygon_l3mu1") diff --git a/main_panel.gd b/main_panel.gd index 3c58daa..e391367 100644 --- a/main_panel.gd +++ b/main_panel.gd @@ -1,4 +1,4 @@ -class_name GamePanel extends PanelContainer +class_name GamePanel extends MarginContainer const notice_template = preload("res://notice_panel.tscn") const quest_progress_bar_template = preload("res://quest_progress_bar.tscn") @@ -24,8 +24,8 @@ func add_quest_progress_bar(quest : Quest) -> void: func switch_panel(active : bool) -> void: - %Active.visible = active - %Passive.visible = !active + %OpenList.visible = active + %WorkingList.visible = !active func _on_end_shift_pressed() -> void: @@ -39,11 +39,11 @@ func connect_visitor_spawner(spawner : VisitorSpawner) -> void: update_visitor_count(spawner.total_visitors - spawner.visitors_remaining, spawner.total_visitors) func update_visitor_count(current : int, total : int) -> void: - %Passive/VisitorsLabel.text = "Visitors: %d/%d" % [current, total] + %OpenList/VisitorsLabel.text = "Visitors: %d/%d" % [current, total] func notice(msg : String, time : float) -> void: var ntc : NoticePanel = notice_template.instantiate() - $MarginContainer.add_child(ntc) + %Notices.add_child(ntc) ntc.message = msg ntc.duration = time diff --git a/main_panel.tscn b/main_panel.tscn index 79bb45e..1bdc5c2 100644 --- a/main_panel.tscn +++ b/main_panel.tscn @@ -1,91 +1,119 @@ -[gd_scene load_steps=3 format=3 uid="uid://c8ofw6na082gv"] +[gd_scene load_steps=6 format=3 uid="uid://c8ofw6na082gv"] [ext_resource type="Script" uid="uid://dhw85vqlvw33s" path="res://main_panel.gd" id="1_pdekv"] [ext_resource type="Script" uid="uid://4jrp67ckp7vt" path="res://timer_label.gd" id="2_5rs2c"] +[ext_resource type="StyleBox" uid="uid://by1jk8r2avjp4" path="res://styles/open_shift_panel.tres" id="2_b7y1i"] +[ext_resource type="StyleBox" uid="uid://b7vjpwageyi6m" path="res://styles/working_shift_panel.tres" id="4_b7y1i"] -[node name="MainPanel" type="PanelContainer"] -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -offset_right = -870.0 -offset_bottom = -526.0 -grow_horizontal = 2 -grow_vertical = 2 +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_q6wja"] +content_margin_left = 4.0 +content_margin_top = 4.0 +content_margin_right = 4.0 +content_margin_bottom = 4.0 +bg_color = Color(0.32774815, 0.3295362, 0.561609, 0.6) +corner_radius_top_left = 3 +corner_radius_top_right = 3 +corner_radius_bottom_right = 3 +corner_radius_bottom_left = 3 +corner_detail = 5 + +[node name="MainPanel" type="MarginContainer"] +offset_right = 319.0 +offset_bottom = 189.0 +theme_override_constants/margin_left = 0 +theme_override_constants/margin_top = 0 +theme_override_constants/margin_right = 0 script = ExtResource("1_pdekv") [node name="Timer" type="Timer" parent="."] wait_time = 400000.0 autostart = true -[node name="MarginContainer" type="MarginContainer" parent="."] +[node name="OpenShift" type="PanelContainer" parent="."] +visible = false layout_mode = 2 -theme_override_constants/margin_left = 20 -theme_override_constants/margin_top = 20 -theme_override_constants/margin_right = 20 -theme_override_constants/margin_bottom = 20 +theme_override_styles/panel = ExtResource("2_b7y1i") -[node name="Passive" type="VBoxContainer" parent="MarginContainer"] +[node name="Margin" type="MarginContainer" parent="OpenShift"] +layout_mode = 2 +theme_override_constants/margin_top = -20 +theme_override_constants/margin_right = -80 + +[node name="OpenList" type="VBoxContainer" parent="OpenShift/Margin"] unique_name_in_owner = true layout_mode = 2 +alignment = 1 -[node name="Label" type="Label" parent="MarginContainer/Passive"] +[node name="Label" type="Label" parent="OpenShift/Margin/OpenList"] layout_mode = 2 theme_override_font_sizes/font_size = 28 text = "Time til Next Shift" horizontal_alignment = 1 -[node name="TimerLabel" type="Label" parent="MarginContainer/Passive"] +[node name="TimerLabel" type="Label" parent="OpenShift/Margin/OpenList"] +layout_mode = 2 +theme_override_font_sizes/font_size = 28 +text = "00:00:00.00" +horizontal_alignment = 1 +script = ExtResource("2_5rs2c") + +[node name="VisitorsLabel" type="Label" parent="OpenShift/Margin/OpenList"] layout_mode = 2 theme_override_font_sizes/font_size = 28 text = "000:00:00.00" script = ExtResource("2_5rs2c") -[node name="VisitorsLabel" type="Label" parent="MarginContainer/Passive"] +[node name="Button" type="Button" parent="OpenShift/Margin/OpenList"] layout_mode = 2 -theme_override_font_sizes/font_size = 28 -text = "000:00:00.00" -script = ExtResource("2_5rs2c") +theme_override_styles/normal = SubResource("StyleBoxFlat_q6wja") +text = "CLOSE GUILD" -[node name="QuestProgressList" type="ScrollContainer" parent="MarginContainer/Passive"] +[node name="WorkingShift" type="PanelContainer" parent="."] +visible = false +layout_mode = 2 +theme_override_styles/panel = ExtResource("4_b7y1i") + +[node name="MarginContainer" type="MarginContainer" parent="WorkingShift"] +layout_mode = 2 +theme_override_constants/margin_left = -80 +theme_override_constants/margin_top = -20 + +[node name="WorkingList" type="VBoxContainer" parent="WorkingShift/MarginContainer"] unique_name_in_owner = true +layout_mode = 2 + +[node name="Label" type="Label" parent="WorkingShift/MarginContainer/WorkingList"] +layout_mode = 2 +theme_override_font_sizes/font_size = 28 +text = "Time til Next Shift" +horizontal_alignment = 1 + +[node name="TimerLabel" type="Label" parent="WorkingShift/MarginContainer/WorkingList"] +layout_mode = 2 +theme_override_font_sizes/font_size = 28 +text = "000:00:00.00" +script = ExtResource("2_5rs2c") + +[node name="Button" type="Button" parent="WorkingShift/MarginContainer/WorkingList"] +layout_mode = 2 +theme_override_styles/normal = SubResource("StyleBoxFlat_q6wja") +text = "Show Quests" + +[node name="QuestProgressList" type="ScrollContainer" parent="."] +visible = false clip_contents = false custom_minimum_size = Vector2(260, 100) layout_mode = 2 horizontal_scroll_mode = 0 -[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/Passive/QuestProgressList"] +[node name="VBoxContainer" type="VBoxContainer" parent="QuestProgressList"] custom_minimum_size = Vector2(300, 100) layout_mode = 2 -[node name="Active" type="VBoxContainer" parent="MarginContainer"] +[node name="Notices" type="VBoxContainer" parent="."] unique_name_in_owner = true -visible = false layout_mode = 2 -[node name="Label" type="Label" parent="MarginContainer/Active"] -layout_mode = 2 -theme_override_font_sizes/font_size = 28 -text = "Time til Next Shift" -horizontal_alignment = 1 - -[node name="TimerLabel" type="Label" parent="MarginContainer/Active"] -layout_mode = 2 -theme_override_font_sizes/font_size = 28 -text = "00:00:00.00" -horizontal_alignment = 1 -script = ExtResource("2_5rs2c") - -[node name="Label3" type="Label" parent="MarginContainer/Active"] -visible = false -layout_mode = 2 -theme_override_font_sizes/font_size = 28 -text = "00:00:00.00" -horizontal_alignment = 1 - -[node name="Button" type="Button" parent="MarginContainer/Active"] -layout_mode = 2 -text = "END SHIFT" - -[connection signal="time_changed" from="." to="MarginContainer/Passive/TimerLabel" method="_on_time_changed"] -[connection signal="time_changed" from="." to="MarginContainer/Active/TimerLabel" method="_on_time_changed"] -[connection signal="pressed" from="MarginContainer/Active/Button" to="." method="_on_end_shift_pressed"] +[connection signal="time_changed" from="." to="OpenShift/Margin/OpenList/TimerLabel" method="_on_time_changed"] +[connection signal="pressed" from="OpenShift/Margin/OpenList/Button" to="OpenShift" method="_on_end_shift_pressed"] +[connection signal="pressed" from="WorkingShift/MarginContainer/WorkingList/Button" to="OpenShift" method="_on_end_shift_pressed"] diff --git a/open_shift_panel.png b/open_shift_panel.png new file mode 100644 index 0000000000000000000000000000000000000000..71717c6aec92993e7b4f7b42907c2f9985b93757 GIT binary patch literal 2729 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 literal 0 HcmV?d00001 diff --git a/open_shift_panel.png.import b/open_shift_panel.png.import new file mode 100644 index 0000000..f005507 --- /dev/null +++ b/open_shift_panel.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bgf0ow1t18yqf" +path="res://.godot/imported/open_shift_panel.png-b4e397711e29b830c9d9a5e0da2dffec.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://open_shift_panel.png" +dest_files=["res://.godot/imported/open_shift_panel.png-b4e397711e29b830c9d9a5e0da2dffec.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/project.godot b/project.godot index 7d11e05..f9ee753 100644 --- a/project.godot +++ b/project.godot @@ -38,6 +38,10 @@ project/assembly_name="pomchronicles" ] } +[limbo_ai] + +behavior_tree/behavior_tree_default_dir="res://demo/ai/trees" + [rendering] textures/canvas_textures/default_texture_filter=0 diff --git a/quest_board.gd b/quest_board.gd index aa98cee..e0e3fb5 100644 --- a/quest_board.gd +++ b/quest_board.gd @@ -1,8 +1,18 @@ -extends Interactable +class_name QuestBoard extends Interactable @onready var polygon : CollisionPolygon2D = $CollisionPolygon2D @onready var window : QuestBoardWindow = $QuestBoardWindow +var busy : bool + +signal interaction_complete() + +func _ready() -> void: + register_board.call_deferred() + +func register_board() -> void: + Guild.hall.board = self + func _input(event : InputEvent) -> void: var evt : InputEventMouseButton = event as InputEventMouseButton if evt and evt.button_index == MOUSE_BUTTON_LEFT and evt.pressed: @@ -15,3 +25,8 @@ func interact(interactor, type : String = "") -> void: if interactor is Player: window.populate(Guild.quests.keys()) window.popup_centered() + elif type == "quest": + #Go through all quests and create a list of open quests suitable for their level + #If that list is zero, return without giving them a quest + #Else pick a random quest from the list and assign it to them + pass diff --git a/receptionist.tscn b/receptionist.tscn new file mode 100644 index 0000000..a62d960 --- /dev/null +++ b/receptionist.tscn @@ -0,0 +1,43 @@ +[gd_scene load_steps=8 format=3 uid="uid://cf6nnjyp8kv78"] + +[ext_resource type="Script" uid="uid://b2unuudq5qfl" path="res://guild_employee.gd" id="1_vwytd"] +[ext_resource type="Texture2D" uid="uid://cg6ptmynq0aq0" path="res://basic-sprite.png" id="2_dlmqr"] +[ext_resource type="Script" uid="uid://b0q2233msdtgo" path="res://guild_queue.gd" id="3_wurf5"] +[ext_resource type="PackedScene" uid="uid://jbqw0n6dlj08" path="res://speech_bubble.tscn" id="4_dlmqr"] +[ext_resource type="BehaviorTree" uid="uid://dxyx7tjsd7khq" path="res://ai/trees/receptionist.tres" id="7_qmbsn"] + +[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_dlmqr"] +radius = 15.0 +height = 54.0 + +[sub_resource type="BlackboardPlan" id="BlackboardPlan_xsrct"] + +[node name="Receptionist" type="CharacterBody2D"] +modulate = Color(1.7602391, 1.7602391, 1.7602391, 1) +position = Vector2(0, -64) +script = ExtResource("1_vwytd") + +[node name="CollisionShape2D" type="CollisionShape2D" parent="."] +position = Vector2(0, 63.999992) +rotation = 1.5707964 +shape = SubResource("CapsuleShape2D_dlmqr") + +[node name="Sprite2D" type="Sprite2D" parent="."] +modulate = Color(0, 0.40784314, 1, 1) +texture = ExtResource("2_dlmqr") + +[node name="NavigationAgent2D" type="NavigationAgent2D" parent="."] +path_desired_distance = 30.0 +avoidance_enabled = true + +[node name="Queue" type="Node2D" parent="."] +position = Vector2(0, 141) +script = ExtResource("3_wurf5") +direction = Vector2(0, 1) + +[node name="SpeechBubble" parent="." instance=ExtResource("4_dlmqr")] +position = Vector2(44, -77) + +[node name="BTPlayer" type="BTPlayer" parent="."] +behavior_tree = ExtResource("7_qmbsn") +blackboard_plan = SubResource("BlackboardPlan_xsrct") diff --git a/speech_bubble.tscn b/speech_bubble.tscn new file mode 100644 index 0000000..ef93a69 --- /dev/null +++ b/speech_bubble.tscn @@ -0,0 +1,114 @@ +[gd_scene load_steps=8 format=3 uid="uid://jbqw0n6dlj08"] + +[ext_resource type="Texture2D" uid="uid://cbamfadh7wwr7" path="res://speech-blip.png" id="1_ra651"] +[ext_resource type="Script" uid="uid://w57riwplc00t" path="res://speech_bubble.gd" id="2_n7y37"] +[ext_resource type="Texture2D" uid="uid://chnk20ey5qxfh" path="res://speech-emojis.png" id="3_iafp4"] + +[sub_resource type="Animation" id="Animation_bog1h"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Sprite2D3:frame") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [0] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("Sprite2D3:position") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(0, 0)] +} + +[sub_resource type="Animation" id="Animation_13vc8"] +resource_name = "busy" +length = 0.7000034 +loop_mode = 1 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Sprite2D3:frame") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7), +"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1), +"update": 1, +"values": [0, 1, 8, 9, 16, 17, 24, 25] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("Sprite2D3:position") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(0, 0)] +} + +[sub_resource type="Animation" id="Animation_lsinl"] +resource_name = "talk" +length = 0.40000334 +loop_mode = 1 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Sprite2D3:position") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Vector2(0, -3)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("Sprite2D3:frame") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0, 0.1, 0.2, 0.3, 0.4), +"transitions": PackedFloat32Array(1, 1, 1, 1, 1), +"update": 1, +"values": [2, 3, 10, 3, 2] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_uo85v"] +_data = { +&"RESET": SubResource("Animation_bog1h"), +&"busy": SubResource("Animation_13vc8"), +&"talk": SubResource("Animation_lsinl") +} + +[node name="SpeechBubble" type="Sprite2D"] +visible = false +position = Vector2(25, -26) +scale = Vector2(2, 2) +texture = ExtResource("1_ra651") +script = ExtResource("2_n7y37") + +[node name="Sprite2D3" type="Sprite2D" parent="."] +texture = ExtResource("3_iafp4") +hframes = 8 +vframes = 8 + +[node name="AnimationPlayer" type="AnimationPlayer" parent="."] +libraries = { +&"": SubResource("AnimationLibrary_uo85v") +} diff --git a/styles/open_shift_panel.tres b/styles/open_shift_panel.tres new file mode 100644 index 0000000..aa8b89a --- /dev/null +++ b/styles/open_shift_panel.tres @@ -0,0 +1,10 @@ +[gd_resource type="StyleBoxTexture" load_steps=2 format=3 uid="uid://by1jk8r2avjp4"] + +[ext_resource type="Texture2D" uid="uid://bgf0ow1t18yqf" path="res://open_shift_panel.png" id="1_vv6wn"] + +[resource] +texture = ExtResource("1_vv6wn") +texture_margin_left = 40.0 +texture_margin_top = 44.0 +texture_margin_right = 117.0 +texture_margin_bottom = 48.0 diff --git a/styles/working_shift_panel.tres b/styles/working_shift_panel.tres new file mode 100644 index 0000000..c527cf6 --- /dev/null +++ b/styles/working_shift_panel.tres @@ -0,0 +1,10 @@ +[gd_resource type="StyleBoxTexture" load_steps=2 format=3 uid="uid://b7vjpwageyi6m"] + +[ext_resource type="Texture2D" uid="uid://uhovyed0br4e" path="res://working_shift_panel.png" id="1_tfsob"] + +[resource] +texture = ExtResource("1_tfsob") +texture_margin_left = 117.0 +texture_margin_top = 48.0 +texture_margin_right = 48.0 +texture_margin_bottom = 35.0 diff --git a/test_adventurer_sprite.tscn b/test_adventurer_sprite.tscn index 0fb8e29..2812041 100644 --- a/test_adventurer_sprite.tscn +++ b/test_adventurer_sprite.tscn @@ -1,114 +1,35 @@ -[gd_scene load_steps=16 format=3 uid="uid://dew8gxu55ex6q"] +[gd_scene load_steps=7 format=3 uid="uid://dew8gxu55ex6q"] [ext_resource type="Script" uid="uid://cjqumk0kw2vte" path="res://adventurer.gd" id="1_wif60"] -[ext_resource type="Texture2D" uid="uid://bldpiytpdrge6" path="res://icon.svg" id="2_rwbq5"] -[ext_resource type="Texture2D" uid="uid://cbamfadh7wwr7" path="res://speech-blip.png" id="3_71qlo"] -[ext_resource type="Texture2D" uid="uid://1mmg270gotb1" path="res://busy-dots.png" id="4_ay0uu"] -[ext_resource type="Script" uid="uid://w57riwplc00t" path="res://speech_bubble.gd" id="4_rwbq5"] -[ext_resource type="Script" uid="uid://dl3b5aywu1hf6" path="res://fsm/nodes/wait.gd" id="6_1cj4e"] -[ext_resource type="Script" uid="uid://dthatmb3if73u" path="res://fsm/machines/newbie.gd" id="6_snss2"] -[ext_resource type="Script" uid="uid://e8we6nmaob1k" path="res://fsm/nodes/test.gd" id="7_ux5kh"] -[ext_resource type="Script" uid="uid://bewrajxqdutsu" path="res://fsm/interact_with_employee.gd" id="9_snss2"] -[ext_resource type="Script" uid="uid://y85swbbk8kbd" path="res://fsm/nodes/queue.gd" id="10_1cj4e"] -[ext_resource type="Script" uid="uid://b0ewnwcibhu21" path="res://fsm/nodes/leave.gd" id="11_ux5kh"] +[ext_resource type="Texture2D" uid="uid://cg6ptmynq0aq0" path="res://basic-sprite.png" id="2_aos2b"] +[ext_resource type="PackedScene" uid="uid://jbqw0n6dlj08" path="res://speech_bubble.tscn" id="3_aos2b"] +[ext_resource type="BehaviorTree" uid="uid://dght2flegv70i" path="res://ai/trees/adventurer.tres" id="6_006nh"] -[sub_resource type="CircleShape2D" id="CircleShape2D_5n4iw"] -radius = 35.0 +[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_aos2b"] +radius = 15.0 +height = 54.0 -[sub_resource type="Animation" id="Animation_bog1h"] -length = 0.001 -tracks/0/type = "value" -tracks/0/imported = false -tracks/0/enabled = true -tracks/0/path = NodePath("Sprite2D3:frame") -tracks/0/interp = 1 -tracks/0/loop_wrap = true -tracks/0/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 1, -"values": [0] -} - -[sub_resource type="Animation" id="Animation_13vc8"] -resource_name = "busy" -length = 0.7000034 -loop_mode = 1 -tracks/0/type = "value" -tracks/0/imported = false -tracks/0/enabled = true -tracks/0/path = NodePath("Sprite2D3:frame") -tracks/0/interp = 1 -tracks/0/loop_wrap = true -tracks/0/keys = { -"times": PackedFloat32Array(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7), -"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1), -"update": 1, -"values": [0, 1, 2, 3, 4, 5, 6, 0] -} - -[sub_resource type="AnimationLibrary" id="AnimationLibrary_uo85v"] -_data = { -&"RESET": SubResource("Animation_bog1h"), -&"busy": SubResource("Animation_13vc8") -} +[sub_resource type="BlackboardPlan" id="BlackboardPlan_tdl5m"] [node name="AdventurerSprite" type="CharacterBody2D"] script = ExtResource("1_wif60") -interaction_range = null -stop_range = null + +[node name="CollisionShape2D" type="CollisionShape2D" parent="."] +rotation = 1.5707964 +shape = SubResource("CapsuleShape2D_aos2b") [node name="Sprite2D" type="Sprite2D" parent="."] modulate = Color(0, 1, 0, 1) -scale = Vector2(0.5, 0.5) -texture = ExtResource("2_rwbq5") +position = Vector2(0, -64) +texture = ExtResource("2_aos2b") [node name="NavigationAgent2D" type="NavigationAgent2D" parent="."] path_desired_distance = 30.0 avoidance_enabled = true -[node name="CollisionShape2D" type="CollisionShape2D" parent="."] -shape = SubResource("CircleShape2D_5n4iw") +[node name="SpeechBubble" parent="." instance=ExtResource("3_aos2b")] +position = Vector2(44, -141) -[node name="SpeechBubble" type="Sprite2D" parent="."] -visible = false -position = Vector2(39, -42) -texture = ExtResource("3_71qlo") -script = ExtResource("4_rwbq5") - -[node name="Sprite2D3" type="Sprite2D" parent="SpeechBubble"] -position = Vector2(0, -4) -texture = ExtResource("4_ay0uu") -hframes = 2 -vframes = 4 - -[node name="AnimationPlayer" type="AnimationPlayer" parent="SpeechBubble"] -libraries = { -&"": SubResource("AnimationLibrary_uo85v") -} - -[node name="StateMachine" type="Node" parent="."] -script = ExtResource("6_snss2") -starting_state = "Queue" - -[node name="Wait" type="Node" parent="StateMachine"] -script = ExtResource("6_1cj4e") -wait_duration = 3.0 - -[node name="Test" type="Node" parent="StateMachine"] -script = ExtResource("7_ux5kh") -message = "TEST COMPLETE!" - -[node name="Interact With Employee" type="Node" parent="StateMachine"] -script = ExtResource("9_snss2") -employee_name = "Receptionist" -speech_bubble = "Talk" -wait_duration = null -interaction_args = Array[String](["register"]) - -[node name="Queue" type="Node" parent="StateMachine"] -script = ExtResource("10_1cj4e") -employee = "Receptionist" - -[node name="Node" type="Node" parent="StateMachine"] -script = ExtResource("11_ux5kh") +[node name="BTPlayer" type="BTPlayer" parent="."] +behavior_tree = ExtResource("6_006nh") +blackboard_plan = SubResource("BlackboardPlan_tdl5m") diff --git a/test_limbo.gd b/test_limbo.gd new file mode 100644 index 0000000..5360193 --- /dev/null +++ b/test_limbo.gd @@ -0,0 +1,4 @@ +extends CharacterBody2D + + +var busy : bool = false diff --git a/test_limbo.gd.uid b/test_limbo.gd.uid new file mode 100644 index 0000000..4c2ebae --- /dev/null +++ b/test_limbo.gd.uid @@ -0,0 +1 @@ +uid://cgsnqeb1dg23d diff --git a/working_shift_panel.png b/working_shift_panel.png new file mode 100644 index 0000000000000000000000000000000000000000..3da65bad23174c72215693c221870a9070cb9c9a GIT binary patch literal 2705 zcmb_e`#Tei7hf*Ds9ckJ(TZFu8gIGeGUhgyxi8F}#g`Cbgqdq`$PcnWLMm9KJlW+wf-+@z041r3tpJ8*Z0Aqov@ay*S`#Y)%T z$dTRfV|FUKfm7$S83*zd%@Tv7&7zlCm<`r!y4Z@e!uO`` z_};vJ{((aB=5~wT%H9qebDDA=n)(?dcuzbKpdVJs1JG>WIRo&NcMKDr=^G@fNjfoM z#3i#W?UZF|gKx|%aGOof>6)EO2M2j#f_`CJa`)J^$TOQGq~SAVh3mUFcKoJYoi%U#8(t`H2U@ z9jC2XlFP@YALaaHEk9lkdC zaBn5C{It1tRtd@-+|p6#`7!+Qx9>>E$tfA9O51PMJ?k+e)3tYMqF!lzwB9c^*~`gj z0^5L*f0VYo>RG5dy$5*>FW2n^Uuuxs#SU{(5q9 z*WoaTmKM$I9yJ*EXTkKkW>OhNNW?S^4fwvHTX1{{pFA~l)$4xG$%jqMQper>PU*_8 zL&#>=2tUB@hXYj8q|_`ib+V=@tnl;u?&kNqFD>#%pA|%)#+R0V?*wmLI$WCmkkidU zg*&n;#((ScKQ|dS+F3ob!+Ov>!vrO<=!T))W=-6%j)th6Ec0reNu&L* zO}1^(UAYIVY0m~mrL5(kJdxZutJdluc}IH^?91XktM&f+0lNp3mt^IOdI5XoZO>+? zXR@tI@ZoFwGWUIOfcLQ$uQ3}K-iiCO%+ZB`A#gX1_3hr=**_L(zjR#LI+n);xNwsQ+%N$tJW03tW$OAhMomVpJg=hqI#b15C({)|5BuRf|`Y1q2eC5-#0*2m-+3gqSQG?k1TXv^+3<4n z2>)lKy*y2UWTYw(;Q#h|oXx)RN1;$r1q5^#=1{4ZuYR$#RmGvbZ@>;_)HWI6hm0F; zov&Fh)C^_ksOt7bo|Z|?!H<85-+b1Z z)mGh2@^|wvT3ip-#@NJ_&Jewdn}GplD?emLq82>W zx+uRl!&v(HSWz-brTlJ61|PSwJU};?-2ONk|AK(1fd6G*u3>%+)7$m*gNFMJoSRSP zKfE3P5gk*rtl{SF5;;tM!afPIeY9KNwmxN>^eee%wCUfv$u3Y-ipSG>dFm+H0wArHl2gvnHKq)ek z`*@!fH?{%U#VVS^J2uXXVNkpzU`J8JB4e%@B#6xn?o>`jlExXtw*6E~TfAl>i+t z?;qml*p!8lVO86c?n%zWMToM((jfq!yN^*0MPjAWepfNg;Rh0?e0Rhd$0(USe*~`u zx~WF3!Ad?vl5B;}PrMkfl2k5wmxD%$pd?$y-jw2T37H-&>G7(ypI6N7kL>ldE;NJn zAFYbJLyyII_YR;6LyJ`J`TRtGQuS{@I%wt+uvWp$WV z>E@#tN3VmGZ8&xo^XPrY}BAy+C-l}6CJ z#jZ0CEzz6nVj&(teacWq+6D2WS7y+gsWA#t=%ei`;JDRws-Jn5`}E~e8NsfzcHW$8 z#+lEC%sWFJNrYLz>afcvb-o>wt5t0hw0G$ku-}(5&Mf~V`l@HsW)6qeK5(SAMFEC(W(UhB*tshc=lr@~td^b^R6 zb`5GHDDX^8KpS{ChNlYO-Kv|9gunk#5h2uo!exb`mByv=#JvO#AadFCXWeU0?VN%1 zl_wcj(;w9|85rjnD2aFpATQIa$fhKnbYQFKCyPmedPNc}Jh7y9-v}F0!yf}xOjRkc zvbm-1ksvGx#(1n=l0nfP|3tnu&{2s6B*=mZDuM=7!{4fpLWNf^rv8hq!m>fbyp)og zAI~EN7WC1u%P&v&^qx&F7Gn}W@Y$a~Wr#%zkTUsELO#VcDuVfg(2mh#T)FHyjw^1D z3gV8F@DivsO1|1HDnbypF#2Df|9=Da%9m(-`2A6F5gw~6UWBY%hOMKKu%<2oR+~@4 zi2TGmm*4euk&ru{gY$Y#Zqt#eV`rI3?dX4_taz@a7r_6jQ|2z>e%#eqa~M14%$qmS zV`vS$FXu6`9SoxJ;Y()~IcG?