1function select_target_actor(src_actor)
2   local var_10 = 0x7fff
3   local target_actor
4   for i=0,0xff do
5      local actor = Actor.get(i)
6      local actor_align = actor.align
7      local actor_obj_n = actor.obj_n
8      local src_actor_align = src_actor.align
9      local src_actor_obj_n = src_actor.obj_n
10      if actor_obj_n ~= 0 and actor.alive and actor.visible and actor.actor_num ~= src_actor.actor_num and actor_obj_n ~= 381 then --OBJ_DUST_DEVIL
11         if src_actor_align ~= ALIGNMENT_NEUTRAL or actor_align ~= ALIGNMENT_NEUTRAL then
12            if src_actor_align ~= ALIGNMENT_CHAOTIC or (src_actor_obj_n ~= actor_obj_n
13                    and (src_actor_obj_n ~= 372 or (actor_obj_n ~= 370 and actor_obj_n ~= 371))
14                    and ((src_actor_obj_n ~= 362 and src_actor_obj_n ~= 373 and src_actor_obj_n ~= 254)
15                        or (actor_obj_n ~= 362 and actor_obj_n ~= 373 and actor_obj_n ~= 254)))
16                    and (src_actor_align ~= ALIGNMENT_GOOD or actor_align == ALIGNMENT_EVIL or actor_align == ALIGNMENT_CHAOTIC)
17                    and (src_actor_align ~= ALIGNMENT_EVIL or actor_align == ALIGNMENT_GOOD or actor_align == ALIGNMENT_CHAOTIC)
18                    and actor_find_max_wrapped_xy_distance(src_actor, actor.x, actor.y) <= 0xb
19                    and (actor.wt ~= 7 or actor_find_max_wrapped_xy_distance(Actor.get_player_actor(), actor.x, actor.y) <= 5)
20             then
21               local var_C = get_wrapped_dist(actor.x, src_actor.x)^2 + get_wrapped_dist(actor.y, src_actor.y)^2
22               if var_C < var_10
23                       or (var_C == var_10 and actor_get_damage(actor) > actor_get_damage(target_actor)) then
24                  var_10 = var_C
25                  target_actor = actor
26               end
27            end
28         end
29      end
30   end
31   return target_actor
32end
33
34function worktype_8_combat_attack(actor)
35   g_selected_obj = select_target_actor(actor)
36
37end
38
39function worktype_15_your_mother(actor)
40   if actor_move(actor, DIR_SOUTH) == false then
41      local target_actor = select_target_actor(actor)
42      if target_actor ~= nil then
43         --FIXME do combat range check. sub_1B305
44         actor_take_hit(actor, target_actor, 6, 0)
45      end
46   end
47   subtract_movement_pts(actor, 3)
48end
49
50function worktype_stomp_around(actor)
51   subtract_movement_pts(actor, 5)
52   if actor.obj_n == 398 and g_current_dream_stage == 0x44 then
53      if math.random(0, 1) == 0 then
54         play_md_sfx(0, true)
55         quake_start(1,50)
56      else
57         return
58      end
59   end
60
61   local direction = math.random(0, 3)
62   actor_move(actor, direction, 0)
63   for obj in objs_at_loc(actor.xyz) do
64      actor_hit(obj, math.random(0, 0xa) + math.random(0, 0xa), 0)
65   end
66
67end
68
69function worktype_16_minotaur(actor)
70   if g_current_dream_stage == 0x60 then
71      Actor.kill(actor)
72      return
73   end
74
75   local dream_actor = Actor.get(0)
76   local target
77   if Actor.inv_has_obj_n(dream_actor, 162) then --OBJ_RED_CAPE
78      target = dream_actor
79      g_selected_obj = target
80   else
81      for obj in find_obj_from_area(0x21, 0x33, 2, 0x1c, 0x10) do
82         if obj.obj_n == 162 then --OBJ_RED_CAPE
83            target = obj
84         end
85      end
86   end
87
88   if target == nil then
89      worktype_stomp_around(actor)
90      return
91   end
92
93   if actor_get_combat_range(actor, target.x, target.y) <= 1 then
94      if target.luatype == "actor" then
95         attack_target_with_weapon(actor, target.x, target.y, actor)
96         subtract_movement_pts(actor, 0xa)
97         return
98      end
99
100      hit_target(target, RED_HIT_TILE)
101      if not Actor.get_talk_flag(0x54, 6) and target.x >= 0x37 and target.y <= 0x37 then
102         complete_tiffany_stage()
103         return
104      end
105   end
106
107   actor_move_towards_loc(actor, target.x, target.y)
108   play_md_sfx(0, true)
109   quake_start(1,50)
110   for obj in objs_at_loc(actor.xyz) do
111      actor_hit(obj, math.random(1, 0xa) + math.random(1, 0xa), 0)
112   end
113   subtract_movement_pts(actor, 5)
114
115end
116
117
118
119function worktype_99_coker_move_to_coal_vein(actor)
120   if actor_move(actor, DIR_NORTH) == false then
121      local vein = map_get_obj(actor.x, actor.y-1, actor.z, 446) --OBJ_VEIN_OF_COAL FIXME should be -2 not -1 need to fix actor_move for coker.
122      if vein ~= nil then
123         if map_is_on_screen(actor.x, actor.y, actor.z) then
124            play_md_sfx(0x10)
125         end
126         actor.wt = 0x9A
127      end
128   end
129end
130
131function worktype_9A_coker_drop_coal(actor)
132   local obj = map_get_obj(actor.x, actor.y+1, actor.z, 188) --OBJ_CONVEYOR_BELT
133   if obj ~= nil then
134      local coal = Obj.new(447) --OBJ_HUGE_LUMP_OF_COAL
135      Obj.moveToMap(coal, actor.x, actor.y+1, actor.z)
136   else
137      obj = map_get_obj(actor.x, actor.y+1, actor.z, 192) --OBJ_BARE_ROLLERS
138      if obj == nil then
139         actor_move(actor, DIR_SOUTH)
140         return
141      end
142   end
143   actor.wt = 0x9B
144end
145
146function worktype_9B_coker_wait_for_coal_to_move_away(actor)
147   local obj = map_get_obj(actor.x, actor.y+1, actor.z, 447) --OBJ_HUGE_LUMP_OF_COAL
148   if obj == nil then
149      obj = map_get_obj(actor.x, actor.y+1, actor.z, 192) --OBJ_BARE_ROLLERS
150      if obj == nil then
151         actor.wt = 0x99
152      end
153   end
154end
155
156function worktype_9D_stoker_wait_for_coal(actor)
157   local coal
158   coal = map_get_obj(actor.x, actor.y+1, actor.z, 447) --OBJ_HUGE_LUMP_OF_COAL
159
160   if coal ~= nil then
161      while coal ~= nil do
162         Obj.removeFromEngine(coal)
163         coal = map_get_obj(actor.x, actor.y+1, actor.z, 447) --OBJ_HUGE_LUMP_OF_COAL
164      end
165      actor.wt = 0x9E
166   end
167
168end
169
170function worktype_9E_stoker_walk_to_furnace(actor)
171   if actor_move(actor, DIR_NORTH) == false then
172      local furnace = map_get_obj(actor.x, actor.y-1, actor.z, 233)
173      if furnace == nil then
174         furnace = map_get_obj(actor.x+1, actor.y-1, actor.z, 233)
175      end
176
177      if furnace ~= nil then
178         if Actor.get_talk_flag(0x72, 2) == false then
179            activate_power_system()
180         else
181            if Actor.get_talk_flag(0x73, 2) == false or Actor.get_talk_flag(0x71, 3) == true then
182               if Actor.get_talk_flag(0x71, 3) == true then
183                  Actor.clear_talk_flag(0x73, 2)
184                  Actor.clear_talk_flag(0x71, 3)
185                  --FIXME sub_3F740
186               end
187               Actor.set_talk_flag(0x73, 2)
188               activate_power_update_tiles()
189               activate_tower_electricity()
190               midgame_cutscene_2()
191            end
192         end
193         actor.wt = 0x9C
194      else
195         stoker_blocked(actor)
196      end
197   end
198end
199
200function activate_tower_electricity()
201   for obj in find_obj(0, 201) do --OBJ_TOWER_TOP
202      if obj ~= nil then
203         if obj.x >= 0x3d0 and obj.x <= 0x3f0 and obj.y >= 0x1d0 and obj.y <= 0x1e7 then
204            local frame_n = obj.frame_n
205            obj.frame_n = bit32.bor(frame_n, 4)
206         end
207      end
208   end
209
210   for obj in find_obj(0, 214) do --OBJ_POWER_CABLE
211      if obj ~= nil then
212         if obj.x >= 0x3d0 and obj.x <= 0x3f0 and obj.y >= 0x1d0 and obj.y <= 0x1e7 then
213            obj.obj_n = 215 --OBJ_POWER_CABLE1
214         end
215      end
216   end
217
218end
219
220function stoker_blocked(stoker)
221   if map_is_on_screen(stoker.x, stoker.y, stoker.z) then
222      printl("STOKERS_PATH_IS_BLOCKED")
223      play_md_sfx(0)
224   end
225end
226
227function worktype_9C_stoker_return_to_conveyor_belt(actor)
228   if map_get_obj(actor.x, actor.y+2, actor.z, 191) == nil then --OBJ_CONVEYOR_BELT2
229      if actor_move(actor, DIR_SOUTH) == false then
230         stoker_blocked(actor)
231      end
232   else
233      actor.wt = 0x9D
234   end
235end
236
237local worktype_tbl = {
238   [0x15]=worktype_15_your_mother,
239   [0x16]=worktype_16_minotaur,
240   [0x99]=worktype_99_coker_move_to_coal_vein,
241   [0x9a]=worktype_9A_coker_drop_coal,
242   [0x9b]=worktype_9B_coker_wait_for_coal_to_move_away,
243   [0x9c]=worktype_9C_stoker_return_to_conveyor_belt,
244   [0x9d]=worktype_9D_stoker_wait_for_coal,
245   [0x9e]=worktype_9E_stoker_walk_to_furnace,
246}
247
248function perform_worktype(actor)
249   --print("wt="..actor.wt.."\n")
250   local mpts = actor.mpts
251   if worktype_tbl[actor.wt] ~= nil then
252      local func = worktype_tbl[actor.wt]
253      func(actor)
254   end
255
256   if mpts == actor.mpts then
257      subtract_movement_pts(actor, 10)
258   end
259end
260