PEP8 cleanup of the entire codebase. Unchanged are many cases of too-long lines, partly because of the rewrite they would require but also because splitting many lines up would make the code harder to read. Also the third-party libraries (idmapper, prettytable etc) were not cleaned.

This commit is contained in:
Griatch 2013-11-14 19:31:17 +01:00
parent 30b7d2a405
commit 1ae17bcbe4
154 changed files with 5613 additions and 4054 deletions

View file

@ -0,0 +1 @@
# -*- coding: utf-8 -*-

View file

@ -14,6 +14,7 @@ from contrib.tutorial_world import scripts as tut_scripts
BASE_CHARACTER_TYPECLASS = settings.BASE_CHARACTER_TYPECLASS
#------------------------------------------------------------
#
# Mob - mobile object
@ -52,15 +53,18 @@ class Mob(tut_objects.TutorialObject):
def update_irregular(self):
"Called at irregular intervals. Moves the mob."
if self.roam_mode:
exits = [ex for ex in self.location.exits if ex.access(self, "traverse")]
exits = [ex for ex in self.location.exits
if ex.access(self, "traverse")]
if exits:
# Try to make it so the mob doesn't backtrack.
new_exits = [ex for ex in exits if ex.destination != self.db.last_location]
new_exits = [ex for ex in exits
if ex.destination != self.db.last_location]
if new_exits:
exits = new_exits
self.db.last_location = self.location
# execute_cmd() allows the mob to respect exit and exit-command locks,
# but may pose a problem if there is more than one exit with the same name.
# execute_cmd() allows the mob to respect exit and
# exit-command locks, but may pose a problem if there is more
# than one exit with the same name.
# - see Enemy example for another way to move
self.execute_cmd("%s" % exits[random.randint(0, len(exits) - 1)].key)
@ -100,7 +104,8 @@ class AttackTimer(Script):
"Called every self.interval seconds."
if self.obj.db.inactive:
return
#print "attack timer: at_repeat", self.dbobj.id, self.ndb.twisted_task, id(self.ndb.twisted_task)
#print "attack timer: at_repeat", self.dbobj.id, self.ndb.twisted_task,
# id(self.ndb.twisted_task)
if self.obj.db.roam_mode:
self.obj.roam()
#return
@ -119,10 +124,12 @@ class AttackTimer(Script):
if (time.time() - self.obj.db.dead_at) > self.obj.db.dead_timer:
self.obj.reset()
class Enemy(Mob):
"""
This is a ghostly enemy with health (hit points). Their chance to hit, damage etc is
determined by the weapon they are wielding, same as characters.
This is a ghostly enemy with health (hit points). Their chance to hit,
damage etc is determined by the weapon they are wielding, same as
characters.
An enemy can be in four modes:
roam (inherited from Mob) - where it just moves around randomly
@ -133,12 +140,16 @@ class Enemy(Mob):
Upon creation, the following attributes describe the enemy's actions
desc - description
full_health - integer number > 0
defeat_location - unique name or #dbref to the location the player is taken when defeated. If not given, will remain in room.
defeat_text - text to show player when they are defeated (just before being whisped away to defeat_location)
defeat_text_room - text to show other players in room when a player is defeated
defeat_location - unique name or #dbref to the location the player is
taken when defeated. If not given, will remain in room.
defeat_text - text to show player when they are defeated (just before
being whisped away to defeat_location)
defeat_text_room - text to show other players in room when a player
is defeated
win_text - text to show player when defeating the enemy
win_text_room - text to show room when a player defeates the enemy
respawn_text - text to echo to room when the mob is reset/respawn in that room.
respawn_text - text to echo to room when the mob is reset/respawn in
that room.
"""
def at_object_creation(self):
@ -157,7 +168,8 @@ class Enemy(Mob):
self.db.health = 20
self.db.dead_at = time.time()
self.db.dead_timer = 100 # how long to stay dead
self.db.inactive = True # this is used during creation to make sure the mob doesn't move away
# this is used during creation to make sure the mob doesn't move away
self.db.inactive = True
# store the last player to hit
self.db.last_attacker = None
# where to take defeated enemies
@ -185,10 +197,12 @@ class Enemy(Mob):
elif random.random() < 0.2:
# no players to attack, move about randomly.
exits = [ex.destination for ex in self.location.exits if ex.access(self, "traverse")]
exits = [ex.destination for ex in self.location.exits
if ex.access(self, "traverse")]
if exits:
# Try to make it so the mob doesn't backtrack.
new_exits = [ex for ex in exits if ex.destination != self.db.last_location]
new_exits = [ex for ex in exits
if ex.destination != self.db.last_location]
if new_exits:
exits = new_exits
self.db.last_location = self.location
@ -224,7 +238,8 @@ class Enemy(Mob):
# analyze result.
if target.db.health <= 0:
# we reduced enemy to 0 health. Whisp them off to the prison room.
# we reduced enemy to 0 health. Whisp them off to
# the prison room.
tloc = search_object(self.db.defeat_location)
tstring = self.db.defeat_text
if not tstring:
@ -235,7 +250,8 @@ class Enemy(Mob):
if tloc:
if not ostring:
ostring = "\n%s envelops the fallen ... and then their body is suddenly gone!" % self.key
# silently move the player to defeat location (we need to call hook manually)
# silently move the player to defeat location
# (we need to call hook manually)
target.location = tloc[0]
tloc[0].at_object_receive(target, self.location)
elif not ostring:
@ -246,7 +262,8 @@ class Enemy(Mob):
self.roam_mode = False
self.pursue_mode = True
else:
# no players found, this could mean they have fled. Switch to pursue mode.
# no players found, this could mean they have fled.
# Switch to pursue mode.
self.battle_mode = False
self.roam_mode = False
self.pursue_mode = True
@ -259,20 +276,24 @@ class Enemy(Mob):
last_attacker = self.db.last_attacker
players = [obj for obj in self.location.contents if utils.inherits_from(obj, BASE_CHARACTER_TYPECLASS) and not obj.is_superuser]
if players:
# we found players in the room. Maybe we caught up with some, or some walked in on us
# before we had time to pursue them. Switch to battle mode.
# we found players in the room. Maybe we caught up with some,
# or some walked in on us before we had time to pursue them.
# Switch to battle mode.
self.battle_mode = True
self.roam_mode = False
self.pursue_mode = False
else:
# find all possible destinations.
destinations = [ex.destination for ex in self.location.exits if ex.access(self, "traverse")]
# find all players in the possible destinations. OBS-we cannot just use the player's
# current position to move the Enemy; this might have changed when the move is performed,
# causing the enemy to teleport out of bounds.
destinations = [ex.destination for ex in self.location.exits
if ex.access(self, "traverse")]
# find all players in the possible destinations. OBS-we cannot
# just use the player's current position to move the Enemy; this
# might have changed when the move is performed, causing the enemy
# to teleport out of bounds.
players = {}
for dest in destinations:
for obj in [o for o in dest.contents if utils.inherits_from(o, BASE_CHARACTER_TYPECLASS)]:
for obj in [o for o in dest.contents
if utils.inherits_from(o, BASE_CHARACTER_TYPECLASS)]:
players[obj] = dest
if players:
# we found targets. Move to intercept.
@ -335,7 +356,8 @@ class Enemy(Mob):
string += "You fear it's only a matter of time before it materializes somewhere again."
self.location.msg_contents(string, exclude=[attacker])
# put enemy in dead mode and hide it from view. AttackTimer will bring it back later.
# put mob in dead mode and hide it from view.
# AttackTimer will bring it back later.
self.db.dead_at = time.time()
self.db.roam_mode = False
self.db.pursue_mode = False
@ -347,7 +369,9 @@ class Enemy(Mob):
return False
def reset(self):
"If the mob was 'dead', respawn it to its home position and reset all modes and damage."
"""
If the mob was 'dead', respawn it to its home position and reset
all modes and damage."""
if self.db.dead_mode:
self.db.health = self.db.full_health
self.db.roam_mode = True
@ -358,4 +382,4 @@ class Enemy(Mob):
string = self.db.respawn_text
if not string:
string = "%s fades into existence from out of thin air. It's looking pissed." % self.key
self.location.msg_contents(string)
self.location.msg_contents(string)

