+def build_fov_map(t):
+ """Build Thing's FOV map."""
+ t["fovmap"] = bytearray(b'v' * (world_db["MAP_LENGTH"] ** 2))
+ maptype = ctypes.c_char * len(world_db["MAP"])
+ test = libpr.build_fov_map(t["T_POSY"], t["T_POSX"],
+ maptype.from_buffer(t["fovmap"]),
+ maptype.from_buffer(world_db["MAP"]))
+ if test:
+ raise RuntimeError("Malloc error in build_fov_Map().")
+
+
+def decrement_lifepoints(t):
+ """Decrement t's lifepoints by 1, and if to zero, corpse it.
+
+ If t is the player avatar, only blank its fovmap, so that the client may
+ still display memory data. On non-player things, erase fovmap and memory.
+ """
+ t["T_LIFEPOINTS"] -= 1
+ if 0 == t["T_LIFEPOINTS"]:
+ t["T_TYPE"] = world_db["ThingTypes"][t["T_TYPE"]]["TT_CORPSE_ID"]
+ if world_db["Things"][0] == t:
+ t["fovmap"] = bytearray(b' ' * (world_db["MAP_LENGTH"] ** 2))
+ strong_write(io_db["file_out"], "LOG You die.\n")
+ else:
+ t["fovmap"] = False
+ t["T_MEMMAP"] = False
+ t["T_MEMDEPTHMAP"] = False
+ t["T_MEMTHING"] = []
+ strong_write(io_db["file_out"], "LOG It dies.\n")
+
+
+def mv_yx_in_dir_legal(dir, y, x):
+ """Wrapper around libpr.mv_yx_in_dir_legal to simplify its use."""
+ dir_c = dir.encode("ascii")[0]
+ test = libpr.mv_yx_in_dir_legal_wrap(dir_c, y, x)
+ if -1 == test:
+ raise RuntimeError("Too much wrapping in mv_yx_in_dir_legal_wrap()!")
+ return (test, libpr.result_y(), libpr.result_x())
+
+
+def actor_wait(t):
+ """Make t do nothing (but loudly, if player avatar)."""
+ if t == world_db["Things"][0]:
+ strong_write(io_db["file_out"], "LOG You wait.\n")
+
+
+def actor_move(t):
+ """If passable, move/collide(=attack) thing into T_ARGUMENT's direction."""
+ passable = False
+ move_result = mv_yx_in_dir_legal(t["T_ARGUMENT"], t["T_POSY"], t["T_POSX"])
+ if 1 == move_result[0]:
+ pos = (move_result[1] * world_db["MAP_LENGTH"]) + move_result[2]
+ passable = "." == chr(world_db["MAP"][pos])
+ hitted = [id for id in world_db["Things"]
+ if world_db["Things"][id] != t
+ if world_db["Things"][id]["T_LIFEPOINTS"]
+ if world_db["Things"][id]["T_POSY"] == move_result[1]
+ if world_db["Things"][id]["T_POSX"] == move_result[2]]
+ if len(hitted):
+ hit_id = hitted[0]
+ hitter_name = world_db["ThingTypes"][t["T_TYPE"]]["TT_NAME"]
+ hitter = "You" if t == world_db["Things"][0] else hitter_name
+ hitted_type = world_db["Things"][hit_id]["T_TYPE"]
+ hitted_name = world_db["ThingTypes"][hitted_type]["TT_NAME"]
+ hitted = "you" if hit_id == 0 else hitted_name
+ verb = " wound " if hitter == "You" else " wounds "
+ strong_write(io_db["file_out"], "LOG " + hitter + verb + hitted + \
+ ".\n")
+ decrement_lifepoints(world_db["Things"][hit_id])
+ return
+ dir = [dir for dir in directions_db
+ if directions_db[dir] == t["T_ARGUMENT"]][0]
+ if passable:
+ t["T_POSY"] = move_result[1]
+ t["T_POSX"] = move_result[2]
+ for id in t["T_CARRIES"]:
+ world_db["Things"][id]["T_POSY"] = move_result[1]
+ world_db["Things"][id]["T_POSX"] = move_result[2]
+ build_fov_map(t)
+ strong_write(io_db["file_out"], "LOG You move " + dir + ".\n")
+ else:
+ strong_write(io_db["file_out"], "LOG You fail to move " + dir + ".\n")
+
+
+def actor_pick_up(t):
+ """Make t pick up (topmost?) Thing from ground into inventory."""
+ # Topmostness is actually not defined so far.
+ ids = [id for id in world_db["Things"] if world_db["Things"][id] != t
+ if not world_db["Things"][id]["carried"]
+ if world_db["Things"][id]["T_POSY"] == t["T_POSY"]
+ if world_db["Things"][id]["T_POSX"] == t["T_POSX"]]
+ if len(ids):
+ world_db["Things"][ids[0]]["carried"] = True
+ t["T_CARRIES"].append(ids[0])
+ if t == world_db["Things"][0]:
+ strong_write(io_db["file_out"], "LOG You pick up an object.\n")
+ elif t == world_db["Things"][0]:
+ err = "You try to pick up an object, but there is none."
+ strong_write(io_db["file_out"], "LOG " + err + "\n")
+
+
+def actor_drop(t):
+ """Make t rop Thing from inventory to ground indexed by T_ARGUMENT."""
+ # TODO: Handle case where T_ARGUMENT matches nothing.
+ if len(t["T_CARRIES"]):
+ id = t["T_CARRIES"][t["T_ARGUMENT"]]
+ t["T_CARRIES"].remove(id)
+ world_db["Things"][id]["carried"] = False
+ if t == world_db["Things"][0]:
+ strong_write(io_db["file_out"], "LOG You drop an object.\n")
+ elif t == world_db["Things"][0]:
+ err = "You try to drop an object, but you own none."
+ strong_write(io_db["file_out"], "LOG " + err + "\n")
+
+
+def actor_use(t):
+ """Make t use (for now: consume) T_ARGUMENT-indexed Thing in inventory."""
+ # Original wrongly featured lifepoints increase through consumable!
+ # TODO: Handle case where T_ARGUMENT matches nothing.
+ if len(t["T_CARRIES"]):
+ id = t["T_CARRIES"][t["T_ARGUMENT"]]
+ type = world_db["Things"][id]["T_TYPE"]
+ if world_db["ThingTypes"][type]["TT_CONSUMABLE"]:
+ t["T_CARRIES"].remove(id)
+ del world_db["Things"][id]
+ t["T_SATIATION"] += world_db["ThingTypes"][type]["TT_CONSUMABLE"]
+ strong_write(io_db["file_out"], "LOG You consume this object.\n")
+ else:
+ strong_write(io_db["file_out"], "LOG You try to use this object," +
+ "but fail.\n")
+ else:
+ strong_write(io_db["file_out"], "LOG You try to use an object, but " +
+ "you own none.\n")
+
+
+def thingproliferation(t):
+ """To chance of 1/TT_PROLIFERATE, create t offspring in neighbor cell.
+
+ Naturally only works with TT_PROLIFERATE > 0. The neighbor cell must be
+ passable and not be inhabited by a Thing of the same type, or, if Thing is
+ animate, any other animate Thing. If there are several map cell candidates,
+ one is selected randomly.
+ """
+ def test_cell(t, y, x):
+ if "." == chr(world_db["MAP"][(y * world_db["MAP_LENGTH"]) + x]):
+ for id in [id for id in world_db["Things"]
+ if y == world_db["Things"][id]["T_POSY"]
+ if x == world_db["Things"][id]["T_POSX"]
+ if (t["T_TYPE"] == world_db["Things"][id]["T_TYPE"])
+ or (t["T_LIFEPOINTS"] and
+ world_db["Things"][id]["T_LIFEPOINTS"])]:
+ return False
+ return True
+ return False
+ prolscore = world_db["ThingTypes"][t["T_TYPE"]]["TT_PROLIFERATE"]
+ if prolscore and (1 == prolscore or 1 == (rand.next() % prolscore)):
+ candidates = []
+ for dir in [directions_db[key] for key in directions_db]:
+ mv_result = mv_yx_in_dir_legal(dir, t["T_POSY"], t["T_POSX"])
+ if mv_result[0] and test_cell(t, mv_result[1], mv_result[2]):
+ candidates.append((mv_result[1], mv_result[2]))
+ if len(candidates):
+ i = rand.next() % len(candidates)
+ id = id_setter(-1, "Things")
+ newT = new_Thing(t["T_TYPE"], (candidates[i][0], candidates[i][1]))
+ world_db["Things"][id] = newT
+
+
+def hunger(t):
+ """Decrement t's satiation, dependent on it trigger lifepoint dec chance."""
+ if t["T_SATIATION"] > -32768:
+ t["T_SATIATION"] -= 1
+ testbase = t["T_SATIATION"] if t["T_SATIATION"] >= 0 else -t["T_SATIATION"]
+ if not world_db["ThingTypes"][t["T_TYPE"]]["TT_LIFEPOINTS"]:
+ raise RuntimeError("A thing that should not hunger is hungering.")
+ stomach = int(32767 / world_db["ThingTypes"][t["T_TYPE"]]["TT_LIFEPOINTS"])
+ if int(int(testbase / stomach) / ((rand.next() % stomach) + 1)):
+ if t == world_db["Things"][0]:
+ strong_write(io_db["file_out"], "LOG You suffer from hunger.\n")
+ else:
+ name = world_db["ThingTypes"][t["T_TYPE"]]["TT_NAME"]
+ strong_write(io_db["file_out"], "LOG " + name + \
+ " suffers from hunger.\n")
+ decrement_lifepoints(t)
+
+
+def turn_over():
+ """Run game world and its inhabitants until new player input expected."""
+ id = 0
+ whilebreaker = False
+ while world_db["Things"][0]["T_LIFEPOINTS"]:
+ for id in [id for id in world_db["Things"]]:
+ Thing = world_db["Things"][id]
+ if Thing["T_LIFEPOINTS"]:
+ if not Thing["T_COMMAND"]:
+ update_map_memory(Thing)
+ if 0 == id:
+ whilebreaker = True
+ break
+ # DUMMY: ai(thing)
+ Thing["T_COMMAND"] = 1
+ # DUMMY: try_healing
+ Thing["T_PROGRESS"] += 1
+ taid = [a for a in world_db["ThingActions"]
+ if a == Thing["T_COMMAND"]][0]
+ ThingAction = world_db["ThingActions"][taid]
+ if Thing["T_PROGRESS"] == ThingAction["TA_EFFORT"]:
+ eval("actor_" + ThingAction["TA_NAME"])(Thing)
+ Thing["T_COMMAND"] = 0
+ Thing["T_PROGRESS"] = 0
+ hunger(Thing)
+ thingproliferation(Thing)
+ if whilebreaker:
+ break
+ world_db["TURN"] += 1
+
+
+def new_Thing(type, pos=(0,0)):
+ """Return Thing of type T_TYPE, with fovmap if alive and world active."""
+ thing = {
+ "T_LIFEPOINTS": world_db["ThingTypes"][type]["TT_LIFEPOINTS"],
+ "T_ARGUMENT": 0,
+ "T_PROGRESS": 0,
+ "T_SATIATION": 0,
+ "T_COMMAND": 0,
+ "T_TYPE": type,
+ "T_POSY": pos[0],
+ "T_POSX": pos[1],
+ "T_CARRIES": [],
+ "carried": False,
+ "T_MEMTHING": [],
+ "T_MEMMAP": False,
+ "T_MEMDEPTHMAP": False,
+ "fovmap": False
+ }
+ if world_db["WORLD_ACTIVE"] and thing["T_LIFEPOINTS"]:
+ build_fov_map(thing)
+ return thing
+
+