X-Git-Url: https://plomlompom.com/repos/?a=blobdiff_plain;f=plomrogue-server.py;h=a66e2ae8e92f6376e97bde3d94181b6006ee9c3c;hb=e7310e4bba2ebdc194f079e68530ddd73fe0ba51;hp=15f2c095fc468c0c7b47907105784cc10506f4a4;hpb=ea9b56e85af64ae816c5faea045ffdd004d56472;p=plomrogue diff --git a/plomrogue-server.py b/plomrogue-server.py index 15f2c09..a66e2ae 100755 --- a/plomrogue-server.py +++ b/plomrogue-server.py @@ -7,7 +7,7 @@ import time def strong_write(file, string): - """Apply write(string), flush() and os.fsync() to file.""" + """Apply write(string), flush(), and os.fsync() to file.""" file.write(string) file.flush() os.fsync(file) @@ -134,11 +134,12 @@ def save_world(): def helper(id): string = "" if world_db["Things"][id][key]: - rmap = world_db["Things"][id][key] + map = world_db["Things"][id][key] length = world_db["MAP_LENGTH"] for i in range(length): - line = rmap[i * length:(i * length) + length].decode() - string = string + key + " " + str(i) + quote(line) + "\n" + line = map[i * length:(i * length) + length].decode() + string = string + key + " " + str(i) + " " + quote(line) \ + + "\n" return string return helper @@ -174,7 +175,7 @@ def save_world(): string = string + helper("Things", "T_ID", {"T_CARRIES": False, "carried": False, "T_MEMMAP": mapsetter("T_MEMMAP"), - "T_MEMTHING": memthing, + "T_MEMTHING": memthing, "fovmap": False, "T_MEMDEPTHMAP": mapsetter("T_MEMDEPTHMAP")}) for id in world_db["Things"]: if [] != world_db["Things"][id]["T_CARRIES"]: @@ -253,6 +254,28 @@ def read_command(): def try_worldstate_update(): """Write worldstate file if io_db["worldstate_updateable"] is set.""" if io_db["worldstate_updateable"]: + + def draw_visible_Things(map, run): + for id in world_db["Things"]: + type = world_db["Things"][id]["T_TYPE"] + consumable = world_db["ThingTypes"][type]["TT_CONSUMABLE"] + alive = world_db["ThingTypes"][type]["TT_LIFEPOINTS"] + if (0 == run and not consumable and not alive) \ + or (1 == run and consumable and not alive) \ + or (2 == run and alive): + y = world_db["Things"][id]["T_POSY"] + x = world_db["Things"][id]["T_POSX"] + fovflag = world_db["Things"][0]["fovmap"][(y * length) + x] + if 'v' == chr(fovflag): + c = world_db["ThingTypes"][type]["TT_SYMBOL"] + map[(y * length) + x] = ord(c) + + def write_map(string, map): + for i in range(length): + line = map[i * length:(i * length) + length].decode() + string = string + line + "\n" + return string + inventory = "" if [] == world_db["Things"][0]["T_CARRIES"]: inventory = "(none)\n" @@ -269,10 +292,22 @@ def try_worldstate_update(): str(world_db["Things"][0]["T_POSX"]) + "\n" + \ str(world_db["MAP_LENGTH"]) + "\n" length = world_db["MAP_LENGTH"] - for i in range(length): - line = world_db["MAP"][i * length:(i * length) + length].decode() - string = string + line + "\n" - # TODO: no proper user-subjective map + fov = bytearray(b' ' * (length ** 2)) + for pos in range(length ** 2): + if 'v' == chr(world_db["Things"][0]["fovmap"][pos]): + fov[pos] = world_db["MAP"][pos] + for i in range(3): + draw_visible_Things(fov, i) + string = write_map(string, fov) + mem = world_db["Things"][0]["T_MEMMAP"][:] + for i in range(2): + for memthing in world_db["Things"][0]["T_MEMTHING"]: + type = world_db["Things"][memthing[0]]["T_TYPE"] + consumable = world_db["ThingTypes"][type]["TT_CONSUMABLE"] + if (i == 0 and not consumable) or (i == 1 and consumable): + c = world_db["ThingTypes"][type]["TT_SYMBOL"] + mem[(memthing[1] * length) + memthing[2]] = ord(c) + string = write_map(string, mem) atomic_write(io_db["path_worldstate"], string) strong_write(io_db["file_out"], "WORLD_UPDATED\n") io_db["worldstate_updateable"] = False @@ -334,6 +369,33 @@ def remake_map(): world_db["MAP"] = bytearray(b'.' * (world_db["MAP_LENGTH"] ** 2)) +def update_map_memory(t): + """Update t's T_MEMMAP with what's in its FOV now,age its T_MEMMEPTHMAP.""" + if not t["T_MEMMAP"]: + t["T_MEMMAP"] = bytearray(b' ' * (world_db["MAP_LENGTH"] ** 2)) + if not t["T_MEMDEPTHMAP"]: + t["T_MEMDEPTHMAP"] = bytearray(b' ' * (world_db["MAP_LENGTH"] ** 2)) + for pos in range(world_db["MAP_LENGTH"] ** 2): + if "v" == chr(t["fovmap"][pos]): + t["T_MEMDEPTHMAP"][pos] = ord("0") + if " " == chr(t["T_MEMMAP"][pos]): + t["T_MEMMAP"][pos] = world_db["MAP"][pos] + continue + # TODO: Aging of MEMDEPTHMAP. + for memthing in t["T_MEMTHING"]: + y = world_db["Things"][memthing[0]]["T_POSY"] + x = world_db["Things"][memthing[1]]["T_POSY"] + if "v" == chr(t["fovmap"][(y * world_db["MAP_LENGTH"]) + x]): + t["T_MEMTHING"].remove(memthing) + for id in world_db["Things"]: + type = world_db["Things"][id]["T_TYPE"] + if not world_db["ThingTypes"][type]["TT_LIFEPOINTS"]: + y = world_db["Things"][id]["T_POSY"] + x = world_db["Things"][id]["T_POSY"] + if "v" == chr(t["fovmap"][(y * world_db["MAP_LENGTH"]) + x]): + t["T_MEMTHING"].append((type, y, x)) + + def set_world_inactive(): """Set world_db["WORLD_ACTIVE"] to 0 and remove worldstate file.""" server_test() @@ -381,9 +443,81 @@ def setter(category, key, min, max): return f +def build_fov_map(t): + """Build Thing's FOV map.""" + t["fovmap"] = bytearray(b'v' * (world_db["MAP_LENGTH"] ** 2)) + # DUMMY so far. Just builds an all-visible map. + + +def actor_wait(Thing): + """Do nothing (but loudly, if by player).""" + if Thing == world_db["Things"][0]: + strong_write(io_db["file_out"], "LOG You wait.\n") + + +def actor_move(Thing): + pass + + +def actor_pick_up(Thing): + """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] != Thing + if not world_db["Things"][id]["carried"] + if world_db["Things"][id]["T_POSY"] == Thing["T_POSY"] + if world_db["Things"][id]["T_POSX"] == Thing["T_POSX"]] + if ids: + world_db["Things"][ids[0]]["carried"] = True + Thing["T_CARRIES"].append(ids[0]) + strong_write(io_db["file_out"], "LOG You pick up an object.\n") + else: + err = "You try to pick up an object, but there is none." + strong_write(io_db["file_out"], "LOG " + err + "\n") + + +def actor_drop(Thing): + pass + + +def actor_use(Thing): + pass + + +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"] + if world_db["Things"][id]["T_LIFEPOINTS"]]: + 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 + # DUMMY: hunger + # DUMMY: thingproliferation + if whilebreaker: + break + world_db["TURN"] += 1 + + def new_Thing(type): - """Return prototype for Thing of T_TYPE of type.""" - return { + """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, @@ -396,8 +530,12 @@ def new_Thing(type): "carried": False, "T_MEMTHING": [], "T_MEMMAP": False, - "T_MEMDEPTHMAP": False + "T_MEMDEPTHMAP": False, + "fovmap": False } + if world_db["WORLD_ACTIVE"] and thing["T_LIFEPOINTS"]: + build_fov_map(thing) + return thing def id_setter(id, category, id_store=False, start_at_1=False): @@ -445,9 +583,71 @@ def command_quit(): raise SystemExit("received QUIT command") -def command_thingshere(y, x): - # DUMMY - print("Ignoring not-yet implemented THINGS_HERE command.") +def command_thingshere(str_y, str_x): + """Write to out file list of Things known to player at coordinate y, x.""" + def write_thing_if_here(): + if y == world_db["Things"][id]["T_POSY"] \ + and x == world_db["Things"][id]["T_POSX"] \ + and not world_db["Things"][id]["carried"]: + type = world_db["Things"][id]["T_TYPE"] + name = world_db["ThingTypes"][type]["TT_NAME"] + strong_write(io_db["file_out"], name + "\n") + if world_db["WORLD_ACTIVE"]: + y = integer_test(str_y, 0, 255) + x = integer_test(str_x, 0, 255) + length = world_db["MAP_LENGTH"] + if None != y and None != x and y < length and x < length: + pos = (y * world_db["MAP_LENGTH"]) + x + strong_write(io_db["file_out"], "THINGS_HERE START\n") + if "v" == chr(world_db["Things"][0]["fovmap"][pos]): + for id in world_db["Things"]: + write_thing_if_here() + else: + for id in world_db["Things"]["T_MEMTHING"]: + write_thing_if_here() + strong_write(io_db["file_out"], "THINGS_HERE END\n") + else: + print("Ignoring: Invalid map coordinates.") + else: + print("Ignoring: Command only works on existing worlds.") + + +def play_commander(action, args=False): + """Setter for player's T_COMMAND and T_ARGUMENT, then calling turn_over(). + + T_ARGUMENT is set to direction char if action=="wait",or 8-bit int if args. + """ + + def set_command(): + id = [x for x in world_db["ThingActions"] + if world_db["ThingActions"][x]["TA_NAME"] == action][0] + world_db["Things"][0]["T_COMMAND"] = id + turn_over() + # TODO: call turn_over() + + def set_command_and_argument_int(str_arg): + val = integer_test(str_arg, 0, 255) + if None != val: + world_db["Things"][0]["T_ARGUMENT"] = val + set_command() + else: + print("Ignoring: Argument must be integer >= 0 <=255.") + + def set_command_and_argument_movestring(str_arg): + dirs = {"east": "d", "south-east": "c", "south-west": "x", + "west": "s", "north-west": "w", "north-east": "e"} + if str_arg in dirs: + world_db["Things"][0]["T_ARGUMENT"] = dirs[str_arg] + set_command() + else: + print("Ignoring: Argument must be valid direction string.") + + if action == "move": + return set_command_and_argument_movestring + elif args: + return set_command_and_argument_int + else: + return set_command def command_seedmap(seed_string): @@ -465,7 +665,7 @@ def command_makeworld(seed_string): and set world_db["WORLD_ACTIVE"], world_db["TURN"] to 1. Build new Things according to ThingTypes' TT_START_NUMBERS, with Thing of ID 0 to ThingType of ID = world["PLAYER_TYPE"]. Place Things randomly, and actors not on each - other; init their FOV/memory maps. Write "NEW_WORLD" line to out file. + other. Init player's memory map. Write "NEW_WORLD" line to out file. """ setter(None, "SEED_RANDOMNESS", 0, 4294967295)(seed_string) setter(None, "SEED_MAP", 0, 4294967295)(seed_string) @@ -495,11 +695,14 @@ def command_makeworld(seed_string): for i in range(world_db["ThingTypes"][playertype]["TT_START_NUMBER"]): id = id_setter(-1, "Things") world_db["Things"][id] = new_Thing(playertype) + # TODO: Positioning. + update_map_memory(world_db["Things"][0]) for type in world_db["ThingTypes"]: for i in range(world_db["ThingTypes"][type]["TT_START_NUMBER"]): - id = id_setter(-1, "Things") - world_db["Things"][id] = new_Thing(playertype) - # TODO: position? update FOVs / map memories? (only at the end) + if type != playertype: + id = id_setter(-1, "Things") + world_db["Things"][id] = new_Thing(type) + # TODO: Positioning. strong_write(io_db["file_out"], "NEW_WORLD\n") @@ -515,7 +718,7 @@ def command_worldactive(worldactive_string): An active world can always be set inactive. An inactive world can only be set active with a "wait" ThingAction, and a player Thing (of ID 0). On - activation, rebuild all Things' FOVs and map memories. + activation, rebuild all Things' FOVs, and the player's map memory. """ # In original version, map existence was also tested (unnecessarily?). val = integer_test(worldactive_string, 0, 1) @@ -537,7 +740,11 @@ def command_worldactive(worldactive_string): player_exists = True break if wait_exists and player_exists: - # TODO: rebuild all things' FOVs, map memories + for id in world_db["Things"]: + if world_db["Things"][id]["T_LIFEPOINTS"]: + build_fov_map(world_db["Things"][id]) + if 0 == id: + update_map_memory(world_db["Things"][id]) world_db["WORLD_ACTIVE"] = 1 @@ -648,25 +855,32 @@ def setter_map(maptype): print("Map line length is unequal map width.") else: length = world_db["MAP_LENGTH"] - rmap = None + map = None if not world_db["Things"][command_tid.id][maptype]: - rmap = bytearray(b' ' * (length ** 2)) + map = bytearray(b' ' * (length ** 2)) else: - rmap = world_db["Things"][command_tid.id][maptype] - rmap[val * length:(val * length) + length] = mapline.encode() - world_db["Things"][command_tid.id][maptype] = rmap + map = world_db["Things"][command_tid.id][maptype] + map[val * length:(val * length) + length] = mapline.encode() + world_db["Things"][command_tid.id][maptype] = map return helper def setter_tpos(axis): - """Generate setter for T_POSX or T_POSY of selected Thing.""" + """Generate setter for T_POSX or T_POSY of selected Thing. + + If world is active, rebuilds animate things' fovmap, player's memory map. + """ @test_Thing_id def helper(str_int): val = integer_test(str_int, 0, 255) if None != val: if val < world_db["MAP_LENGTH"]: world_db["Things"][command_tid.id]["T_POS" + axis] = val - # TODO: Delete Thing's FOV, and rebuild it if world is active. + if world_db["WORLD_ACTIVE"] \ + and world_db["Things"][command_tid.id]["T_LIFEPOINTS"]: + build_fov_map(world_db["Things"][command_tid.id]) + if 0 == command_tid.id: + update_map_memory(world_db["Things"][command_tid.id]) else: print("Ignoring: Position is outside of map.") return helper @@ -804,6 +1018,11 @@ commands_db = { "T_MEMTHING": (3, False, command_tmemthing), "T_POSY": (1, False, setter_tpos("Y")), "T_POSX": (1, False, setter_tpos("X")), + "wait": (0, False, play_commander("wait")), + "move": (1, False, play_commander("move")), + "pick_up": (0, False, play_commander("pick_up")), + "drop": (1, False, play_commander("drop", True)), + "use": (1, False, play_commander("use", True)), } @@ -839,7 +1058,6 @@ io_db = { try: opts = parse_command_line_arguments() setup_server_io() - # print("DUMMY: Run game.") if None != opts.replay: replay_game() else: @@ -851,4 +1069,3 @@ except: raise finally: cleanup_server_io() - # print("DUMMY: (Clean up C heap.)")