home · contact · privacy
TCE: Add drinking, bladder.
[plomrogue] / plugins / server / TheCrawlingEater.py
1 # This file is part of PlomRogue. PlomRogue is licensed under the GPL version 3
2 # or any later version. For details on its copyright, license, and warranties,
3 # see the file NOTICE in the root directory of the PlomRogue source package.
4
5
6 from server.config.world_data import world_db
7
8
9 def play_drink():
10     if action_exists("drink") and world_db["WORLD_ACTIVE"]:
11         if ord("~") != world_db["MAP"][world_db["Things"][0]["pos"]]:
12             log("Nothing to drink here.")
13             return
14         world_db["set_command"]("drink")
15
16
17 def actor_drink(t):
18     if ord("~") == world_db["MAP"][world_db["Things"][0]["pos"]]:
19         log("You DRINK.")
20         t["T_BLADDER"] += 1
21
22
23 def play_drop():
24     if action_exists("drop") and world_db["WORLD_ACTIVE"]:
25         if world_db["Things"][0]["T_STOMACH"] < 1:
26             log("Nothing to drop from empty stomach.")
27             return
28         world_db["set_command"]("drop")
29
30
31 def actor_drop(t):
32     if t["T_STOMACH"] < 1:
33         return
34     if t == world_db["Things"][0]:
35         log("You DEFECATE.")
36     terrain = world_db["MAP"][t["pos"]]
37     t["T_STOMACH"] -= 1
38     if chr(terrain) == "_":
39         world_db["MAP"][t["pos"]] = ord(".")
40     elif chr(terrain) == ".":
41         world_db["MAP"][t["pos"]] = ord(":")
42     elif chr(terrain) == ":":
43         world_db["MAP"][t["pos"]] = ord("%")
44     elif chr(terrain) == "%":
45         world_db["MAP"][t["pos"]] = ord("#")
46     elif chr(terrain) == "#":
47         world_db["MAP"][t["pos"]] = ord("X")
48     elif chr(terrain) == "X":
49         t["T_LIFEPOINTS"] = 0
50         if t == world_db["Things"][0]:
51             t["fovmap"] = bytearray(b' ' * (world_db["MAP_LENGTH"] ** 2))
52             log("You SUFFOCATE.")
53
54
55 def play_move(str_arg):
56     """Try "move" as player's T_COMMAND, str_arg as T_ARGUMENT / direction."""
57     if action_exists("move") and world_db["WORLD_ACTIVE"]:
58         from server.config.world_data import directions_db, symbols_passable
59         t = world_db["Things"][0]
60         if not str_arg in directions_db:
61             print("Illegal move direction string.")
62             return
63         d = ord(directions_db[str_arg])
64         from server.utils import mv_yx_in_dir_legal
65         move_result = mv_yx_in_dir_legal(chr(d), t["T_POSY"], t["T_POSX"])
66         if 1 == move_result[0]:
67             pos = (move_result[1] * world_db["MAP_LENGTH"]) + move_result[2]
68             if ord("%") == world_db["MAP"][pos] or \
69                     ord("#") == world_db["MAP"][pos]:
70                 world_db["Things"][0]["T_ARGUMENT"] = d
71                 world_db["set_command"]("move")
72                 return
73             if chr(world_db["MAP"][pos]) in symbols_passable:
74                 world_db["Things"][0]["T_ARGUMENT"] = d
75                 world_db["set_command"]("move")
76                 return
77         log("You CAN'T eat your way through there.")
78
79
80 def actor_move(t):
81     from server.build_fov_map import build_fov_map
82     from server.utils import mv_yx_in_dir_legal, rand
83     from server.config.world_data import directions_db, symbols_passable
84     passable = False
85     move_result = mv_yx_in_dir_legal(chr(t["T_ARGUMENT"]),
86                                      t["T_POSY"], t["T_POSX"])
87     if 1 == move_result[0]:
88         pos = (move_result[1] * world_db["MAP_LENGTH"]) + move_result[2]
89         hitted = [tid for tid in world_db["Things"]
90                   if world_db["Things"][tid] != t
91                   if world_db["Things"][tid]["T_LIFEPOINTS"]
92                   if world_db["Things"][tid]["T_POSY"] == move_result[1]
93                   if world_db["Things"][tid]["T_POSX"] == move_result[2]]
94         if len(hitted):
95             hit_id = hitted[0]
96             hitted_tid = world_db["Things"][hit_id]["T_TYPE"]
97             if t == world_db["Things"][0]:
98                 hitted_name = world_db["ThingTypes"][hitted_tid]["TT_NAME"]
99                 log("You BUMP into " + hitted_name + ".")
100             elif 0 == hit_id:
101                 hitter_name = world_db["ThingTypes"][t["T_TYPE"]]["TT_NAME"]
102                 log(hitter_name +" BUMPS into you.")
103             return
104         passable = chr(world_db["MAP"][pos]) in symbols_passable
105     direction = [direction for direction in directions_db
106                  if directions_db[direction] == chr(t["T_ARGUMENT"])][0]
107     if passable:
108         t["T_POSY"] = move_result[1]
109         t["T_POSX"] = move_result[2]
110         t["pos"] = move_result[1] * world_db["MAP_LENGTH"] + move_result[2]
111         build_fov_map(t)
112     else:
113         if t["T_STOMACH"] >= 32:
114             if t == world_db["Things"][0]:
115                 log("You're too FULL to eat.")
116         elif ord("%") == world_db["MAP"][pos] and 0 == int(rand.next() % 2):
117             log("You EAT.")
118             world_db["MAP"][pos] = ord("_")
119             t["T_STOMACH"] += 3
120         elif ord("#") == world_db["MAP"][pos] and 0 == int(rand.next() % 5):
121             log("You EAT.")
122             world_db["MAP"][pos] = ord("_")
123             t["T_STOMACH"] += 4
124         if t["T_STOMACH"] > 32:
125             t["T_STOMACH"] = 32
126
127
128 def make_map():
129     from server.make_map import new_pos, is_neighbor
130     from server.utils import rand
131     world_db["MAP"] = bytearray(b'X' * (world_db["MAP_LENGTH"] ** 2))
132     length = world_db["MAP_LENGTH"]
133     add_half_width = (not (length % 2)) * int(length / 2)
134     world_db["MAP"][int((length ** 2) / 2) + add_half_width] = ord("#")
135     while (1):
136         y, x, pos = new_pos()
137         if "X" == chr(world_db["MAP"][pos]) and is_neighbor((y, x), "#"):
138             if y == 0 or y == (length - 1) or x == 0 or x == (length - 1):
139                 break
140             world_db["MAP"][pos] = ord("#")
141     n_ground = int((length ** 2) / 16)
142     i_ground = 0
143     while (i_ground <= n_ground):
144         single_allowed = rand.next() % 32
145         y, x, pos = new_pos()
146         if "#" == chr(world_db["MAP"][pos]) \
147                 and ((not single_allowed) or is_neighbor((y, x), "_")):
148             world_db["MAP"][pos] = ord("_")
149             i_ground += 1
150     n_water = int((length ** 2) / 64)
151     i_water = 0
152     while (i_water <= n_water):
153         single_allowed = rand.next() % 32
154         y, x, pos = new_pos()
155         if "_" == chr(world_db["MAP"][pos]) \
156                 and ((not single_allowed) or is_neighbor((y, x), "~")):
157             world_db["MAP"][pos] = ord("~")
158             i_water += 1
159
160
161 def calc_effort(ta, t):
162     from server.utils import mv_yx_in_dir_legal
163     if ta["TA_NAME"] == "move":
164         move_result = mv_yx_in_dir_legal(chr(t["T_ARGUMENT"]),
165                                          t["T_POSY"], t["T_POSX"])
166         if 1 == move_result[0]:
167             pos = (move_result[1] * world_db["MAP_LENGTH"]) + move_result[2]
168             terrain = chr(world_db["MAP"][pos])
169             if terrain == ".":
170                 return 2
171             elif terrain == ":":
172                 return 4
173     return 1
174 world_db["calc_effort"] = calc_effort
175
176
177 def turn_over():
178     from server.ai import ai
179     from server.config.actions import action_db
180     from server.update_map_memory import update_map_memory
181     from server.io import try_worldstate_update
182     from server.config.io import io_db
183     from server.utils import rand
184     while world_db["Things"][0]["T_LIFEPOINTS"]:
185         for tid in [tid for tid in world_db["Things"]]:
186             if not tid in world_db["Things"]:
187                 continue
188             Thing = world_db["Things"][tid]
189             if Thing["T_LIFEPOINTS"]:
190                 if not Thing["T_COMMAND"]:
191                     update_map_memory(Thing)
192                     if 0 == tid:
193                         return
194                     ai(Thing)
195                 if Thing["T_LIFEPOINTS"]:
196                     Thing["T_PROGRESS"] += 1
197                     taid = [a for a in world_db["ThingActions"]
198                               if a == Thing["T_COMMAND"]][0]
199                     ThingAction = world_db["ThingActions"][taid]
200                     effort = world_db["calc_effort"](ThingAction, Thing)
201                     if Thing["T_PROGRESS"] >= effort:
202                         action = action_db["actor_" + ThingAction["TA_NAME"]]
203                         action(Thing)
204                         Thing["T_COMMAND"] = 0
205                         Thing["T_PROGRESS"] = 0
206                     if Thing["T_STOMACH"] > 16:
207                         if 0 == (rand.next() % (33 - Thing["T_STOMACH"])):
208                             action_db["actor_drop"](Thing)
209         world_db["TURN"] += 1
210         io_db["worldstate_updateable"] = True
211         try_worldstate_update()
212 world_db["turn_over"] = turn_over
213
214
215 def command_ai():
216     """Call ai() on player Thing, then turn_over()."""
217     from server.ai import ai
218     if world_db["WORLD_ACTIVE"]:
219         ai(world_db["Things"][0])
220         world_db["turn_over"]()
221
222
223 def set_command(action):
224     """Set player's T_COMMAND, then call turn_over()."""
225     tid = [x for x in world_db["ThingActions"]
226            if world_db["ThingActions"][x]["TA_NAME"] == action][0]
227     world_db["Things"][0]["T_COMMAND"] = tid
228     world_db["turn_over"]()
229 world_db["set_command"] = set_command
230
231
232 def play_wait():
233     """Try "wait" as player's T_COMMAND."""
234     if world_db["WORLD_ACTIVE"]:
235         world_db["set_command"]("wait")
236
237
238 from server.config.io import io_db
239 io_db["worldstate_write_order"] += [["T_STOMACH", "player_int"]]
240 io_db["worldstate_write_order"] += [["T_BLADDER", "player_int"]]
241 import server.config.world_data
242 server.config.world_data.symbols_hide = "%#X"
243 server.config.world_data.symbols_passable = "_.:~"
244 server.config.world_data.thing_defaults["T_STOMACH"] = 0
245 server.config.world_data.thing_defaults["T_BLADDER"] = 0
246 import server.config.make_world_helpers
247 server.config.make_world_helpers.make_map = make_map
248 from server.config.commands import commands_db
249 commands_db["THINGS_HERE"] = (2, True, lambda x, y: None)
250 commands_db["ai"] = (0, False, command_ai)
251 commands_db["move"] = (1, False, play_move)
252 commands_db["wait"] = (0, False, play_wait)
253 commands_db["drop"] = (0, False, play_drop)
254 commands_db["drink"] = (0, False, play_drink)
255 commands_db["use"] = (1, False, lambda x: None)
256 commands_db["pickup"] = (0, False, lambda: None)
257 commands_db["T_STOMACH"] = (1, False, setter("Thing", "T_STOMACH", 0, 255))
258 commands_db["T_BLADDER"] = (1, False, setter("Thing", "T_BLADDER", 0, 255))
259 from server.actions import actor_wait
260 import server.config.actions
261 server.config.actions.action_db = {
262     "actor_wait": actor_wait,
263     "actor_move": actor_move,
264     "actor_drop": actor_drop,
265     "actor_drink": actor_drink,
266 }
267
268 strong_write(io_db["file_out"], "PLUGIN TheCrawlingEater\n")