View file

@ -19,9 +19,10 @@ WeaponRack
"""
import time, random
import time
import random
from ev import utils, create_object
from ev import create_object
from ev import Object, Exit, Command, CmdSet, Script
#------------------------------------------------------------
@ -91,12 +92,14 @@ class CmdRead(Command):
string = "There is nothing to read on %s." % obj.key
self.caller.msg(string)
class CmdSetReadable(CmdSet):
"CmdSet for readables"
def at_cmdset_creation(self):
"called when object is created."
self.add(CmdRead())
class Readable(TutorialObject):
"""
This object defines some attributes and defines a read method on itself.
@ -147,6 +150,7 @@ class CmdClimb(Command):
self.caller.msg(ostring)
self.caller.db.last_climbed = self.obj
class CmdSetClimbable(CmdSet):
"Climbing cmdset"
def at_cmdset_creation(self):
@ -182,6 +186,7 @@ OBELISK_DESCS = ["You can briefly make out the image of {ba woman with a blue bi
"You think you can see the outline of {ba flaming shield{n in the stone.",
"The surface for a moment seems to portray {ba woman fighting a beast{n."]
class Obelisk(TutorialObject):
"""
This object changes its description randomly.
@ -196,7 +201,7 @@ class Obelisk(TutorialObject):
def return_appearance(self, caller):
"Overload the default version of this hook."
clueindex = random.randint(0, len(OBELISK_DESCS)-1)
clueindex = random.randint(0, len(OBELISK_DESCS) - 1)
# set this description
string = "The surface of the obelisk seem to waver, shift and writhe under your gaze, with "
string += "different scenes and structures appearing whenever you look at it. "
@ -206,6 +211,7 @@ class Obelisk(TutorialObject):
# call the parent function as normal (this will use db.desc we just set)
return super(Obelisk, self).return_appearance(caller)
#------------------------------------------------------------
#
# LightSource
@ -237,6 +243,7 @@ class StateLightSourceOn(Script):
self.db.script_started = time.time()
def at_repeat(self):
"Called at self.interval seconds"
# this is only called when torch has burnt out
self.obj.db.burntime = -1
self.obj.reset()
@ -262,13 +269,14 @@ class StateLightSourceOn(Script):
"This script is only valid as long as the lightsource burns."
return self.obj.db.is_active
class CmdLightSourceOn(Command):
"""
Switches on the lightsource.
"""
key = "on"
aliases = ["switch on", "turn on", "light"]
locks = "cmd:holds()" # only allow if command.obj is carried by caller.
locks = "cmd:holds()" # only allow if command.obj is carried by caller.
help_category = "TutorialWorld"
def func(self):
@ -283,18 +291,19 @@ class CmdLightSourceOn(Command):
self.obj.scripts.add(StateLightSourceOn)
self.caller.msg("{gYou light {C%s.{n" % self.obj.key)
self.caller.location.msg_contents("%s lights %s!" % (self.caller, self.obj.key), exclude=[self.caller])
# we run script validation on the room to make light/dark states tick.
# run script validation on the room to make light/dark states tick.
self.caller.location.scripts.validate()
# look around
self.caller.execute_cmd("look")
class CmdLightSourceOff(Command):
"""
Switch off the lightsource.
"""
key = "off"
aliases = ["switch off", "turn off", "dowse"]
locks = "cmd:holds()" # only allow if command.obj is carried by caller.
locks = "cmd:holds()" # only allow if command.obj is carried by caller.
help_category = "TutorialWorld"
def func(self):
@ -311,38 +320,39 @@ class CmdLightSourceOff(Command):
self.caller.location.msg_contents("%s dowses %s." % (self.caller, self.obj.key), exclude=[self.caller])
self.caller.location.scripts.validate()
self.caller.execute_cmd("look")
# we run script validation on the room to make light/dark states tick.
class CmdSetLightSource(CmdSet):
"CmdSet for the lightsource commands"
key = "lightsource_cmdset"
def at_cmdset_creation(self):
"called at cmdset creation"
self.add(CmdLightSourceOn())
self.add(CmdLightSourceOff())
class LightSource(TutorialObject):
"""
This implements a light source object.
When burned out, lightsource will be moved to its home - which by default is the
location it was first created at.
When burned out, lightsource will be moved to its home - which by
default is the location it was first created at.
"""
def at_object_creation(self):
"Called when object is first created."
super(LightSource, self).at_object_creation()
self.db.tutorial_info = "This object can be turned on off and has a timed script controlling it."
self.db.is_active = False
self.db.burntime = 60*3 # 3 minutes
self.db.burntime = 60 * 3 # 3 minutes
self.db.desc = "A splinter of wood with remnants of resin on it, enough for burning."
# add commands
self.cmdset.add_default(CmdSetLightSource, permanent=True)
def reset(self):
"""
Can be called by tutorial world runner, or by the script when the lightsource
has burned out.
Can be called by tutorial world runner, or by the script when
the lightsource has burned out.
"""
if self.db.burntime <= 0:
# light burned out. Since the lightsources's "location" should be
@ -360,10 +370,11 @@ class LightSource(TutorialObject):
# maybe it was dropped, try validating at current location.
try:
self.location.scripts.validate()
except AttributeError,e:
except AttributeError:
pass
self.delete()
#------------------------------------------------------------
#
# Crumbling wall - unique exit
@ -473,7 +484,7 @@ class CmdShiftRoot(Command):
root_pos["green"] += 1
self.caller.msg("The green weedy root falls down.")
elif direction == "down":
root_pos[color] = min(1, root_pos[color] +1)
root_pos[color] = min(1, root_pos[color] + 1)
self.caller.msg("You shove the root adorned with small yellow flowers downwards.")
if root_pos[color] != 0 and root_pos[color] == root_pos["green"]:
root_pos["green"] -= 1
@ -502,13 +513,15 @@ class CmdShiftRoot(Command):
self.caller.db.crumbling_wall_found_button = True
self.caller.msg("Holding aside the root you think you notice something behind it ...")
class CmdPressButton(Command):
"""
Presses a button.
"""
key = "press"
aliases = ["press button", "button", "push", "push button"]
locks = "cmd:attr(crumbling_wall_found_button) and not locattr(is_dark)" # only accessible if the button was found and there is light.
# only accessible if the button was found and there is light.
locks = "cmd:attr(crumbling_wall_found_button) and not locattr(is_dark)"
help_category = "TutorialWorld"
def func(self):
@ -534,14 +547,17 @@ class CmdPressButton(Command):
self.obj.destination = eloc
self.caller.msg(string)
class CmdSetCrumblingWall(CmdSet):
"Group the commands for crumblingWall"
key = "crumblingwall_cmdset"
def at_cmdset_creation(self):
"called when object is first created."
self.add(CmdShiftRoot())
self.add(CmdPressButton())
class CrumblingWall(TutorialObject, Exit):
"""
The CrumblingWall can be examined in various
@ -559,24 +575,28 @@ class CrumblingWall(TutorialObject, Exit):
"called when the object is first created."
super(CrumblingWall, self).at_object_creation()
self.aliases.add(["secret passage", "passage", "crack", "opening", "secret door"])
# this is assigned first when pushing button, so assign this at creation time!
self.aliases.add(["secret passage", "passage",
"crack", "opening", "secret door"])
# this is assigned first when pushing button, so assign
# this at creation time!
self.db.destination = 2
# locks on the object directly transfer to the exit "command"
self.locks.add("cmd:not locattr(is_dark)")
self.db.tutorial_info = "This is an Exit with a conditional traverse-lock. Try to shift the roots around."
# the lock is important for this exit; we only allow passage if we "found exit".
# the lock is important for this exit; we only allow passage
# if we "found exit".
self.locks.add("traverse:attr(crumbling_wall_found_exit)")
# set cmdset
self.cmdset.add(CmdSetCrumblingWall, permanent=True)
# starting root positions. H1/H2 are the horizontally hanging roots, V1/V2 the
# vertically hanging ones. Each can have three positions: (-1, 0, 1) where
# 0 means the middle position. yellow/green are horizontal roots and red/blue vertical.
# all may have value 0, but never any other identical value.
self.db.root_pos = {"yellow":0, "green":0, "red":0, "blue":0}
# starting root positions. H1/H2 are the horizontally hanging roots,
# V1/V2 the vertically hanging ones. Each can have three positions:
# (-1, 0, 1) where 0 means the middle position. yellow/green are
# horizontal roots and red/blue vertical, all may have value 0, but n
# ever any other identical value.
self.db.root_pos = {"yellow": 0, "green": 0, "red": 0, "blue": 0}
def _translate_position(self, root, ipos):
"Translates the position into words"
@ -598,7 +618,10 @@ class CrumblingWall(TutorialObject, Exit):
return string
def return_appearance(self, caller):
"This is called when someone looks at the wall. We need to echo the current root positions."
"""
This is called when someone looks at the wall. We need to echo the
current root positions.
"""
if caller.db.crumbling_wall_found_button:
string = "Having moved all the roots aside, you find that the center of the wall, "
string += "previously hidden by the vegetation, hid a curious square depression. It was maybe once "
@ -615,7 +638,10 @@ class CrumblingWall(TutorialObject, Exit):
return super(CrumblingWall, self).return_appearance(caller)
def at_after_traverse(self, traverser, source_location):
"This is called after we traversed this exit. Cleans up and resets the puzzle."
"""
This is called after we traversed this exit. Cleans up and resets
the puzzle.
"""
del traverser.db.crumbling_wall_found_button
del traverser.db.crumbling_wall_found_exit
self.reset()
@ -625,11 +651,14 @@ class CrumblingWall(TutorialObject, Exit):
traverser.msg("No matter how you try, you cannot force yourself through %s." % self.key)
def reset(self):
"Called by tutorial world runner, or whenever someone successfully traversed the Exit."
"""
Called by tutorial world runner, or whenever someone successfully
traversed the Exit.
"""
self.location.msg_contents("The secret door closes abruptly, roots falling back into place.")
for obj in self.location.contents:
# clear eventual puzzle-solved attribues on everyone that didn't get out in time. They
# have to try again.
# clear eventual puzzle-solved attribues on everyone that didn't
# get out in time. They have to try again.
del obj.db.crumbling_wall_found_exit
# Reset the roots with some random starting positions for the roots:
@ -641,6 +670,7 @@ class CrumblingWall(TutorialObject, Exit):
self.db.root_pos = start_pos[random.randint(0, 4)]
self.destination = None
#------------------------------------------------------------
#
# Weapon - object type
@ -667,15 +697,17 @@ class CmdAttack(Command):
stab - (thrust) makes a lot of damage but is harder to hit with.
slash - is easier to land, but does not make as much damage.
parry - forgoes your attack but will make you harder to hit on next enemy attack.
parry - forgoes your attack but will make you harder to hit on next
enemy attack.
"""
# this is an example of implementing many commands as a single command class,
# using the given command alias to separate between them.
# this is an example of implementing many commands as a single
# command class, using the given command alias to separate between them.
key = "attack"
aliases = ["hit","kill", "fight", "thrust", "pierce", "stab", "slash", "chop", "parry", "defend"]
aliases = ["hit","kill", "fight", "thrust", "pierce", "stab",
"slash", "chop", "parry", "defend"]
locks = "cmd:all()"
help_category = "TutorialWorld"
@ -684,7 +716,6 @@ class CmdAttack(Command):
cmdstring = self.cmdstring
if cmdstring in ("attack", "fight"):
string = "How do you want to fight? Choose one of 'stab', 'slash' or 'defend'."
self.caller.msg(string)
@ -709,15 +740,15 @@ class CmdAttack(Command):
tstring = ""
ostring = ""
if cmdstring in ("thrust", "pierce", "stab"):
hit = float(self.obj.db.hit) * 0.7 # modified due to stab
damage = self.obj.db.damage * 2 # modified due to stab
hit = float(self.obj.db.hit) * 0.7 # modified due to stab
damage = self.obj.db.damage * 2 # modified due to stab
string = "You stab with %s. " % self.obj.key
tstring = "%s stabs at you with %s. " % (self.caller.key, self.obj.key)
ostring = "%s stabs at %s with %s. " % (self.caller.key, target.key, self.obj.key)
self.caller.db.combat_parry_mode = False
elif cmdstring in ("slash", "chop"):
hit = float(self.obj.db.hit) # un modified due to slash
damage = self.obj.db.damage # un modified due to slash
hit = float(self.obj.db.hit) # un modified due to slash
damage = self.obj.db.damage # un modified due to slash
string = "You slash with %s. " % self.obj.key
tstring = "%s slash at you with %s. " % (self.caller.key, self.obj.key)
ostring = "%s slash at %s with %s. " % (self.caller.key, target.key, self.obj.key)
@ -753,12 +784,14 @@ class CmdAttack(Command):
target.msg(tstring + "{gThey miss you.{n")
self.caller.location.msg_contents(ostring + "They miss.", exclude=[target, self.caller])
class CmdSetWeapon(CmdSet):
"Holds the attack command."
def at_cmdset_creation(self):
"called at first object creation."
self.add(CmdAttack())
class Weapon(TutorialObject):
"""
This defines a bladed weapon.
@ -766,7 +799,8 @@ class Weapon(TutorialObject):
Important attributes (set at creation):
hit - chance to hit (0-1)
parry - chance to parry (0-1)
damage - base damage given (modified by hit success and type of attack) (0-10)
damage - base damage given (modified by hit success and
type of attack) (0-10)
"""
def at_object_creation(self):
@ -779,13 +813,17 @@ class Weapon(TutorialObject):
self.cmdset.add_default(CmdSetWeapon, permanent=True)
def reset(self):
"When reset, the weapon is simply deleted, unless it has a place to return to."
"""
When reset, the weapon is simply deleted, unless it has a place
to return to.
"""
if self.location.has_player and self.home == self.location:
self.location.msg_contents("%s suddenly and magically fades into nothingness, as if it was never there ..." % self.key)
self.delete()
else:
self.location = self.home
#------------------------------------------------------------
#
# Weapon rack - spawns weapons
@ -833,18 +871,23 @@ class CmdSetWeaponRack(CmdSet):
"group the rack cmd"
key = "weaponrack_cmdset"
mergemode = "Replace"
def at_cmdset_creation(self):
"Called at first creation of cmdset"
self.add(CmdGetWeapon())
class WeaponRack(TutorialObject):
"""
This will spawn a new weapon for the player unless the player already has one from this rack.
This will spawn a new weapon for the player unless the player already has
one from this rack.
attribute to set at creation:
min_dmg - the minimum damage of objects from this rack
max_dmg - the maximum damage of objects from this rack
magic - if weapons should be magical (have the magic flag set)
get_text - the echo text to return when getting the weapon. Give '%s' to include the name of the weapon.
get_text - the echo text to return when getting the weapon. Give '%s'
to include the name of the weapon.
"""
def at_object_creation(self):
"called at creation"

View file

@ -10,6 +10,7 @@ from ev import utils, create_object, search_object
from contrib.tutorial_world import scripts as tut_scripts
from contrib.tutorial_world.objects import LightSource, TutorialObject
#------------------------------------------------------------
#
# Tutorial room - parent room class
@ -45,7 +46,7 @@ class CmdTutorial(Command):
caller = self.caller
if not self.args:
target = self.obj # this is the room object the command is defined on
target = self.obj # this is the room the command is defined on
else:
target = caller.search(self.args.strip())
if not target:
@ -56,13 +57,16 @@ class CmdTutorial(Command):
else:
caller.msg("{RSorry, there is no tutorial help available here.{n")
class TutorialRoomCmdSet(CmdSet):
"Implements the simple tutorial cmdset"
key = "tutorial_cmdset"
def at_cmdset_creation(self):
"add the tutorial cmd"
self.add(CmdTutorial())
class TutorialRoom(Room):
"""
This is the base room type for all rooms in the tutorial world.
@ -78,7 +82,6 @@ class TutorialRoom(Room):
pass
#------------------------------------------------------------
#
# Weather room - scripted room
@ -89,7 +92,6 @@ class TutorialRoom(Room):
#
#------------------------------------------------------------
class WeatherRoom(TutorialRoom):
"""
This should probably better be called a rainy room...
@ -107,6 +109,7 @@ class WeatherRoom(TutorialRoom):
self.scripts.add(tut_scripts.IrregularEvent)
self.db.tutorial_info = \
"This room has a Script running that has it echo a weather-related message at irregular intervals."
def update_irregular(self):
"create a tuple of possible texts to return."
strings = (
@ -122,21 +125,23 @@ class WeatherRoom(TutorialRoom):
"You hear the distant howl of what sounds like some sort of dog or wolf.",
"Large clouds rush across the sky, throwing their load of rain over the world.")
# get a random value so we can select one of the strings above. Send this to the room.
# get a random value so we can select one of the strings above.
# Send this to the room.
irand = random.randint(0, 15)
if irand > 10:
return # don't return anything, to add more randomness
return # don't return anything, to add more randomness
self.msg_contents("{w%s{n" % strings[irand])
#-----------------------------------------------------------------------------------
#------------------------------------------------------------------------------
#
# Dark Room - a scripted room
#
# This room limits the movemenets of its denizens unless they carry a and active
# LightSource object (LightSource is defined in tutorialworld.objects.LightSource)
# LightSource object (LightSource is defined in
# tutorialworld.objects.LightSource)
#
#-----------------------------------------------------------------------------------
#------------------------------------------------------------------------------
class CmdLookDark(Command):
"""
@ -169,13 +174,15 @@ class CmdLookDark(Command):
caller.msg(messages[irand])
else:
# check so we don't already carry a lightsource.
carried_lights = [obj for obj in caller.contents if utils.inherits_from(obj, LightSource)]
carried_lights = [obj for obj in caller.contents
if utils.inherits_from(obj, LightSource)]
if carried_lights:
string = "You don't want to stumble around in blindness anymore. You already found what you need. Let's get light already!"
caller.msg(string)
return
#if we are lucky, we find the light source.
lightsources = [obj for obj in self.obj.contents if utils.inherits_from(obj, LightSource)]
lightsources = [obj for obj in self.obj.contents
if utils.inherits_from(obj, LightSource)]
if lightsources:
lightsource = lightsources[0]
else:
@ -186,6 +193,7 @@ class CmdLookDark(Command):
string += "\nYou pick it up, holding it firmly. Now you just need to {wlight{n it using the flint and steel you carry with you."
caller.msg(string)
class CmdDarkHelp(Command):
"""
Help command for the dark state.
@ -193,27 +201,34 @@ class CmdDarkHelp(Command):
key = "help"
locks = "cmd:all()"
help_category = "TutorialWorld"
def func(self):
"Implements the help command."
string = "Can't help you until you find some light! Try feeling around for something to burn."
string += " You cannot give up even if you don't find anything right away."
self.caller.msg(string)
# the nomatch system command will give a suitable error when we cannot find the normal commands.
# the nomatch system command will give a suitable error when we cannot find
# the normal commands.
from src.commands.default.syscommands import CMD_NOMATCH
from src.commands.default.general import CmdSay
class CmdDarkNoMatch(Command):
"This is called when there is no match"
key = CMD_NOMATCH
locks = "cmd:all()"
def func(self):
"Implements the command."
self.caller.msg("Until you find some light, there's not much you can do. Try feeling around.")
class DarkCmdSet(CmdSet):
"Groups the commands."
key = "darkroom_cmdset"
mergetype = "Replace" # completely remove all other commands
mergetype = "Replace" # completely remove all other commands
def at_cmdset_creation(self):
"populates the cmdset."
self.add(CmdTutorial())
@ -221,6 +236,7 @@ class DarkCmdSet(CmdSet):
self.add(CmdDarkHelp())
self.add(CmdDarkNoMatch())
self.add(CmdSay)
#
# Darkness room two-state system
#
@ -238,6 +254,7 @@ class DarkState(Script):
self.key = "tutorial_darkness_state"
self.desc = "A dark room"
self.persistent = True
def at_start(self):
"called when the script is first starting up."
for char in [char for char in self.obj.contents if char.has_player]:
@ -246,9 +263,11 @@ class DarkState(Script):
else:
char.cmdset.add(DarkCmdSet)
char.msg("The room is pitch dark! You are likely to be eaten by a Grue.")
def is_valid(self):
"is valid only as long as noone in the room has lit the lantern."
return not self.obj.is_lit()
def at_stop(self):
"Someone turned on a light. This state dies. Switch to LightState."
for char in [char for char in self.obj.contents if char.has_player]:
@ -256,23 +275,31 @@ class DarkState(Script):
self.obj.db.is_dark = False
self.obj.scripts.add(LightState)
class LightState(Script):
"""
This is the counterpart to the Darkness state. It is active when the lantern is on.
This is the counterpart to the Darkness state. It is active when the
lantern is on.
"""
def at_script_creation(self):
"Called when script is first created."
self.key = "tutorial_light_state"
self.desc = "A room lit up"
self.persistent = True
def is_valid(self):
"This state is only valid as long as there is an active light source in the room."
"""
This state is only valid as long as there is an active light
source in the room.
"""
return self.obj.is_lit()
def at_stop(self):
"Light disappears. This state dies. Return to DarknessState."
self.obj.db.is_dark = True
self.obj.scripts.add(DarkState)
class DarkRoom(TutorialRoom):
"""
A dark room. This tries to start the DarkState script on all
@ -287,20 +314,24 @@ class DarkRoom(TutorialRoom):
"""
return any([any([True for obj in char.contents
if utils.inherits_from(obj, LightSource) and obj.db.is_active])
for char in self.contents if char.has_player])
for char in self.contents if char.has_player])
def at_object_creation(self):
"Called when object is first created."
super(DarkRoom, self).at_object_creation()
self.db.tutorial_info = "This is a room with custom command sets on itself."
# this variable is set by the scripts. It makes for an easy flag to look for
# by other game elements (such as the crumbling wall in the tutorial)
# this variable is set by the scripts. It makes for an easy flag to
# look for by other game elements (such as the crumbling wall in
# the tutorial)
self.db.is_dark = True
# the room starts dark.
self.scripts.add(DarkState)
def at_object_receive(self, character, source_location):
"Called when an object enters the room. We crank the wheels to make sure scripts are synced."
"""
Called when an object enters the room. We crank the wheels to make
sure scripts are synced.
"""
if character.has_player:
if not self.is_lit() and not character.is_superuser:
character.cmdset.add(DarkCmdSet)
@ -313,10 +344,14 @@ class DarkRoom(TutorialRoom):
self.scripts.validate()
def at_object_leave(self, character, target_location):
"In case people leave with the light, we make sure to update the states accordingly."
character.cmdset.delete(DarkCmdSet) # in case we are teleported away
"""
In case people leave with the light, we make sure to update the
states accordingly.
"""
character.cmdset.delete(DarkCmdSet) # in case we are teleported away
self.scripts.validate()
#------------------------------------------------------------
#
# Teleport room - puzzle room
@ -347,23 +382,27 @@ class TeleportRoom(TutorialRoom):
super(TeleportRoom, self).at_object_creation()
# what character.db.puzzle_clue must be set to, to avoid teleportation.
self.db.puzzle_value = 1
# the target of the success teleportation. Can be a dbref or a unique room name.
# target of successful teleportation. Can be a dbref or a
# unique room name.
self.db.success_teleport_to = "treasure room"
# the target of the failure teleportation.
self.db.failure_teleport_to = "dark cell"
def at_object_receive(self, character, source_location):
"This hook is called by the engine whenever the player is moved into this room."
"""
This hook is called by the engine whenever the player is moved into
this room.
"""
if not character.has_player:
# only act on player characters.
return
#print character.db.puzzle_clue, self.db.puzzle_value
if character.db.puzzle_clue != self.db.puzzle_value:
# we didn't pass the puzzle. See if we can teleport.
teleport_to = self.db.failure_teleport_to # this is a room name
teleport_to = self.db.failure_teleport_to # this is a room name
else:
# passed the puzzle
teleport_to = self.db.success_teleport_to # this is a room name
teleport_to = self.db.success_teleport_to # this is a room name
results = search_object(teleport_to)
if not results or len(results) > 1:
@ -376,7 +415,7 @@ class TeleportRoom(TutorialRoom):
return
# teleport
character.execute_cmd("look")
character.location = results[0] # stealth move
character.location = results[0] # stealth move
character.location.at_object_receive(character, self)
#------------------------------------------------------------
@ -412,7 +451,8 @@ class CmdEast(Command):
bridge_step = min(5, caller.db.tutorial_bridge_position + 1)
if bridge_step > 4:
# we have reached the far east end of the bridge. Move to the east room.
# we have reached the far east end of the bridge.
# Move to the east room.
eexit = search_object(self.obj.db.east_exit)
if eexit:
caller.move_to(eexit[0])
@ -423,6 +463,7 @@ class CmdEast(Command):
caller.location.msg_contents("%s steps eastwards across the bridge." % caller.name, exclude=caller)
caller.execute_cmd("look")
# go back across the bridge
class CmdWest(Command):
"""
@ -440,7 +481,8 @@ class CmdWest(Command):
bridge_step = max(-1, caller.db.tutorial_bridge_position - 1)
if bridge_step < 0:
# we have reached the far west end of the bridge. Move to the west room.
# we have reached the far west end of the bridge.#
# Move to the west room.
wexit = search_object(self.obj.db.west_exit)
if wexit:
caller.move_to(wexit[0])
@ -451,6 +493,7 @@ class CmdWest(Command):
caller.location.msg_contents("%s steps westwartswards across the bridge." % caller.name, exclude=caller)
caller.execute_cmd("look")
class CmdLookBridge(Command):
"""
looks around at the bridge.
@ -486,7 +529,8 @@ class CmdLookBridge(Command):
self.caller.msg(message)
# there is a chance that we fall if we are on the western or central part of the bridge.
# there is a chance that we fall if we are on the western or central
# part of the bridge.
if bridge_position < 3 and random.random() < 0.05 and not self.caller.is_superuser:
# we fall on 5% of the times.
fexit = search_object(self.obj.db.fall_exit)
@ -504,6 +548,7 @@ class CmdLookBridge(Command):
self.caller.location = fexit[0] # stealth move, without any other hook calls.
self.obj.msg_contents("A plank gives way under %s's feet and they fall from the bridge!" % self.caller.key)
# custom help command
class CmdBridgeHelp(Command):
"""
@ -521,33 +566,38 @@ class CmdBridgeHelp(Command):
string += "or try to get back to the mainland {wwest{n)."
self.caller.msg(string)
class BridgeCmdSet(CmdSet):
"This groups the bridge commands. We will store it on the room."
key = "Bridge commands"
priority = 1 # this gives it precedence over the normal look/help commands.
def at_cmdset_creation(self):
"Called at first cmdset creation"
self.add(CmdTutorial())
self.add(CmdEast())
self.add(CmdWest())
self.add(CmdLookBridge())
self.add(CmdBridgeHelp())
class BridgeRoom(TutorialRoom):
"""
The bridge room implements an unsafe bridge. It also enters the player into a
state where they get new commands so as to try to cross the bridge.
The bridge room implements an unsafe bridge. It also enters the player into
a state where they get new commands so as to try to cross the bridge.
We want this to result in the player getting a special set of
commands related to crossing the bridge. The result is that it will take several
steps to cross it, despite it being represented by only a single room.
commands related to crossing the bridge. The result is that it will
take several steps to cross it, despite it being represented by only a
single room.
We divide the bridge into steps:
self.db.west_exit - - | - - self.db.east_exit
0 1 2 3 4
The position is handled by a variable stored on the player when entering and giving
special move commands will increase/decrease the counter until the bridge is crossed.
The position is handled by a variable stored on the player when entering
and giving special move commands will increase/decrease the counter
until the bridge is crossed.
"""
def at_object_creation(self):
@ -617,8 +667,8 @@ class BridgeRoom(TutorialRoom):
#
# Intro Room - unique room
#
# This room marks the start of the tutorial. It sets up properties on the player char
# that is needed for the tutorial.
# This room marks the start of the tutorial. It sets up properties on
# the player char that is needed for the tutorial.
#
#------------------------------------------------------------
@ -652,6 +702,7 @@ class IntroRoom(TutorialRoom):
string += "-"*78
character.msg("{r%s{n" % string)
#------------------------------------------------------------
#
# Outro room - unique room
@ -683,5 +734,6 @@ class OutroRoom(TutorialRoom):
del character.db.puzzle_clue
del character.db.combat_parry_mode
del character.db.tutorial_bridge_position
for tut_obj in [obj for obj in character.contents if utils.inherits_from(obj, TutorialObject)]:
for tut_obj in [obj for obj in character.contents
if utils.inherits_from(obj, TutorialObject)]:
tut_obj.reset()

