"switch_to_admin_thing_protect": "T",
"flatten": "F",
"switch_to_enter_face": "f",
+ "switch_to_enter_hat": "H",
"switch_to_take_thing": "z",
"switch_to_drop_thing": "u",
"teleport": "p",
game.record_fov_change(t.position)
cmd_PLAYER_FACE.argtypes = 'string'
+def cmd_PLAYER_HAT(game, hat, connection_id):
+ t = game.get_player(connection_id)
+ if not t:
+ raise GameError('can only edit hat when already logged in')
+ if not t.name in game.hats:
+ raise GameError('not currently wearing an editable hat')
+ if len(hat) != 18:
+ raise GameError('wrong hat string length')
+ legal_chars = t.get_cookie_chars()
+ for c in hat:
+ if c not in legal_chars:
+ raise GameError('used illegal character: "%s" – '
+ 'allowed characters: %s'
+ % (c, legal_chars))
+ game.hats[t.name] = hat
+ game.changed = True
+ # FIXME: pseudo-FOV-change actually
+ game.record_fov_change(t.position)
+cmd_PLAYER_HAT.argtypes = 'string'
+
def cmd_GOD_PLAYER_FACE(game, name, face):
if len(face) != 18:
raise GameError('wrong face string length')
game.hats[name] = hat
cmd_GOD_PLAYER_HAT.argtypes = 'string string'
+def cmd_GOD_PLAYERS_HAT_CHARS(game, name, hat_chars):
+ game.players_hat_chars[name] = hat_chars
+cmd_GOD_PLAYERS_HAT_CHARS.argtypes = 'string string'
+
def cmd_THING_HAT_DESIGN(game, thing_id, design):
if len(design) != 18:
raise GameError('hat design of wrong length')
self.spawn_point = YX(0, 0), YX(0, 0)
self.portals = {}
self.player_chars = string.digits + string.ascii_letters
+ self.players_hat_chars = {}
self.player_char_i = -1
self.admin_passwords = []
self.send_gamestate_interval = datetime.timedelta(seconds=0.04)
# collected here as a shortcut, but a cleaner way would be to
# differentiate the changes somehow.
self.io.send('PSEUDO_FOV_WIPE', c_id)
+ self.io.send('PLAYERS_HAT_CHARS ' + quote(player.get_cookie_chars()),
+ c_id)
for t in player.seen_things:
target_yx = player.fov_stencil.target_yx(*t.position)
self.io.send('THING %s %s %s %s %s %s'
for name in self.hats:
write(f, 'GOD_PLAYER_HAT %s %s' % (quote(name),
quote(self.hats[name])))
+ for name in self.players_hat_chars:
+ write(f, 'GOD_PLAYERS_HAT_CHARS %s %s' %
+ (quote(name), quote(self.players_hat_chars[name])))
for t in [t for t in self.things if not t.type_ == 'Player']:
write(f, 'THING %s %s %s %s' % (t.position[0],
t.position[1], t.type_, t.id_))
target_position = self._get_move_target()
dropped = self.thing.uncarry()
dropped.position = target_position
- if dropped.type_ == 'Bottle' and not dropped.full:
+ over_cookie_spawner = None
+ for t in [t for t in self.thing.game.things
+ if t.type_ == 'CookieSpawner'
+ and t.position == dropped.position]:
+ over_cookie_spawner = t
+ break
+ if over_cookie_spawner:
+ over_cookie_spawner.accept(dropped)
+ self.thing.game.remove_thing(dropped)
+ elif dropped.type_ == 'Bottle' and not dropped.full:
for t in [t for t in self.thing.game.things
if t.type_ == 'BottleDeposit'
and t.position == dropped.position]:
def check(self):
if self.thing.carrying is None:
raise PlayError('carrying nothing to drink from')
- if self.thing.carrying.type_ != 'Bottle':
- raise PlayError('cannot drink from non-bottle')
- if not self.thing.carrying.full:
+ if self.thing.carrying.type_ not in {'Bottle', 'Cookie'}:
+ raise PlayError('cannot consume this kind of thing')
+ if self.thing.carrying.type_ == 'Bottle' and\
+ not self.thing.carrying.full:
raise PlayError('bottle is empty')
def do(self):
- self.thing.carrying.full = False
- self.thing.carrying.empty()
- self.thing.send_msg('RANDOM_COLORS')
- self.thing.send_msg('CHAT "You are drunk now."')
- self.thing.drunk = 10000
- # FIXME: pseudo-FOV-change actually
- self.thing.game.record_fov_change(self.thing.position)
+ if self.thing.carrying.type_ == 'Bottle':
+ self.thing.carrying.full = False
+ self.thing.carrying.empty()
+ self.thing.send_msg('RANDOM_COLORS')
+ self.thing.send_msg('CHAT "You are drunk now."')
+ self.thing.drunk = 10000
+ # FIXME: pseudo-FOV-change actually
+ self.thing.game.record_fov_change(self.thing.position)
+ elif self.thing.carrying.type_ == 'Cookie':
+ self.thing.send_msg('CHAT ' + quote('You eat a cookie and gain the ability to draw the following character: "%s"' % self.thing.carrying.thing_char))
+ self.thing.add_cookie_char(self.thing.carrying.thing_char)
+ eaten = self.thing.uncarry()
+ self.thing.game.remove_thing(eaten)
self.thing.game.hats[self.thing.name] =\
self.thing.carrying.design
self.thing.send_msg('CHAT "You put on a hat."')
- self.thing.game.remove_thing(self.thing.carrying)
- self.thing.carrying = None
+ dropped = self.uncarry()
+ self.thing.game.remove_thing(dropped)
# FIXME: pseudo-FOV-change actually
self.thing.game.record_fov_change(self.thing.position)
self.sound('HAT REMIXER', 'remixing a hat …')
self.game.changed = True
# FIXME: pseudo-FOV-change actually
- self.game.record_fov_change(self.thing.position)
+ self.game.record_fov_change(self.position)
+class Thing_Cookie(Thing):
+ symbol_hint = 'c'
+ portable = True
+
+ def __init__(self, *args, **kwargs):
+ import string
+ super().__init__(*args, **kwargs)
+ legal_chars = string.ascii_letters + string.digits + string.punctuation + ' '
+ self.thing_char = random.choice(list(legal_chars))
+
+
+
+class Thing_CookieSpawner(Thing):
+ symbol_hint = 'O'
+
+ def accept(self, thing):
+ self.sound('OVEN', '*heat* *brrzt* here\'s a cookie!')
+ self.game.add_thing('Cookie', self.position)
+
+
class ThingAnimate(Thing):
blocking = True
self.game.io.send('CHAT "You sober up."', c_id)
#self.invalidate_map_view()
# FIXME: pseudo-FOV-change actually
- self.game.record_fov_change(self.thing.position)
+ self.game.record_fov_change(self.position)
break
self.game.changed = True
if self.task is None:
t.carried = False
self.carrying = None
return t
+
+ def add_cookie_char(self, c):
+ if not self.name in self.game.players_hat_chars:
+ self.game.players_hat_chars[self.name] = ' #' # default
+ if not c in self.game.players_hat_chars[self.name]:
+ self.game.players_hat_chars[self.name] += c
+
+ def get_cookie_chars(self):
+ if self.name in self.game.players_hat_chars:
+ return self.game.players_hat_chars[self.name]
+ return ' #' # default
<button id="switch_to_name_thing"></button>
<button id="switch_to_password"></button>
<button id="switch_to_enter_face"></button>
+ <button id="switch_to_enter_hat"></button>
</td>
</tr>
<tr>
<li>(un-)wear: <input id="key_wear" type="text" value="W" />
<li><input id="key_switch_to_drop_thing" type="text" value="u" />
<li><input id="key_switch_to_enter_face" type="text" value="f" />
+<li><input id="key_switch_to_enter_hat" type="text" value="H" />
<li><input id="key_switch_to_take_thing" type="text" value="z" />
<li><input id="key_switch_to_chat" type="text" value="t" />
<li><input id="key_switch_to_play" type="text" value="p" />
'intro': '@ enter face line (enter nothing to abort):',
'long': 'Draw your face as ASCII art. The string you enter must be 18 characters long, and will be divided on display into 3 lines of 6 characters each, from top to bottom..'
},
+ 'enter_hat': {
+ 'short': 'enter your hat',
+ 'intro': '@ enter hat line (enter nothing to abort):',
+ 'long': 'Draw your hat as ASCII art. The string you enter must be 18 characters long, and will be divided on display into 3 lines of 6 characters each, from top to bottom..'
+ },
'write': {
'short': 'change terrain',
'intro': '',
explorer.info_cached = false;
game.things = game.things_new;
game.player = game.things[game.player_id];
+ game.players_hat_chars = game.players_hat_chars_new;
game.turn_complete = true;
if (tui.mode.name == 'post_login_wait') {
tui.switch_mode('play');
tui.log_msg('#MUSICPLAYER: ' + tokens[1], 1);
} else if (tokens[0] === 'PLAYER_ID') {
game.player_id = parseInt(tokens[1]);
+ } else if (tokens[0] === 'PLAYERS_HAT_CHARS') {
+ game.players_hat_chars_new = tokens[1];
} else if (tokens[0] === 'LOGIN_OK') {
this.send(['GET_GAMESTATE']);
tui.switch_mode('post_login_wait');
mode_take_thing: new Mode('take_thing', true),
mode_drop_thing: new Mode('drop_thing', true),
mode_enter_face: new Mode('enter_face', true),
+ mode_enter_hat: new Mode('enter_hat', true),
mode_admin_enter: new Mode('admin_enter', true),
mode_admin: new Mode('admin'),
mode_control_pw_pw: new Mode('control_pw_pw', true),
this.mode_control_tile_draw.available_actions = ["toggle_tile_draw"];
this.mode_edit.available_modes = ["write", "annotate", "portal", "name_thing",
"password", "chat", "study", "play",
- "admin_enter", "enter_face"]
+ "admin_enter", "enter_face", "enter_hat"]
this.mode_edit.available_actions = ["move", "flatten", "install",
"toggle_map_mode"]
this.inputEl = document.getElementById("input");
this.map_size_new = [0,0];
this.portals = {};
this.portals_new = {};
+ this.players_hat_chars = "";
},
get_thing_temp: function(id_, create_if_not_found=false) {
if (id_ in game.things_new) {
}
tui.inputEl.value = "";
tui.switch_mode('edit');
+ } else if (tui.mode.name == 'enter_hat' && event.key == 'Enter') {
+ if (tui.inputEl.value.length != 18) {
+ tui.log_msg('? wrong input length, aborting');
+ } else {
+ server.send(['PLAYER_HAT', tui.inputEl.value]);
+ }
+ tui.inputEl.value = "";
+ tui.switch_mode('edit');
} else if (tui.mode.name == 'command_thing' && event.key == 'Enter') {
server.send(['TASK:COMMAND', tui.inputEl.value]);
tui.inputEl.value = "";
cmd_THING_MUSICPLAYER_SETTINGS, cmd_THING_HAT_DESIGN,
cmd_THING_MUSICPLAYER_PLAYLIST_ITEM, cmd_TERRAIN,
cmd_THING_BOTTLE_EMPTY, cmd_PLAYER_FACE,
- cmd_GOD_PLAYER_FACE, cmd_GOD_PLAYER_HAT)
+ cmd_GOD_PLAYER_FACE, cmd_GOD_PLAYER_HAT,
+ cmd_GOD_PLAYERS_HAT_CHARS, cmd_PLAYER_HAT)
from plomrogue.tasks import (Task_WAIT, Task_MOVE, Task_WRITE, Task_PICK_UP,
Task_DROP, Task_FLATTEN_SURROUNDINGS, Task_DOOR,
Task_INTOXICATE, Task_COMMAND, Task_INSTALL,
Thing_SpawnPoint, Thing_SpawnPointSpawner,
Thing_Door, Thing_DoorSpawner, Thing_Bottle,
Thing_BottleSpawner, Thing_BottleDeposit,
- Thing_MusicPlayer, Thing_Hat, Thing_HatRemixer)
+ Thing_MusicPlayer, Thing_Hat, Thing_HatRemixer,
+ Thing_Cookie, Thing_CookieSpawner)
from plomrogue.config import config
game = Game(config['savefile'])
game.register_command(cmd_PLAYER_FACE)
game.register_command(cmd_GOD_PLAYER_FACE)
game.register_command(cmd_GOD_PLAYER_HAT)
+game.register_command(cmd_GOD_PLAYERS_HAT_CHARS)
+game.register_command(cmd_PLAYER_HAT)
game.register_command(cmd_THING_HAT_DESIGN)
game.register_task(Task_WAIT)
game.register_task(Task_MOVE)
game.register_thing_type(Thing_MusicPlayer)
game.register_thing_type(Thing_Hat)
game.register_thing_type(Thing_HatRemixer)
+game.register_thing_type(Thing_Cookie)
+game.register_thing_type(Thing_CookieSpawner)
game.read_savefile()
game.io.start_loop()
for port in config['servers']:
'intro': '@ enter face line (enter nothing to abort):',
'long': 'Draw your face as ASCII art. The string you enter must be 18 characters long, and will be divided on display into 3 lines of 6 characters each, from top to bottom..'
},
+ 'enter_hat': {
+ 'short': 'enter your hat',
+ 'intro': '@ enter hat line (enter nothing to abort):',
+ 'long': 'Draw your hat as ASCII art. The string you enter must be 18 characters long, and will be divided on display into 3 lines of 6 characters each, from top to bottom..'
+ },
'write': {
'short': 'change terrain',
'intro': '',
game.player_id = player_id
cmd_PLAYER_ID.argtypes = 'int:nonneg'
+def cmd_PLAYERS_HAT_CHARS(game, hat_chars):
+ game.players_hat_chars_new = hat_chars
+cmd_PLAYERS_HAT_CHARS.argtypes = 'string'
+
def cmd_THING(game, yx, thing_type, protection, thing_id, portable, commandable):
t = game.get_thing_temp(thing_id)
if not t:
game.map_content = game.map_content_new
game.map_control_content = game.map_control_content_new
game.player = game.get_thing(game.player_id)
+ game.players_hat_chars = game.players_hat_chars_new
game.turn_complete = True
if game.tui.mode.name == 'post_login_wait':
game.tui.switch_mode('play')
self.register_command(cmd_PORTAL)
self.register_command(cmd_ANNOTATION)
self.register_command(cmd_GAME_STATE_COMPLETE)
+ self.register_command(cmd_PLAYERS_HAT_CHARS)
self.register_command(cmd_ARGUMENT_ERROR)
self.register_command(cmd_GAME_ERROR)
self.register_command(cmd_PLAY_ERROR)
self.register_command(cmd_DEFAULT_COLORS)
self.register_command(cmd_RANDOM_COLORS)
self.map_content = ''
+ self.players_hat_chars = ''
self.player_id = -1
self.annotations = {}
self.annotations_new = {}
mode_take_thing = Mode('take_thing', has_input_prompt=True)
mode_drop_thing = Mode('drop_thing', has_input_prompt=True)
mode_enter_face = Mode('enter_face', has_input_prompt=True)
+ mode_enter_hat = Mode('enter_hat', has_input_prompt=True)
is_admin = False
tile_draw = False
self.mode_control_tile_draw.available_actions = ["move_explorer",
"toggle_tile_draw"]
self.mode_edit.available_modes = ["write", "annotate", "portal",
- "name_thing", "enter_face", "password",
+ "name_thing", "enter_face", "enter_hat", "password",
"chat", "study", "play", "admin_enter"]
self.mode_edit.available_actions = ["move", "flatten", "install",
"toggle_map_mode"]
'switch_to_admin_thing_protect': 'T',
'flatten': 'F',
'switch_to_enter_face': 'f',
+ 'switch_to_enter_hat': 'H',
'switch_to_take_thing': 'z',
'switch_to_drop_thing': 'u',
'teleport': 'p',
['HERE'] + list(self.game.tui.movement_keys.values())
for i in range(len(self.selectables)):
self.log_msg(str(i) + ': ' + self.selectables[i])
+ elif self.mode.name == 'enter_hat':
+ self.log_msg('legal characters: ' + self.game.players_hat_chars)
elif self.mode.name == 'command_thing':
self.send('TASK:COMMAND ' + quote('HELP'))
elif self.mode.name == 'control_pw_pw':
self.send('PLAYER_FACE %s' % quote(self.input_))
self.input_ = ""
self.switch_mode('edit')
+ elif self.mode.name == 'enter_hat' and key == '\n':
+ if len(self.input_) != 18:
+ self.log_msg('? wrong input length, aborting')
+ else:
+ self.send('PLAYER_HAT %s' % quote(self.input_))
+ self.input_ = ""
+ self.switch_mode('edit')
elif self.mode.name == 'take_thing' and key == '\n':
pick_selectable('PICK_UP')
elif self.mode.name == 'drop_thing' and key == '\n':