home · contact · privacy
Client: Restructure into modules below client/.
[plomrogue] / roguelike-server
index 30f9337d0c2287b912ffc05b436e270cfdd1ef59..f7b2896f104a20fd49ff6cd85ba8b15efc95227e 100755 (executable)
@@ -34,7 +34,7 @@ def prep_library():
     """Prepare ctypes library at ./libplomrogue.so"""
     libpath = ("./libplomrogue.so")
     if not os.access(libpath, os.F_OK):
-        raise SystemExit("No library " + libpath + ", run ./redo first?")
+        raise SystemExit("No library " + libpath + ", run ./build.sh first?")
     libpr = ctypes.cdll.LoadLibrary(libpath)
     libpr.seed_rrand.restype = ctypes.c_uint32
     return libpr
@@ -56,7 +56,7 @@ def setup_server_io():
     """Fill IO files DB with proper file( path)s. Write process IO test string.
 
     Ensure IO files directory at server/. Remove any old input file if found.
-    Set up new input file for reading, and new output file for writing. Start
+    Set up new input file for reading, and new output file for appending. Start
     output file with process hash line of format PID + " " + floated UNIX time
     (io_db["teststring"]). Raise SystemExit if file is found at path of either
     record or save file plus io_db["tmp_suffix"].
@@ -73,7 +73,7 @@ def setup_server_io():
     io_db["verbose"] = False
     io_db["record_chunk"] = ""
     os.makedirs(io_db["path_server"], exist_ok=True)
-    io_db["file_out"] = open(io_db["path_out"], "w")
+    io_db["file_out"] = open(io_db["path_out"], "a")
     strong_write(io_db["file_out"], io_db["teststring"] + "\n")
     if os.access(io_db["path_in"], os.F_OK):
         os.remove(io_db["path_in"])
@@ -585,11 +585,6 @@ def build_fov_map(t):
         raise RuntimeError("Malloc error in build_fov_Map().")
 
 
-def log_help():
-    """Send quick usage info to log."""
-    log("LOG See README file for help.")
-
-
 def decrement_lifepoints(t):
     """Decrement t's lifepoints by 1, and if to zero, corpse it.
 
@@ -648,10 +643,10 @@ def actor_move(t):
             if t == world_db["Things"][0]:
                 hitted_type = world_db["Things"][hit_id]["T_TYPE"]
                 hitted_name = world_db["ThingTypes"][hitted_type]["TT_NAME"]
-                log("You wound " + hitted_name + ".")
+                log("You WOUND" + hitted_name + ".")
             elif 0 == hit_id:
                 hitter_name = world_db["ThingTypes"][t["T_TYPE"]]["TT_NAME"]
-                log(hitter_name +" wounds you.")
+                log(hitter_name +" WOUNDS you.")
             decrement_lifepoints(world_db["Things"][hit_id])
             return
         passable = "." == chr(world_db["MAP"][pos])
@@ -665,9 +660,7 @@ def actor_move(t):
             world_db["Things"][id]["T_POSX"] = move_result[2]
         build_fov_map(t)
         if t == world_db["Things"][0]:
-            log("You move " + dir + ".")
-    elif t == world_db["Things"][0]:
-        log("You fail to move " + dir + ".")
+            log("You MOVE " + dir + ".")
 
 
 def actor_pick_up(t):
@@ -689,9 +682,7 @@ def actor_pick_up(t):
         world_db["Things"][id]["carried"] = True
         t["T_CARRIES"].append(id)
         if t == world_db["Things"][0]:
-                log("You pick up an object.")
-    elif t == world_db["Things"][0]:
-            log("You try to pick up an object, but there is none.")
+                log("You PICK UP an object.")
 
 
 def actor_drop(t):
@@ -702,9 +693,7 @@ def actor_drop(t):
         t["T_CARRIES"].remove(id)
         world_db["Things"][id]["carried"] = False
         if t == world_db["Things"][0]:
-            log("You drop an object.")
-    elif t == world_db["Things"][0]:
-       log("You try to drop an object, but you own none.")
+            log("You DROP an object.")
 
 
 def actor_use(t):
@@ -718,11 +707,9 @@ def actor_use(t):
             del world_db["Things"][id]
             t["T_SATIATION"] += world_db["ThingTypes"][type]["TT_TOOLPOWER"]
             if t == world_db["Things"][0]:
-                log("You consume this object.")
+                log("You CONSUME this object.")
         elif t == world_db["Things"][0]:
-            log("You try to use this object, but fail.")
-    elif t == world_db["Things"][0]:
-        log("You try to use an object, but you own none.")
+            log("You try to use this object, but FAIL.")
 
 
 def thingproliferation(t, prol_map):
@@ -759,7 +746,7 @@ def try_healing(t):
         if (testval <= 1 or 1 == (rand.next() % testval)):
             t["T_LIFEPOINTS"] += 1
             if t == world_db["Things"][0]:
-                log("You heal.")
+                log("You HEAL.")
 
 
 def hunger_per_turn(type_id):
@@ -774,9 +761,9 @@ def hunger(t):
     if 0 != t["T_SATIATION"] and 0 == int(rand.next() / abs(t["T_SATIATION"])):
         if t == world_db["Things"][0]:
             if t["T_SATIATION"] < 0:
-                log("You suffer from hunger.")
+                log("You SUFFER from hunger.")
             else:
-                log("You suffer from over-eating.")
+                log("You SUFFER from over-eating.")
         decrement_lifepoints(t)
 
 
@@ -1148,6 +1135,15 @@ def id_setter(id, category, id_store=False, start_at_1=False):
     return id
 
 