View file

@ -5,6 +5,7 @@ This defines some generally useful scripts for the tutorial world.
import random
from ev import Script
#------------------------------------------------------------
#
# IrregularEvent - script firing at random intervals
@ -28,8 +29,9 @@ class IrregularEvent(Script):
self.key = "update_irregular"
self.desc = "Updates at irregular intervals"
self.interval = random.randint(30, 70) # interval to call.
self.start_delay = True # wait at least self.interval seconds before calling at_repeat the first time
self.interval = random.randint(30, 70) # interval to call.
self.start_delay = True # wait at least self.interval seconds before
# calling at_repeat the first time
self.persistent = True
# this attribute determines how likely it is the
@ -47,11 +49,13 @@ class IrregularEvent(Script):
except Exception:
pass
class FastIrregularEvent(IrregularEvent):
"A faster updating irregular event"
def at_script_creation(self):
"Called at initial script creation"
super(FastIrregularEvent, self).at_script_creation()
self.interval = 5 # every 5 seconds, 1/5 chance of firing
self.interval = 5 # every 5 seconds, 1/5 chance of firing
#------------------------------------------------------------
@ -64,11 +68,13 @@ class FastIrregularEvent(IrregularEvent):
# #
# # This sets up a reset system -- it resets the entire tutorial_world domain
# # and all objects inheriting from it back to an initial state, MORPG style. This is useful in order for
# # different players to explore it without finding things missing.
# # and all objects inheriting from it back to an initial state, MORPG style.
# This is useful in order for different players to explore it without finding
# # things missing.
# #
# # Note that this will of course allow a single player to end up with multiple versions of objects if
# # they just wait around between resets; In a real game environment this would have to be resolved e.g.
# # Note that this will of course allow a single player to end up with
# # multiple versions of objects if they just wait around between resets;
# # In a real game environment this would have to be resolved e.g.
# # with custom versions of the 'get' command not accepting doublets.
# #
@ -77,7 +83,8 @@ class FastIrregularEvent(IrregularEvent):
# UPDATE_INTERVAL = 60 * 10 # Measured in seconds
# #This is a list of script parent objects that subscribe to the reset functionality.
# #This is a list of script parent objects that subscribe to the reset
# functionality.
# RESET_SUBSCRIBERS = ["examples.tutorial_world.p_weapon_rack",
# "examples.tutorial_world.p_mob"]
@ -104,7 +111,4 @@ class FastIrregularEvent(IrregularEvent):
# try:
# obj.scriptlink.reset()
# except:
# logger.log_errmsg(traceback.print_exc())
# logger.log_errmsg(traceback.print_exc())