1 # This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3
2 # or any later version. For details on its copyright, license, and warranties,
3 # see the file NOTICE in the root directory of the PlomRogue source package.
6 from server.config.world_data import world_db
9 def command_help(str_int):
10 val = integer_test(str_int, 0, 9)
14 log("[HELP SCREEN 0: help screen list]")
15 log("0 - this screen")
16 log("1 - key bindings")
17 log("2 - environment 1/3")
18 log("3 - environment 2/3")
19 log("4 - environment 3/3")
20 log("5 - other beings")
22 log("7 - restart and replay")
23 log("For more, see ./README or ./README_TCE files.")
27 log("[HELP SCREEN 1: key bindings]")
28 log("movement/eating: w/e/d/c/x/s")
36 log("help screens: 1/2/3/4/5/6/7/8/9")
37 log("help overview: 0")
40 log("[HELP SCREEN 2: environment 1/3]")
41 log("There is mostly solid matter and fluid. "
42 "'_', '.', ':' are ground, '%', '#', 'X' are walls. "
43 "Less thick ones can be eaten."
44 "Background color indicates fluid concentration. "
45 "'O'/'0' is holes; stepping into them is dangerous."
46 "'-' and '+' are cracks in the ground, and may becomes holes. "
47 "'$' is special places that will change you. "
48 "Learn more in HELP SCREEN 3."
52 log("[HELP SCREEN 3: environment 2/3]")
53 log("Use the 'l' command to investigate the environment. "
54 "Its cursor may describe the area pointed at by two numbers: "
55 "ground elevation/matter thickness (left), wetness (right). "
56 "You cannot breathe there if the sum of both is > 5. "
57 "Greater ground elevation means slower movement."
61 log("[HELP SCREEN 4: environment 3/3]")
62 log("Waste will pile up to ground matter an walls. "
63 "Fluid will trickle down into the environment. "
64 "General humidity will sparkle up new fluid on the ground "
66 "Only from there can you drink fluid. "
67 "Much fluid on a ground level tile creates potential for "
68 "cracks to appear there. They may be sealed with waste."
72 log("[HELP SCREEN 5: other beings]")
73 log(" '?' on the memory map indicate sounds of movement. "
74 "You may encounter the sources. They appear as the general "
75 "humidity of the environment grows, grown from its fluids and "
80 log("[HELP SCREEN 6: winning]")
81 log("Find '$' tiles. Don't dump waste and fluids on fields with "
82 "great elevation and wetness sums. Control ground wetness "
83 "by providing great or small ground space for fluid sparkling "
84 "up to concentrate in. "
85 "A special kind of hole will only evolve from a 'O' hole that "
86 "is surrounded by six other holes."
90 log("[HELP SCREEN 7: restart and replay]")
91 log("You can restart in a new game world by running "
92 "./roguelike -n. You can replay a record of your current game"
93 " by running ./roguelike -s."
94 "See file ./README for more details."
98 log("No HELP SCREEN defined for this number.")
103 if not (world_db["WORLD_ACTIVE"]
104 and world_db["Things"][0]["T_LIFEPOINTS"] > 0):
106 world_db["ai"](world_db["Things"][0])
107 world_db["turn_over"]()
111 if not (action_exists("drink") and world_db["WORLD_ACTIVE"]
112 and world_db["Things"][0]["T_LIFEPOINTS"] > 0):
114 pos = world_db["Things"][0]["pos"]
115 if not (chr(world_db["MAP"][pos]) in "0-+"
116 and world_db["wetmap"][pos] > ord("0")):
117 log("NOTHING to drink here.")
119 elif world_db["Things"][0]["T_KIDNEY"] >= 32:
120 log("You're too FULL to drink more.")
122 world_db["set_command"]("drink")
127 if chr(world_db["MAP"][pos]) in "0-+" and \
128 world_db["wetmap"][pos] > ord("0") and t["T_KIDNEY"] < 32:
129 if world_db["Things"][0] == t:
132 world_db["wetmap"][pos] -= 1
136 if not (action_exists("pee") and world_db["WORLD_ACTIVE"]
137 and world_db["Things"][0]["T_LIFEPOINTS"] > 0):
139 if world_db["Things"][0]["T_BLADDER"] < 1:
140 log("NOTHING to drop from empty bladder.")
142 world_db["set_command"]("pee")
146 if t["T_BLADDER"] < 1:
148 if t == world_db["Things"][0]:
149 log("You LOSE fluid.")
150 if not world_db["test_air"](t):
153 if chr(world_db["MAP"][t["pos"]]) not in "*&":
154 world_db["wetmap"][t["pos"]] += 1
158 if not (action_exists("drop") and world_db["WORLD_ACTIVE"]
159 and world_db["Things"][0]["T_LIFEPOINTS"] > 0):
161 if world_db["Things"][0]["T_BOWEL"] < 1:
162 log("NOTHING to drop from empty bowel.")
164 world_db["set_command"]("drop")
170 if t == world_db["Things"][0]:
171 log("You DROP waste.")
172 if not world_db["test_air"](t):
174 if world_db["MAP"][t["pos"]] == ord("+"):
175 world_db["MAP"][t["pos"]] = ord("-")
176 elif world_db["MAP"][t["pos"]] == ord("-"):
177 world_db["MAP"][t["pos"]] = ord("0")
178 elif chr(world_db["MAP"][t["pos"]]) not in "*&":
179 world_db["MAP"][t["pos"]] += 1
183 def play_move(str_arg):
184 if not (action_exists("move") and world_db["WORLD_ACTIVE"]
185 and world_db["Things"][0]["T_LIFEPOINTS"] > 0):
187 from server.config.world_data import directions_db, symbols_passable
188 t = world_db["Things"][0]
189 if not str_arg in directions_db:
190 print("Illegal move direction string.")
192 d = ord(directions_db[str_arg])
193 from server.utils import mv_yx_in_dir_legal
194 move_result = mv_yx_in_dir_legal(chr(d), t["T_POSY"], t["T_POSX"])
195 if 1 == move_result[0]:
196 pos = (move_result[1] * world_db["MAP_LENGTH"]) + move_result[2]
197 hitted = [tid for tid in world_db["Things"]
198 if world_db["Things"][tid]["T_POSY"] == move_result[1]
199 if world_db["Things"][tid]["T_POSX"] == move_result[2]]
201 if t["T_STOMACH"] >= 32 and t["T_KIDNEY"] >= 32:
202 if t == world_db["Things"][0]:
203 log("You're too FULL to suck resources from another creature.")
205 world_db["Things"][0]["T_ARGUMENT"] = d
206 world_db["set_command"]("eat")
209 if world_db["GRACE"] >= 8:
211 if chr(world_db["MAP"][pos]) in legal_targets:
212 if t["T_STOMACH"] >= 32:
213 if t == world_db["Things"][0]:
214 log("You're too FULL to eat.")
216 world_db["Things"][0]["T_ARGUMENT"] = d
217 world_db["set_command"]("eat")
219 if chr(world_db["MAP"][pos]) in symbols_passable:
220 world_db["Things"][0]["T_ARGUMENT"] = d
221 world_db["set_command"]("move")
223 log("You CAN'T eat your way through there.")
226 def suck_out_creature(t, tid):
228 t = world_db["Things"][tid]
230 tid = next(tid for tid in world_db["Things"]
231 if world_db["Things"][tid] == t)
232 room_stomach = 32 - world_db["Things"][0]["T_STOMACH"]
233 room_kidney = 32 - world_db["Things"][0]["T_KIDNEY"]
234 if t["T_STOMACH"] > room_stomach:
235 t["T_STOMACH"] -= room_stomach
236 world_db["Things"][0]["T_STOMACH"] = 32
238 world_db["Things"][0]["T_STOMACH"] + t["T_STOMACH"]
240 if t["T_KIDNEY"] > room_stomach:
241 t["T_KIDNEY"] -= room_stomach
242 world_db["Things"][0]["T_KIDNEY"] = 32
244 world_db["Things"][0]["T_KIDNEY"] + t["T_KIDNEY"]
246 hitted_name = world_db["ThingTypes"][t["T_TYPE"]]["TT_NAME"]
247 log("You SUCK EVERYTHING from " + hitted_name + ", killing them.")
248 world_db["die"](t, "FOO")
249 world_db["suck_out_creature"] = suck_out_creature
253 from server.utils import mv_yx_in_dir_legal, rand
254 from server.config.world_data import symbols_passable
256 move_result = mv_yx_in_dir_legal(chr(t["T_ARGUMENT"]),
257 t["T_POSY"], t["T_POSX"])
258 if 1 == move_result[0]:
259 pos = (move_result[1] * world_db["MAP_LENGTH"]) + move_result[2]
260 hitted = [tid for tid in world_db["Things"]
261 if world_db["Things"][tid]["T_POSY"] == move_result[1]
262 if world_db["Things"][tid]["T_POSX"] == move_result[2]]
265 hitted_tid = world_db["Things"][hit_id]["T_TYPE"]
266 if t == world_db["Things"][0]:
267 if world_db["GRACE"] >= 16:
268 world_db["suck_out_creature"](None, hit_id)
270 hitted_name = world_db["ThingTypes"][hitted_tid]["TT_NAME"]
271 log("You SUCK resources from " + hitted_name + ".")
273 if world_db["GRACE"] >= 16:
274 world_db["suck_out_creature"](t, None)
276 hitter_name = world_db["ThingTypes"][t["T_TYPE"]]["TT_NAME"]
277 log(hitter_name +" SUCKS resources from you.")
278 hitted = world_db["Things"][hit_id]
279 if t["T_STOMACH"] < 32:
280 t["T_STOMACH"] = t["T_STOMACH"] + 1
281 hitted["T_STOMACH"] -= 1
282 if t["T_KIDNEY"] < 32:
283 t["T_KIDNEY"] = t["T_KIDNEY"] + 1
284 hitted["T_KIDNEY"] -= 1
286 passable = chr(world_db["MAP"][pos]) in symbols_passable
287 if passable and t == world_db["Things"][0]:
288 log("You try to EAT, but fail.")
290 height = world_db["MAP"][pos] - ord("0")
291 if t["T_STOMACH"] >= 32:
293 if height == 5 and not \
294 (t == world_db["Things"][0] and world_db["GRACE"] >= 8):
297 if t == world_db["Things"][0]:
299 eaten = (height == 3 and 0 == int(rand.next() % 2)) or \
300 (height == 4 and 0 == int(rand.next() % 5)) or \
301 (height == 5 and 0 == int(rand.next() % 10))
303 world_db["MAP"][pos] = ord("0")
304 if t["T_STOMACH"] > 32:
309 from server.build_fov_map import build_fov_map
310 from server.utils import mv_yx_in_dir_legal, rand
311 from server.config.world_data import symbols_passable
313 move_result = mv_yx_in_dir_legal(chr(t["T_ARGUMENT"]),
314 t["T_POSY"], t["T_POSX"])
315 if 1 == move_result[0]:
316 pos = (move_result[1] * world_db["MAP_LENGTH"]) + move_result[2]
317 hitted = [tid for tid in world_db["Things"]
318 if world_db["Things"][tid]["T_POSY"] == move_result[1]
319 if world_db["Things"][tid]["T_POSX"] == move_result[2]]
322 hitted_tid = world_db["Things"][hit_id]["T_TYPE"]
323 if t == world_db["Things"][0]:
324 if world_db["GRACE"] >= 16:
325 world_db["suck_out_creature"](None, hit_id)
327 hitted_name = world_db["ThingTypes"][hitted_tid]["TT_NAME"]
328 log("You BUMP into " + hitted_name + ".")
330 if world_db["GRACE"] >= 16:
331 world_db["suck_out_creature"](t, None)
333 hitter_name = world_db["ThingTypes"][t["T_TYPE"]]["TT_NAME"]
334 log(hitter_name +" BUMPS into you.")
336 passable = chr(world_db["MAP"][pos]) in symbols_passable
338 t["T_POSY"] = move_result[1]
339 t["T_POSX"] = move_result[2]
340 t["pos"] = move_result[1] * world_db["MAP_LENGTH"] + move_result[2]
341 world_db["soundmap"][t["pos"]] = ord("9")
342 if t == world_db["Things"][0] and world_db["MAP"][t["pos"]] == ord("$"):
343 world_db["MAP"][t["pos"]] = ord("0")
344 log("You feel a strange AURA from this place.")
345 if world_db["GRACE"] == 0:
346 log("You can now eat ALL walls.")
347 elif world_db["GRACE"] == 8:
348 log("You now have a DEATH touch towards other creatures.")
349 elif world_db["GRACE"] == 16:
350 log("You can now LEVITATE over holes.")
351 elif world_db["GRACE"] == 24:
352 log("You are now READY to leave through a special hole.")
353 elif world_db["GRACE"] == 32:
354 log("You already have all the GRACE you can get.")
355 if world_db["GRACE"] <= 24:
356 world_db["GRACE"] += 8
357 elif t == world_db["Things"][0]:
358 log("You try to MOVE there, but fail.")
362 if t == world_db["Things"][0]:
363 if world_db["GRACE"] < 32 and world_db["MAP"][t["pos"]] == ord("&"):
364 log("You feel you need more GRACE to leave through this hole.")
365 elif world_db["GRACE"] >= 32 and world_db["MAP"][t["pos"]] == ord("&"):
366 world_db["die"](t, "You FLY through the hole, into your waking life."
367 "Good bye, and CONGRATULATIONS.")
369 if world_db["GRACE"] >= 24:
371 if chr(world_db["MAP"][t["pos"]]) in "*&":
372 world_db["die"](t, "You FALL into a hole, and die.")
375 world_db["test_hole"] = test_hole
379 if world_db["terrain_fullness"](t["pos"]) > 5:
380 world_db["die"](t, "You SUFFOCATE.")
383 world_db["test_air"] = test_air
387 t["T_LIFEPOINTS"] = 0
388 if t == world_db["Things"][0]:
389 t["fovmap"] = bytearray(b' ' * (world_db["MAP_LENGTH"] ** 2))
390 t["T_MEMMAP"][t["pos"]] = ord("@")
393 if world_db["MAP"][t["pos"]] != ord("$"):
394 world_db["MAP"][t["pos"]] = ord("5")
395 world_db["HUMILITY"] = t["T_KIDNEY"] + t["T_BLADDER"] + \
396 (world_db["wetmap"][t["pos"]] - ord("0"))
397 world_db["wetmap"][t["pos"]] = 0
398 tid = next(tid for tid in world_db["Things"]
399 if world_db["Things"][tid] == t)
400 del world_db["Things"][tid]
401 world_db["die"] = die
405 from server.make_map import new_pos, is_neighbor
406 from server.utils import rand
407 world_db["MAP"] = bytearray(b'5' * (world_db["MAP_LENGTH"] ** 2))
408 length = world_db["MAP_LENGTH"]
409 add_half_width = (not (length % 2)) * int(length / 2)
410 world_db["MAP"][int((length ** 2) / 2) + add_half_width] = ord("4")
412 y, x, pos = new_pos()
413 if "5" == chr(world_db["MAP"][pos]) and is_neighbor((y, x), "4"):
414 if y == 0 or y == (length - 1) or x == 0 or x == (length - 1):
416 world_db["MAP"][pos] = ord("4")
417 n_ground = int((length ** 2) / 16)
419 while (i_ground <= n_ground):
420 single_allowed = rand.next() % 32
421 y, x, pos = new_pos()
422 if "4" == chr(world_db["MAP"][pos]) \
423 and ((not single_allowed) or is_neighbor((y, x), "0")):
424 world_db["MAP"][pos] = ord("0")
426 n_water = int((length ** 2) / 32)
428 while (i_water <= n_water):
429 y, x, pos = new_pos()
430 if ord("0") == world_db["MAP"][pos] and \
431 ord("0") == world_db["wetmap"][pos]:
432 world_db["wetmap"][pos] = ord("3")
436 while (i_altars < n_altars):
437 y, x, pos = new_pos()
438 if ord("0") == world_db["MAP"][pos]:
439 world_db["MAP"][pos] = ord("$")
443 def calc_effort(ta, t):
444 from server.utils import mv_yx_in_dir_legal
445 if ta["TA_NAME"] == "move":
446 move_result = mv_yx_in_dir_legal(chr(t["T_ARGUMENT"]),
447 t["T_POSY"], t["T_POSX"])
448 if 1 == move_result[0]:
449 pos = (move_result[1] * world_db["MAP_LENGTH"]) + move_result[2]
450 if chr(world_db["MAP"][pos]) in "012":
451 narrowness = world_db["MAP"][pos] - ord("0")
452 return 2 ** narrowness
454 world_db["calc_effort"] = calc_effort
458 from server.ai import ai
459 from server.config.actions import action_db
460 from server.update_map_memory import update_map_memory
461 from server.io import try_worldstate_update
462 from server.config.io import io_db
463 from server.utils import rand
464 from server.build_fov_map import build_fov_map
465 while world_db["Things"][0]["T_LIFEPOINTS"]:
466 for tid in [tid for tid in world_db["Things"]]:
467 if not tid in world_db["Things"]:
469 t = world_db["Things"][tid]
470 if t["T_LIFEPOINTS"]:
471 if not (world_db["test_air"](t) and world_db["test_hole"](t)):
473 if not t["T_COMMAND"]:
479 if t["T_LIFEPOINTS"]:
481 taid = [a for a in world_db["ThingActions"]
482 if a == t["T_COMMAND"]][0]
483 ThingAction = world_db["ThingActions"][taid]
484 effort = world_db["calc_effort"](ThingAction, t)
485 if t["T_PROGRESS"] >= effort:
486 action = action_db["actor_" + ThingAction["TA_NAME"]]
488 if t["T_LIFEPOINTS"] <= 0:
492 if t["T_BOWEL"] > 16:
493 if 0 == (rand.next() % (33 - t["T_BOWEL"])):
494 action_db["actor_drop"](t)
495 if t["T_BLADDER"] > 16:
496 if 0 == (rand.next() % (33 - t["T_BLADDER"])):
497 action_db["actor_pee"](t)
498 if 0 == world_db["TURN"] % 5:
503 if t["T_STOMACH"] <= 0:
504 world_db["die"](t, "You DIE of hunger.")
505 elif t["T_KIDNEY"] <= 0:
506 world_db["die"](t, "You DIE of dehydration.")
507 mapsize = world_db["MAP_LENGTH"] ** 2
508 for pos in range(mapsize):
509 wetness = world_db["wetmap"][pos] - ord("0")
510 height = world_db["MAP"][pos] - ord("0")
511 if world_db["MAP"][pos] == ord("-"):
513 elif world_db["MAP"][pos] == ord("+"):
515 elif world_db["MAP"][pos] == ord("$"):
517 if height == -2 and wetness > 1 \
518 and 0 == rand.next() % ((2 ** 10) / (2 ** wetness)):
519 world_db["MAP"][pos] = ord("*")
520 world_db["HUMIDITY"] += wetness
521 if height == -1 and wetness > 1 \
522 and 0 == rand.next() % ((2 ** 9) / (2 ** wetness)):
523 world_db["MAP"][pos] = ord("+")
524 if height == 0 and wetness > 1 \
525 and 0 == rand.next() % ((2 ** 8) / (2 ** wetness)):
526 world_db["MAP"][pos] = ord("-")
527 if ((wetness > 0 and height > 0) or wetness > 1) \
528 and 0 == rand.next() % 16:
529 world_db["wetmap"][pos] -= 1
530 world_db["HUMIDITY"] += 1
531 if world_db["HUMIDITY"] > 0:
532 if world_db["HUMIDITY"] > 2 and 0 == rand.next() % 2:
533 world_db["NEW_SPAWN"] += 1
534 world_db["HUMIDITY"] -= 1
535 if world_db["NEW_SPAWN"] >= 16:
536 world_db["NEW_SPAWN"] -= 16
537 from server.new_thing import new_Thing
539 y = rand.next() % world_db["MAP_LENGTH"]
540 x = rand.next() % world_db["MAP_LENGTH"]
541 if chr(world_db["MAP"][y * world_db["MAP_LENGTH"] + x]) !=\
543 from server.utils import id_setter
544 tid = id_setter(-1, "Things")
545 world_db["Things"][tid] = new_Thing(
546 world_db["PLAYER_TYPE"], (y, x))
547 pos = y * world_db["MAP_LENGTH"] + x
549 positions_to_wet = []
550 for pos in range(mapsize):
551 if chr(world_db["MAP"][pos]) in "0-+" \
552 and world_db["wetmap"][pos] < ord("5"):
553 positions_to_wet += [pos]
554 while world_db["HUMIDITY"] > 0 and len(positions_to_wet) > 0:
555 select = rand.next() % len(positions_to_wet)
556 pos = positions_to_wet[select]
557 world_db["wetmap"][pos] += 1
558 positions_to_wet.remove(pos)
559 world_db["HUMIDITY"] -= 1
560 for pos in range(mapsize):
561 if world_db["soundmap"][pos] > ord("0"):
562 world_db["soundmap"][pos] -= 1
563 from server.utils import libpr
564 libpr.init_score_map()
565 def set_map_score(pos, score):
566 test = libpr.set_map_score(pos, score)
568 raise RuntimeError("No score map allocated for set_map_score().")
569 [set_map_score(pos, 1) for pos in range(mapsize)
570 if world_db["MAP"][pos] == ord("*")]
571 for pos in range(mapsize):
572 if world_db["MAP"][pos] == ord("*"):
573 if libpr.ready_neighbor_scores(pos):
574 raise RuntimeError("No score map allocated for " +
575 "ready_neighbor_scores.()")
578 for i in range(len(dirs)):
579 score += libpr.get_neighbor_score(i)
581 world_db["MAP"][pos] = ord("&")
582 libpr.free_score_map()
583 world_db["TURN"] += 1
584 io_db["worldstate_updateable"] = True
585 try_worldstate_update()
586 world_db["turn_over"] = turn_over
589 def set_command(action):
590 """Set player's T_COMMAND, then call turn_over()."""
591 tid = [x for x in world_db["ThingActions"]
592 if world_db["ThingActions"][x]["TA_NAME"] == action][0]
593 world_db["Things"][0]["T_COMMAND"] = tid
594 world_db["turn_over"]()
595 world_db["set_command"] = set_command
599 """Try "wait" as player's T_COMMAND."""
600 if world_db["WORLD_ACTIVE"]:
601 world_db["set_command"]("wait")
605 length = world_db["MAP_LENGTH"]
607 for i in range(length):
608 line = world_db["wetmap"][i * length:(i * length) + length].decode()
609 string = string + "WETMAP" + " " + str(i) + " " + line + "\n"
610 for i in range(length):
611 line = world_db["soundmap"][i * length:(i * length) + length].decode()
612 string = string + "SOUNDMAP" + " " + str(i) + " " + line + "\n"
616 def soundmapset(str_int, mapline):
617 def valid_map_line(str_int, mapline):
618 from server.utils import integer_test
619 val = integer_test(str_int, 0, 255)
621 if val >= world_db["MAP_LENGTH"]:
622 print("Illegal value for map line number.")
623 elif len(mapline) != world_db["MAP_LENGTH"]:
624 print("Map line length is unequal map width.")
628 val = valid_map_line(str_int, mapline)
630 length = world_db["MAP_LENGTH"]
631 if not world_db["soundmap"]:
632 m = bytearray(b' ' * (length ** 2))
634 m = world_db["soundmap"]
635 m[val * length:(val * length) + length] = mapline.encode()
636 if not world_db["soundmap"]:
637 world_db["soundmap"] = m
640 def wetmapset(str_int, mapline):
641 def valid_map_line(str_int, mapline):
642 from server.utils import integer_test
643 val = integer_test(str_int, 0, 255)
645 if val >= world_db["MAP_LENGTH"]:
646 print("Illegal value for map line number.")
647 elif len(mapline) != world_db["MAP_LENGTH"]:
648 print("Map line length is unequal map width.")
652 val = valid_map_line(str_int, mapline)
654 length = world_db["MAP_LENGTH"]
655 if not world_db["wetmap"]:
656 m = bytearray(b' ' * (length ** 2))
658 m = world_db["wetmap"]
659 m[val * length:(val * length) + length] = mapline.encode()
660 if not world_db["wetmap"]:
661 world_db["wetmap"] = m
664 def write_soundmap():
665 from server.worldstate_write_helpers import write_map
666 length = world_db["MAP_LENGTH"]
667 return write_map(world_db["soundmap"], world_db["MAP_LENGTH"])
671 from server.worldstate_write_helpers import write_map
672 length = world_db["MAP_LENGTH"]
673 visible_wetmap = bytearray(b' ' * (length ** 2))
674 for i in range(length ** 2):
675 if world_db["Things"][0]["fovmap"][i] == ord('v'):
676 visible_wetmap[i] = world_db["wetmap"][i]
677 return write_map(visible_wetmap, world_db["MAP_LENGTH"])
680 def get_dir_to_target(t, target):
682 from server.utils import rand, libpr, c_pointer_to_bytearray
683 from server.config.world_data import symbols_passable
685 def get_map_score(pos):
686 result = libpr.get_map_score(pos)
688 raise RuntimeError("No score map allocated for get_map_score().")
691 def zero_score_map_where_char_on_memdepthmap(c):
692 map = c_pointer_to_bytearray(t["T_MEMDEPTHMAP"])
693 if libpr.zero_score_map_where_char_on_memdepthmap(c, map):
694 raise RuntimeError("No score map allocated for "
695 "zero_score_map_where_char_on_memdepthmap().")
697 def set_map_score(pos, score):
698 test = libpr.set_map_score(pos, score)
700 raise RuntimeError("No score map allocated for set_map_score().")
702 def set_movement_cost_map():
703 copy_memmap = t["T_MEMMAP"][:]
704 copy_memmap.replace(b' ', b'4')
705 memmap = c_pointer_to_bytearray(copy_memmap)
706 if libpr.TCE_set_movement_cost_map(memmap):
707 raise RuntimeError("No movement cost map allocated for "
708 "set_movement_cost_map().")
710 def animates_in_fov(maplength):
711 return [Thing for Thing in world_db["Things"].values()
712 if Thing["T_LIFEPOINTS"] and 118 == t["fovmap"][Thing["pos"]]
713 and (not Thing == t)]
719 except StopIteration:
722 mapsize = world_db["MAP_LENGTH"] ** 2
723 if target == "food" and t["T_MEMMAP"]:
724 return exists(pos for pos in range(mapsize)
725 if ord("2") < t["T_MEMMAP"][pos] < ord("5"))
726 elif target == "fluid_certain" and t["fovmap"]:
727 return exists(pos for pos in range(mapsize)
728 if t["fovmap"] == ord("v")
729 if world_db["MAP"][pos] == ord("0")
730 if world_db["wetmap"][pos] > ord("0"))
731 elif target == "crack" and t["T_MEMMAP"]:
732 return exists(pos for pos in range(mapsize)
733 if t["T_MEMMAP"][pos] == ord("-"))
734 elif target == "fluid_potential" and t["T_MEMMAP"] and t["fovmap"]:
735 return exists(pos for pos in range(mapsize)
736 if t["T_MEMMAP"][pos] == ord("0")
737 if t["fovmap"] != ord("v"))
738 elif target == "space" and t["T_MEMMAP"] and t["fovmap"]:
739 return exists(pos for pos in range(mapsize)
740 if ord("-") <= t["T_MEMMAP"][pos] <= ord("2")
741 if (t["fovmap"] != ord("v")
742 or world_db["terrain_fullness"](pos) < 5))
743 elif target in {"hunt", "flee"} and t["fovmap"]:
744 return exists(Thing for
745 Thing in animates_in_fov(world_db["MAP_LENGTH"])) \
746 or exists(pos for pos in range(mapsize)
747 if world_db["soundmap"][pos] > ord("0")
748 if t["fovmap"][pos] != ord("v"))
751 def init_score_map():
752 mapsize = world_db["MAP_LENGTH"] ** 2
753 test = libpr.TCE_init_score_map()
754 [set_map_score(pos, 65535) for pos in range(mapsize)
755 if chr(t["T_MEMMAP"][pos]) in "5*&"]
756 set_movement_cost_map()
758 raise RuntimeError("Malloc error in init_score_map().")
759 if target == "food" and t["T_MEMMAP"]:
760 [set_map_score(pos, 0) for pos in range(mapsize)
761 if ord("2") < t["T_MEMMAP"][pos] < ord("5")]
762 elif target == "fluid_certain" and t["fovmap"]:
763 [set_map_score(pos, 0) for pos in range(mapsize)
764 if t["fovmap"] == ord("v")
765 if world_db["MAP"][pos] == ord("0")
766 if world_db["wetmap"][pos] > ord("0")]
767 elif target == "crack" and t["T_MEMMAP"]:
768 [set_map_score(pos, 0) for pos in range(mapsize)
769 if t["T_MEMMAP"][pos] == ord("-")]
770 elif target == "fluid_potential" and t["T_MEMMAP"] and t["fovmap"]:
771 [set_map_score(pos, 0) for pos in range(mapsize)
772 if t["T_MEMMAP"][pos] == ord("0")
773 if t["fovmap"] != ord("v")]
774 elif target == "space" and t["T_MEMMAP"] and t["fovmap"]:
775 [set_map_score(pos, 0) for pos in range(mapsize)
776 if ord("-") <= t["T_MEMMAP"][pos] <= ord("2")
777 if (t["fovmap"] != ord("v")
778 or world_db["terrain_fullness"](pos) < 5)]
779 elif target == "search":
780 zero_score_map_where_char_on_memdepthmap(mem_depth_c[0])
781 elif target in {"hunt", "flee"}:
782 [set_map_score(Thing["pos"], 0) for
783 Thing in animates_in_fov(world_db["MAP_LENGTH"])]
784 [set_map_score(pos, 0) for pos in range(mapsize)
785 if world_db["soundmap"][pos] > ord("0")
786 if t["fovmap"][pos] != ord("v")]
788 def rand_target_dir(neighbors, cmp, dirs):
791 for i in range(len(dirs)):
792 if cmp == neighbors[i]:
793 candidates.append(dirs[i])
795 return candidates[rand.next() % n_candidates] if n_candidates else 0
797 def get_neighbor_scores(dirs, eye_pos):
799 if libpr.ready_neighbor_scores(eye_pos):
800 raise RuntimeError("No score map allocated for " +
801 "ready_neighbor_scores.()")
802 for i in range(len(dirs)):
803 scores.append(libpr.get_neighbor_score(i))
806 def get_dir_from_neighbors():
808 dir_to_target = False
811 neighbors = get_neighbor_scores(dirs, eye_pos)
812 minmax_start = 0 if "flee" == target else 65535 - 1
813 minmax_neighbor = minmax_start
814 for i in range(len(dirs)):
815 if ("flee" == target and get_map_score(t["pos"]) < neighbors[i] and
816 minmax_neighbor < neighbors[i] and 65535 != neighbors[i]) \
817 or ("flee" != target and minmax_neighbor > neighbors[i]):
818 minmax_neighbor = neighbors[i]
819 if minmax_neighbor != minmax_start:
820 dir_to_target = rand_target_dir(neighbors, minmax_neighbor, dirs)
822 distance = get_map_score(t["pos"])
825 if not dir_to_target:
826 if attack_distance >= distance:
827 dir_to_target = rand_target_dir(neighbors,
829 elif dir_to_target and fear_distance < distance:
831 return dir_to_target, minmax_neighbor
833 dir_to_target = False
835 run_i = 9 + 1 if "search" == target else 1
837 while run_i and not dir_to_target and \
838 ("search" == target or seeing_thing()):
841 mem_depth_c = b'9' if b' ' == mem_depth_c \
842 else bytes([mem_depth_c[0] - 1])
843 if libpr.TCE_dijkstra_map_with_movement_cost():
844 raise RuntimeError("No score map allocated for dijkstra_map().")
845 dir_to_target, minmax_neighbor = get_dir_from_neighbors()
846 libpr.free_score_map()
847 if dir_to_target and str == type(dir_to_target):
849 from server.utils import mv_yx_in_dir_legal
850 move_result = mv_yx_in_dir_legal(dir_to_target, t["T_POSY"],
852 if 1 != move_result[0]:
854 pos = (move_result[1] * world_db["MAP_LENGTH"]) + move_result[2]
855 hitted = [tid for tid in world_db["Things"]
856 if world_db["Things"][tid]["pos"] == pos]
857 if world_db["MAP"][pos] > ord("2") or len(hitted) > 0:
859 t["T_COMMAND"] = [taid for taid in world_db["ThingActions"]
860 if world_db["ThingActions"][taid]["TA_NAME"]
862 t["T_ARGUMENT"] = ord(dir_to_target)
863 return dir_to_target, minmax_neighbor
864 world_db["get_dir_to_target"] = get_dir_to_target
867 def terrain_fullness(pos):
868 wetness = world_db["wetmap"][pos] - ord("0")
869 if chr(world_db["MAP"][pos]) in "-+":
872 height = world_db["MAP"][pos] - ord("0")
873 return wetness + height
874 world_db["terrain_fullness"] = terrain_fullness
879 if t["T_LIFEPOINTS"] == 0:
882 def standing_on_fluid(t):
883 if world_db["MAP"][t["pos"]] == ord("0") and \
884 world_db["wetmap"][t["pos"]] > ord("0"):
889 def thing_action_id(name):
890 return [taid for taid in world_db["ThingActions"]
891 if world_db["ThingActions"][taid]
892 ["TA_NAME"] == name][0]
894 t["T_COMMAND"] = thing_action_id("wait")
898 "safe_pee": (world_db["terrain_fullness"](t["pos"]) * t["T_BLADDER"]) / 4,
899 "safe_drop": (world_db["terrain_fullness"](t["pos"]) * t["T_BOWEL"]) / 4,
900 "food": 33 - t["T_STOMACH"],
901 "fluid_certain": 33 - t["T_KIDNEY"],
902 "fluid_potential": 32 - t["T_KIDNEY"],
905 from operator import itemgetter
906 needs = sorted(needs.items(), key=itemgetter(1,0))
910 if need[0] == "fix_cracks":
911 if world_db["MAP"][t["pos"]] == ord("-") and \
912 t["T_BOWEL"] > 0 and \
913 world_db["terrain_fullness"](t["pos"]) <= 3:
914 t["T_COMMAND"] = thing_action_id("drop")
916 elif world_db["get_dir_to_target"](t, "crack")[0]:
918 if need[0] in {"fluid_certain", "fluid_potential"}:
919 if standing_on_fluid(t):
920 t["T_COMMAND"] = thing_action_id("drink")
922 elif t["T_BLADDER"] > 0 and \
923 world_db["MAP"][t["pos"]] == ord("0"):
924 t["T_COMMAND"] = thing_action_id("pee")
926 elif need[0] in {"safe_pee", "safe_drop"}:
927 action_name = need[0][len("safe_"):]
928 if world_db["terrain_fullness"](t["pos"]) <= 3:
929 t["T_COMMAND"] = thing_action_id(action_name)
931 test = world_db["get_dir_to_target"](t, "space")
935 elif world_db["terrain_fullness"](t["pos"]) < 5:
936 t["T_COMMAND"] = thing_action_id(action_name)
938 if t["T_STOMACH"] < 32 and \
939 world_db["get_dir_to_target"](t, "food")[0]:
942 if need[0] in {"fluid_certain", "fluid_potential", "food"}:
943 if world_db["get_dir_to_target"](t, need[0])[0]:
945 elif world_db["get_dir_to_target"](t, "hunt")[0]:
947 elif need[0] != "food" and t["T_STOMACH"] < 32 and \
948 world_db["get_dir_to_target"](t, "food")[0]:
950 elif world_db["get_dir_to_target"](t, need[0])[0]:
955 from server.config.io import io_db
956 io_db["worldstate_write_order"] += [["T_STOMACH", "player_int"]]
957 io_db["worldstate_write_order"] += [["T_KIDNEY", "player_int"]]
958 io_db["worldstate_write_order"] += [["T_BOWEL", "player_int"]]
959 io_db["worldstate_write_order"] += [["T_BLADDER", "player_int"]]
960 io_db["worldstate_write_order"] += [[write_wetmap, "func"]]
961 io_db["worldstate_write_order"] += [[write_soundmap, "func"]]
962 io_db["worldstate_write_order"] += [["GRACE", "world_int"]]
963 import server.config.world_data
964 server.config.world_data.symbols_hide = "345"
965 server.config.world_data.symbols_passable = "012-+*&$"
966 server.config.world_data.thing_defaults["T_STOMACH"] = 16
967 server.config.world_data.thing_defaults["T_BOWEL"] = 0
968 server.config.world_data.thing_defaults["T_KIDNEY"] = 16
969 server.config.world_data.thing_defaults["T_BLADDER"] = 0
970 world_db["soundmap"] = bytearray(b"0" * world_db["MAP_LENGTH"] ** 2)
971 world_db["wetmap"] = bytearray(b"0" * world_db["MAP_LENGTH"] ** 2)
972 if not "NEW_SPAWN" in world_db:
973 world_db["NEW_SPAWN"] = 0
974 if not "HUMIDITY" in world_db:
975 world_db["HUMIDITY"] = 0
976 if not "GRACE" in world_db:
977 world_db["GRACE"] = 0
978 io_db["hook_save"] = save_maps
979 import server.config.make_world_helpers
980 server.config.make_world_helpers.make_map = make_map
981 from server.config.commands import commands_db
982 commands_db["THINGS_HERE"] = (2, True, lambda x, y: None)
983 commands_db["HELP"] = (1, False, command_help)
984 commands_db["ai"] = (0, False, command_ai)
985 commands_db["move"] = (1, False, play_move)
986 commands_db["eat"] = (1, False, play_move)
987 commands_db["wait"] = (0, False, play_wait)
988 commands_db["drop"] = (0, False, play_drop)
989 commands_db["drink"] = (0, False, play_drink)
990 commands_db["pee"] = (0, False, play_pee)
991 commands_db["use"] = (1, False, lambda x: None)
992 commands_db["pickup"] = (0, False, lambda: None)
993 commands_db["GRACE"] = (1, False, setter(None, "GRACE", 0, 255))
994 commands_db["NEW_SPAWN"] = (1, False, setter(None, "NEW_SPAWN", 0, 255))
995 commands_db["HUMIDITY"] = (1, False, setter(None, "HUMIDITY", 0, 65535))
996 commands_db["T_STOMACH"] = (1, False, setter("Thing", "T_STOMACH", 0, 255))
997 commands_db["T_KIDNEY"] = (1, False, setter("Thing", "T_KIDNEY", 0, 255))
998 commands_db["T_BOWEL"] = (1, False, setter("Thing", "T_BOWEL", 0, 255))
999 commands_db["T_BLADDER"] = (1, False, setter("Thing", "T_BLADDER", 0, 255))
1000 commands_db["WETMAP"] = (2, False, wetmapset)
1001 commands_db["SOUNDMAP"] = (2, False, soundmapset)
1002 from server.actions import actor_wait
1003 import server.config.actions
1004 server.config.actions.action_db = {
1005 "actor_wait": actor_wait,
1006 "actor_move": actor_move,
1007 "actor_drop": actor_drop,
1008 "actor_drink": actor_drink,
1009 "actor_pee": actor_pee,
1010 "actor_eat": actor_eat,
1013 strong_write(io_db["file_out"], "PLUGIN TheCrawlingEater\n")