home · contact · privacy
7DRL: Documentation rump in SERVER_COMMANDS.
[plomrogue] / roguelike-server
index a32a13b0ba6c771ca7c25b41c5350ac5c94a80d1..ece7c86e595c2975966fca584cbfcc2b059be2f8 100755 (executable)
@@ -418,7 +418,7 @@ def play_game():
         obey(read_command(), "in file", do_record=True)
 
 
-def remake_map():
+def make_map():
     """(Re-)make island map.
 
     Let "~" represent water, "." land, "X" trees: Build island shape randomly,
@@ -427,6 +427,7 @@ def remake_map():
     to land. The cycle ends when a land cell is due to be created at the map's
     border. Then put some trees on the map (TODO: more precise algorithm desc).
     """
+    # 7DRL: Also add some ":" cells as land to which plants may proliferate.
 
     def is_neighbor(coordinates, type):
         y = coordinates[0]
@@ -475,10 +476,22 @@ def remake_map():
             world_db["MAP"][pos] = ord("X")
             i_trees += 1
     # This all-too-precise replica of the original C code misses iter_limit().
+    n_colons = int((length ** 2) / 16)  # #
+    i_colons = 0  # #
+    while (i_colons <= n_colons):  # #
+        single_allowed = rand.next() % 256  # #
+        y = rand.next() % length  # #
+        x = rand.next() % length  # #
+        pos = (y * length) + x  # #
+        if ("." == chr(world_db["MAP"][pos])  # #
+          and ((not single_allowed) or is_neighbor((y, x), ":"))):  # #
+            world_db["MAP"][pos] = ord(":")  # #
+            i_colons += 1  # #
 
 
 def update_map_memory(t, age_map=True):
     """Update t's T_MEMMAP with what's in its FOV now,age its T_MEMMEPTHMAP."""
+
     def age_some_memdepthmap_on_nonfov_cells():
         # OUTSOURCED FOR PERFORMANCE REASONS TO libplomrogue.so:
         # ord_v = ord("v")
@@ -494,6 +507,7 @@ def update_map_memory(t, age_map=True):
         memdepthmap = c_pointer_to_bytearray(t["T_MEMDEPTHMAP"])
         fovmap = c_pointer_to_bytearray(t["fovmap"])
         libpr.age_some_memdepthmap_on_nonfov_cells(memdepthmap, fovmap)
+
     if not t["T_MEMMAP"]:
         t["T_MEMMAP"] = bytearray(b' ' * (world_db["MAP_LENGTH"] ** 2))
     if not t["T_MEMDEPTHMAP"]:
@@ -655,7 +669,8 @@ def actor_move(t):
                                      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])
+        passable = "." == chr(world_db["MAP"][pos]) or \
+                   ":" == 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"]
@@ -768,16 +783,18 @@ def thingproliferation(t, prol_map):
     """To chance of 1/TT_PROLIFERATE,create  t offspring in open neighbor cell.
 
     Naturally only works with TT_PROLIFERATE > 0. The neighbor cell must be be
-    marked '.' in prol_map. If there are several map cell candidates, one is
+    marked "." in prol_map. If there are several map cell candidates, one is
     selected randomly.
     """
     # # 7DRL: success increments God's mood
