room.gd 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. extends Node2D
  2. const MOB_CLASS = preload("res://scripts/mob.gd")
  3. const TRANSITION_CLASS = preload("res://scripts/transition.gd")
  4. const CONTAINER_CLASS = preload("res://scripts/container.gd")
  5. const CONVERSATION_SCENE = preload("res://scenes/conversation.tscn")
  6. const TILE_SIZE = 64
  7. const TILE_TYPES = \
  8. {
  9. -1: "impossible", # Nothing can pass
  10. 0: "impossible",
  11. 1: "solid", # Only ghosts can pass
  12. 2: "walkable", # Anything can pass
  13. 3: "solid",
  14. 4: "walkable",
  15. 5: "water" # Flying, aquatic can pass
  16. }
  17. # Another type, lava, only flying and magmic can pass
  18. # Speed to turn probabilities, in percentile
  19. # These approximately fit a square root curve
  20. const SPEED_PROBABILITY = \
  21. [
  22. 0,
  23. 0,
  24. 13,
  25. 19,
  26. 24,
  27. 28,
  28. 31,
  29. 34,
  30. 37,
  31. 40,
  32. 42
  33. ]
  34. var player
  35. var direction_press = false
  36. func _input(event):
  37. var valid = event.is_pressed() && !event.is_echo()
  38. if valid:
  39. if event.is_action("ui_left"):
  40. direction_press = "left"
  41. elif event.is_action("ui_right"):
  42. direction_press = "right"
  43. elif event.is_action("ui_up"):
  44. direction_press = "up"
  45. elif event.is_action("ui_down"):
  46. direction_press = "down"
  47. elif event.is_action("ui_playermenu"):
  48. bring_player_menu()
  49. func get_mobs():
  50. var result = []
  51. for i in get_children():
  52. if i extends MOB_CLASS:
  53. result.append(i)
  54. return result
  55. func get_containers():
  56. var result = []
  57. for i in get_children():
  58. if i extends CONTAINER_CLASS:
  59. result.append(i)
  60. return result
  61. func bring_player_menu():
  62. var pm = player.get_node("canvas").get_node("playermenu")
  63. pm.open_menu()
  64. get_tree().set_pause(true)
  65. func remove_child_player():
  66. # Used to easily remove the player when changing rooms
  67. remove_child(player)
  68. func redraw(item):
  69. # This method displays the item in the correct coordinate
  70. var x = item.x
  71. var y = item.y
  72. item.set_pos(Vector2((x + 0.5) * TILE_SIZE, (y + 0.5) * TILE_SIZE))
  73. func opposite_dir(direction):
  74. if direction == "up":
  75. return "down"
  76. elif direction == "down":
  77. return "up"
  78. elif direction == "left":
  79. return "right"
  80. else:
  81. return "left"
  82. func open_conversation(mob):
  83. var conv = CONVERSATION_SCENE.instance()
  84. conv.npc = mob
  85. conv.npc_name = mob.name
  86. conv.conversation_tree = mob.conversations
  87. get_node("canvas").add_child(conv)
  88. get_tree().set_pause(true)
  89. func check_tile(mob, direction):
  90. var x = mob.x
  91. var y = mob.y
  92. if direction == "up":
  93. y -= 1
  94. elif direction == "down":
  95. y += 1
  96. elif direction == "right":
  97. x += 1
  98. else:
  99. x -= 1
  100. var tile_result = mob.can_walk(TILE_TYPES[get_node("tiles").get_cell(x,y)])
  101. var mob_result = false
  102. var container_result = false
  103. if not tile_result:
  104. return ["bad", false]
  105. for i in get_mobs():
  106. if i.x == x and i.y == y:
  107. mob_result = i
  108. break
  109. if mob_result:
  110. return ["mob", mob_result]
  111. for i in get_containers():
  112. if i.x == x and i.y == y:
  113. container_result = i
  114. break
  115. if container_result:
  116. return ["container", container_result]
  117. return ["normal", false]
  118. func mobs_turn():
  119. for i in get_mobs():
  120. if not (i.is_player or i.dead):
  121. mob_take_turn(i)
  122. # Based on speed, the mob may take a turn again
  123. while (randi() % 100 < SPEED_PROBABILITY[i.effective_speed()]):
  124. mob_take_turn(i)
  125. func mob_take_turn(mob):
  126. var mobloc = Vector2(mob.x, mob.y)
  127. # Check whether the mob can attack
  128. for i in get_mobs():
  129. if mob != i and mob.in_attack_range(i) and mob.is_enemy(i):
  130. mob.melee_attack(i)
  131. return
  132. # Otherwise, move
  133. if mob.movement == mob.ROAM:
  134. wander_mob(mob)
  135. elif mob.movement == mob.SEARCH:
  136. for i in get_mobs():
  137. if mob != i and mob.in_vision_range(i) and mob.is_enemy(i):
  138. var dirs = mob.direction_towards(i)
  139. var walk_type = check_tile(mob, dirs[0])
  140. if walk_type[0] == "normal":
  141. move_mob(mob, dirs[0])
  142. else:
  143. move_mob(mob, dirs[1])
  144. return
  145. wander_mob(mob)
  146. func wander_mob(mob):
  147. var i = randi() % 4
  148. var direction
  149. if i == 0:
  150. direction = "up"
  151. elif i == 1:
  152. direction = "down"
  153. elif i == 2:
  154. direction = "left"
  155. else:
  156. direction = "right"
  157. move_mob(mob, direction)
  158. func move_mob(mob, dir):
  159. var walk_type = check_tile(mob, dir)
  160. if walk_type[0] == "normal":
  161. mob.move(dir)
  162. redraw(mob)
  163. func _process(delta):
  164. if direction_press:
  165. var direction = direction_press
  166. direction_press = false
  167. var walk_type = check_tile(player, direction)
  168. assert(walk_type[0] in ["bad", "normal", "mob", "container"])
  169. if walk_type[0] == "bad":
  170. player.face(direction)
  171. elif walk_type[0] == "normal":
  172. move_mob(player, direction)
  173. if (randi() % 100 >= SPEED_PROBABILITY[player.effective_speed()]):
  174. mobs_turn()
  175. elif walk_type[0] == "mob":
  176. var mob = walk_type[1]
  177. if mob.disposition < 0:
  178. player.face(direction)
  179. mob.face(opposite_dir(direction))
  180. player.melee_attack(mob)
  181. if (randi() % 100 >= SPEED_PROBABILITY[player.effective_speed()]):
  182. mobs_turn()
  183. else:
  184. player.face(direction)
  185. mob.face(opposite_dir(direction))
  186. open_conversation(mob)
  187. elif walk_type[0] == "container":
  188. player.face(direction)
  189. else:
  190. print("walk_type not understood")
  191. func _ready():
  192. player = get_node("/root/game").player
  193. # Calculate mob location based on initial position
  194. for i in get_children():
  195. if (i extends MOB_CLASS and i != player) or i extends TRANSITION_CLASS or i extends CONTAINER_CLASS:
  196. var position = i.get_pos()
  197. i.x = int(round((position.x - 32) / TILE_SIZE))
  198. i.y = int(round((position.y - 32) / TILE_SIZE))
  199. # Check if the NPC is dead already
  200. if i extends MOB_CLASS and i.id != "respawnable" and i.id in get_node("/root/game").dead_npcs:
  201. i.start_dead()
  202. redraw(i)
  203. set_process_input(true)
  204. set_process(true)