+def command_plugin(str_plugin):
+    """Run code in plugins/[str_plugin]."""
+    if (str_plugin.replace("_", "").isalnum()
+        and os.access("plugins/" + str_plugin, os.F_OK)):
+        exec(open("plugins/" + str_plugin).read())
+        return
+    print("Bad plugin name:", str_plugin)
+
+
 def command_ping():
     """Send PONG line to server output file."""
     strong_write(io_db["file_out"], "PONG\n")
@@ -1194,37 +1190,80 @@ def command_thingshere(str_y, str_x):
         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().
+def set_command(action):
+    """Set player's T_COMMAND, then call turn_over()."""
+    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()
 
-    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()
+def play_wait():
+    """Try "wait" as player's T_COMMAND."""
+    set_command("wait")
+
+
+def play_pickup():
+    """Try "pick_up" as player's T_COMMAND"."""
+    t = world_db["Things"][0]
+    ids = [id for id in world_db["Things"] if id
+           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 not len(ids):
+         log("NOTHING to pick up.")
+    else:
+        set_command("pick_up")
+
 
-    def set_command_and_argument_int(str_arg):
+def play_drop(str_arg):
+    """Try "drop" as player's T_COMMAND, int(str_arg) as T_ARGUMENT / slot."""
+    t = world_db["Things"][0]
+    if 0 == len(t["T_CARRIES"]):
+        log("You have NOTHING to drop in your inventory.")
+    else:
         val = integer_test(str_arg, 0, 255)
-        if None != val:
+        if None != val and val < len(t["T_CARRIES"]):
             world_db["Things"][0]["T_ARGUMENT"] = val
-            set_command()
-
-    def set_command_and_argument_movestring(str_arg):
-        if str_arg in directions_db:
-            world_db["Things"][0]["T_ARGUMENT"] = ord(directions_db[str_arg])
-            set_command()
+            set_command("drop")
         else:
-            print("Ignoring: Argument must be valid direction string.")
+            print("Illegal inventory index.")
+
 
-    if action == "move":
-        return set_command_and_argument_movestring
-    elif args:
-        return set_command_and_argument_int
+def play_use(str_arg):
+    """Try "use" as player's T_COMMAND, int(str_arg) as T_ARGUMENT / slot."""
+    t = world_db["Things"][0]
+    if 0 == len(t["T_CARRIES"]):
+        log("You have NOTHING to use in your inventory.")
     else:
-        return set_command
+        val = integer_test(str_arg, 0, 255)
+        if None != val and val < len(t["T_CARRIES"]):
+            id = t["T_CARRIES"][val]
+            type = world_db["Things"][id]["T_TYPE"]
+            if not world_db["ThingTypes"][type]["TT_TOOL"] == "food":
+                log("You CAN'T consume this thing.")
+                return
+            world_db["Things"][0]["T_ARGUMENT"] = val
+            set_command("use")
+        else:
+            print("Illegal inventory index.")
+
+
+def play_move(str_arg):
+    """Try "move" as player's T_COMMAND, str_arg as T_ARGUMENT / direction."""
+    t = world_db["Things"][0]
+    if not str_arg in directions_db:
+        print("Illegal move direction string.")
+        return
+    dir = ord(directions_db[str_arg])
+    move_result = mv_yx_in_dir_legal(chr(dir), t["T_POSY"], t["T_POSX"])
+    if 1 == move_result[0]:
+        pos = (move_result[1] * world_db["MAP_LENGTH"]) + move_result[2]
+        if ord(".") == world_db["MAP"][pos]:
+            world_db["Things"][0]["T_ARGUMENT"] = dir
+            set_command("move")
+            return
+    log("You CAN'T move there.")
 
 
 def command_seedrandomness(seed_string):
@@ -1244,7 +1283,6 @@ def command_makeworld(seed_string):
     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 player's memory map. Write "NEW_WORLD" line to out file.
-    Call log_help().
     """
 
     def free_pos():
@@ -1307,7 +1345,6 @@ def command_makeworld(seed_string):
                 id = id_setter(-1, "Things")
                 world_db["Things"][id] = new_Thing(type, free_pos())
     strong_write(io_db["file_out"], "NEW_WORLD\n")
-    log_help()
 
 
 def command_maplength(maplength_string):
@@ -1327,7 +1364,6 @@ 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), and a
     map. On activation, rebuild all Things' FOVs, and the player's map memory.
-    Also call log_help().
     """
     val = integer_test(worldactive_string, 0, 1)
     if None != val:
@@ -1357,7 +1393,6 @@ def command_worldactive(worldactive_string):
                     empty_fovmap = bytearray(b" " * world_db["MAP_LENGTH"] ** 2)
                     world_db["Things"][0]["fovmap"] = empty_fovmap
                 world_db["WORLD_ACTIVE"] = 1
-                log_help()
             else:
                 print("Ignoring: Not all conditions for world activation met.")
 
@@ -1629,6 +1664,7 @@ be ignored in replay mode if read from server input file), and ([2]) a function
 to be called on it.
 """
 commands_db = {
+    "PLUGIN": (1, True, command_plugin),
     "QUIT": (0, True, command_quit),
     "PING": (0, True, command_ping),
     "THINGS_HERE": (2, True, command_thingshere),
@@ -1666,11 +1702,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)),
+    "wait": (0, False, play_wait),
+    "move": (1, False, play_move),
+    "pick_up": (0, False, play_pickup),
+    "drop": (1, False, play_drop),
+    "use": (1, False, play_use),
     "ai": (0, False, command_ai)
 }
 # TODO: Unhandled cases: (Un-)killing animates (esp. player!) with T_LIFEPOINTS.