+    # # 7DRL: Things proliferate only on ":" ground.
     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  ord('.') == prol_map[mv_result[1]
+            # if mv_result[0] and  ord(":") == prol_map[mv_result[1]
+            if mv_result[0] and  ord(".") == prol_map[mv_result[1]  # #
                                                       * world_db["MAP_LENGTH"]
                                                       + mv_result[2]]:
                 candidates.append((mv_result[1], mv_result[2]))
@@ -1261,21 +1278,25 @@ def command_makeworld(seed_string):
 
     Seed rand with seed. Do more only with a "wait" ThingAction and
     world["PLAYER_TYPE"] matching ThingType of TT_START_NUMBER > 0. Then,
-    world_db["Things"] emptied, call remake_map() and set
+    world_db["Things"] emptied, call make_map() 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 player's memory map. Write "NEW_WORLD" line to out file.
     """
 
-    def free_pos():
+    # def free_pos(plant=False):
+    def free_pos(plant=False):  # #
         i = 0
         while 1:
             err = "Space to put thing on too hard to find. Map too small?"
             while 1:
                 y = rand.next() % world_db["MAP_LENGTH"]
                 x = rand.next() % world_db["MAP_LENGTH"]
-                if "." == chr(world_db["MAP"][y * world_db["MAP_LENGTH"] + x]):
+                pos = y * world_db["MAP_LENGTH"] + x;
+                if (not plant  # #
+                    and "." == chr(world_db["MAP"][pos])) \
+                   or ":" == chr(world_db["MAP"][pos]):  # #
                     break
                 i += 1
                 if i == 65535:
@@ -1311,18 +1332,22 @@ def command_makeworld(seed_string):
         print("Ignoring: No thing action with name 'wait' defined.")
         return
     world_db["Things"] = {}
-    remake_map()
+    make_map()
     world_db["WORLD_ACTIVE"] = 1
     world_db["TURN"] = 1
     for i in range(world_db["ThingTypes"][playertype]["TT_START_NUMBER"]):
         id = id_setter(-1, "Things")
         world_db["Things"][id] = new_Thing(playertype, free_pos())
+    if not world_db["Things"][0]["fovmap"]:
+        empty_fovmap = bytearray(b" " * world_db["MAP_LENGTH"] ** 2)
+        world_db["Things"][0]["fovmap"] = empty_fovmap
     update_map_memory(world_db["Things"][0])
     for type in world_db["ThingTypes"]:
         for i in range(world_db["ThingTypes"][type]["TT_START_NUMBER"]):
             if type != playertype:
                 id = id_setter(-1, "Things")
-                world_db["Things"][id] = new_Thing(type, free_pos())
+                plantness = world_db["ThingTypes"][type]["TT_PROLIFERATE"]  # #
+                world_db["Things"][id] = new_Thing(type, free_pos(plantness))
     strong_write(io_db["file_out"], "NEW_WORLD\n")
 
 
@@ -1331,6 +1356,7 @@ def command_maplength(maplength_string):
     val = integer_test(maplength_string, 1, 256)
     if None != val:
         world_db["MAP_LENGTH"] = val
+        world_db["MAP"] = False
         set_world_inactive()
         world_db["Things"] = {}
         libpr.set_maplength(val)
@@ -1361,12 +1387,15 @@ def command_worldactive(worldactive_string):
                 if 0 == Thing:
                     player_exists = True
                     break
-            if wait_exists and player_exists and "MAP" in world_db:
+            if wait_exists and player_exists and world_db["MAP"]:
                 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], False)
+                if not world_db["Things"][0]["T_LIFEPOINTS"]:
+                    empty_fovmap = bytearray(b" " * world_db["MAP_LENGTH"] ** 2)
+                    world_db["Things"][0]["fovmap"] = empty_fovmap
                 world_db["WORLD_ACTIVE"] = 1
             else:
                 print("Ignoring: Not all conditions for world activation met.")
@@ -1485,12 +1514,12 @@ def setter_map(maptype):
         val = valid_map_line(str_int, mapline)
         if None != val:
             length = world_db["MAP_LENGTH"]
-            if not "MAP" in world_db:
+            if not world_db["MAP"]:
                 map = bytearray(b' ' * (length ** 2))
             else:
                 map = world_db["MAP"]
             map[val * length:(val * length) + length] = mapline.encode()
-            if not "MAP" in world_db:
+            if not world_db["MAP"]:
                 world_db["MAP"] = map
 
     @test_Thing_id
@@ -1679,6 +1708,7 @@ commands_db = {
     "use": (1, False, play_commander("use", True)),
     "ai": (0, False, command_ai)
 }
+# TODO: Unhandled cases: (Un-)killing animates (esp. player!) with T_LIFEPOINTS.
 
 
 """World state database. With sane default values. (Randomness is in rand.)"""
@@ -1689,6 +1719,7 @@ world_db = {
     "WORLD_ACTIVE": 0,
     "GOD_MOOD": 0,  # #
     "GOD_FAVOR": 0,  # #
+    "MAP": False,
     "ThingActions": {},
     "ThingTypes": {},
     "Things": {}