home · contact · privacy
Server/py: Fix map generation bug.
[plomrogue] / plomrogue-server.py
index 5c07f6d73a1acd96a7c3915fc3cac635f8937ce4..de1bd420cd2a54650c1b036798e1686081ec5505 100755 (executable)
@@ -435,6 +435,7 @@ def remake_map():
             return True
         return False
     store_seed = rand.seed
+    rand.seed = world_db["SEED_MAP"]
     world_db["MAP"] = bytearray(b'~' * (world_db["MAP_LENGTH"] ** 2))
     length = world_db["MAP_LENGTH"]
     add_half_width = (not (length % 2)) * int(length / 2)
@@ -604,7 +605,7 @@ def actor_move(t):
             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 + \
+            strong_write(io_db["file_out"], "LOG " + hitter + verb + hitted +
                                             ".\n")
             decrement_lifepoints(world_db["Things"][hit_id])
             return
@@ -655,7 +656,6 @@ def actor_drop(t):
 
 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"]]
@@ -664,6 +664,8 @@ def actor_use(t):
             t["T_CARRIES"].remove(id)
             del world_db["Things"][id]
             t["T_SATIATION"] += world_db["ThingTypes"][type]["TT_CONSUMABLE"]
+            t["T_LIFEPOINTS"] += 1
+            # Wrongly increment HPs is a replica of the original code.
             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," +
@@ -687,7 +689,7 @@ def thingproliferation(t):
                        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 
+                       or (t["T_LIFEPOINTS"] and
                            world_db["Things"][id]["T_LIFEPOINTS"])]:
                 return False
             return True
@@ -706,8 +708,29 @@ def thingproliferation(t):
             world_db["Things"][id] = newT
 
 
+def try_healing(t):
+    """Grow t's HP to a 1/32 chance if < HP max, satiation > 0, and waiting.
+
+    On success, decrease satiation score by 32.
+    """
+    if t["T_SATIATION"] > 0 \
+       and t["T_LIFEPOINTS"] < \
+           world_db["ThingTypes"][t["T_TYPE"]]["TT_LIFEPOINTS"] \
+       and 0 == (rand.next() % 31) \
+       and t["T_COMMAND"] == [id for id in world_db["ThingActions"]
+                              if world_db["ThingActions"][id]["TA_NAME"] ==
+                                 "wait"][0]:
+        t["T_LIFEPOINTS"] += 1
+        t["T_SATIATION"] -= 32
+        if t == world_db["Things"][0]:
+            strong_write(io_db["file_out"], "LOG You heal.\n")
+        else:
+            name = world_db["ThingTypes"][t["T_TYPE"]]["TT_NAME"]
+            strong_write(io_db["file_out"], "LOG " + name + "heals.\n")
+
+
 def hunger(t):
-    """Decrement t's satiation, dependent on it trigger lifepoint dec chance."""
+    """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"]
@@ -719,17 +742,78 @@ def hunger(t):
             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 + \
+            strong_write(io_db["file_out"], "LOG " + name +
                                             " suffers from hunger.\n")
         decrement_lifepoints(t)
 
 
+def get_dir_to_nearest_target(t, c):
+    # Dummy
+    return False
+
+
+def standing_on_consumable(t):
+    """Return True/False whether t is standing on a consumable."""
+    for id in [id for id in world_db["Things"] if world_db["Things"][id] != t
+               if world_db["Things"][id]["T_POSY"] == t["T_POSY"]
+               if world_db["Things"][id]["T_POSX"] == t["T_POSX"]
+               if world_db["ThingTypes"][world_db["Things"][id]["T_TYPE"]]
+                          ["TT_CONSUMABLE"]]:
+        return True
+    return False
+
+
+def get_inventory_slot_to_consume(t):
+    """Return slot Id of strongest consumable in t's inventory, else -1."""
+    cmp_consumability = 0
+    selection = -1
+    i = 0
+    for id in t["T_CARRIES"]:
+        type = world_db["Things"][id]["T_TYPE"]
+        if world_db["ThingTypes"][type]["TT_CONSUMABLE"] > cmp_consumability:
+            cmp_consumability = world_db["ThingTypes"][type]["TT_CONSUMABLE"]
+            selection = i
+        i += 1
+    return selection
+
+
+def ai(t):
+    """Determine next command/argment for actor t via AI algorithms.
+
+    AI will look for, and move towards, enemies (animate Things not of their
+    own ThingType); if they see none, they will consume consumables in their
+    inventory; if there are none, they will pick up what they stand on if they
+    stand on consumables; if they stand on none, they will move towards the
+    next consumable they see or remember on the map; if they see or remember
+    none, they will explore parts of the map unseen since ever or for at least
+    one turn; if there is nothing to explore, they will simply wait.
+    """
+    t["T_COMMAND"] = [id for id in world_db["ThingActions"]
+                      if world_db["ThingActions"][id]["TA_NAME"] == "wait"][0]
+    if not get_dir_to_nearest_target(t, "f"):
+        sel = get_inventory_slot_to_consume(t)
+        if -1 != sel:
+            t["T_COMMAND"] = [id for id in world_db["ThingActions"]
+                              if world_db["ThingActions"][id]["TA_NAME"]
+                                 == "use"][0]
+            t["T_ARGUMENT"] = sel
+        elif standing_on_consumable(t):
+            t["T_COMMAND"] = [id for id in world_db["ThingActions"]
+                              if world_db["ThingActions"][id]["TA_NAME"]
+                                 == "pick_up"][0]
+        elif (not get_dir_to_nearest_target(t, "c")) and \
+             (not get_dir_to_nearest_target(t, "a")):
+            get_dir_to_nearest_target(t, "s")
+
+
 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 not id in world_db["Things"]: # Thing may have been consumed
+                continue                     # during turn …
             Thing = world_db["Things"][id]
             if Thing["T_LIFEPOINTS"]:
                 if not Thing["T_COMMAND"]:
@@ -737,9 +821,9 @@ def turn_over():
                     if 0 == id:
                         whilebreaker = True
                         break
-                    # DUMMY: ai(thing)
+                    ai(Thing)
                     Thing["T_COMMAND"] = 1
-                # DUMMY: try_healing
+                try_healing(Thing)
                 Thing["T_PROGRESS"] += 1
                 taid = [a for a in world_db["ThingActions"]
                           if a == Thing["T_COMMAND"]][0]
@@ -755,7 +839,7 @@ def turn_over():
         world_db["TURN"] += 1
 
 
-def new_Thing(type, pos=(0,0)):
+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"],
@@ -1240,6 +1324,12 @@ def command_taname(name):
     # In contrast to the original,naming won't map a function to a ThingAction.
 
 
+def command_ai():
+    """Call ai() on player Thing, then turn_over()."""
+    ai(world_db["Things"][0])
+    turn_over()
+
+
 """Commands database.
 
 Map command start tokens to ([0]) number of expected command arguments, ([1])
@@ -1290,6 +1380,7 @@ commands_db = {
     "pick_up": (0, False, play_commander("pick_up")),
     "drop": (1, False, play_commander("drop", True)),
     "use": (1, False, play_commander("use", True)),
+    "ai": (0, False, command_ai)
 }