From 1b0544c261c53b7d35ec9aae8a588884a11645c0 Mon Sep 17 00:00:00 2001 From: Griatch Date: Thu, 27 Sep 2012 21:36:20 +0200 Subject: [PATCH] Fixing tutorial world usage of search. --- contrib/tutorial_world/mob.py | 162 ++++++++--------- contrib/tutorial_world/objects.py | 290 +++++++++++++++--------------- contrib/tutorial_world/rooms.py | 2 +- 3 files changed, 227 insertions(+), 227 deletions(-) diff --git a/contrib/tutorial_world/mob.py b/contrib/tutorial_world/mob.py index 6e67270bd2..082376fc10 100644 --- a/contrib/tutorial_world/mob.py +++ b/contrib/tutorial_world/mob.py @@ -1,7 +1,7 @@ """ -This module implements a simple mobile object with +This module implements a simple mobile object with a very rudimentary AI as well as an aggressive enemy -object based on that mobile class. +object based on that mobile class. """ @@ -16,10 +16,10 @@ BASE_CHARACTER_TYPECLASS = settings.BASE_CHARACTER_TYPECLASS #------------------------------------------------------------ # -# Mob - mobile object +# Mob - mobile object # # This object utilizes exits and moves about randomly from -# room to room. +# room to room. # #------------------------------------------------------------ @@ -27,7 +27,7 @@ class Mob(tut_objects.TutorialObject): """ This type of mobile will roam from exit to exit at random intervals. Simply lock exits against the is_mob attribute - to block them from the mob (lockstring = "traverse:not attr(is_mob)"). + to block them from the mob (lockstring = "traverse:not attr(is_mob)"). """ def at_object_creation(self): "This is called when the object is first created." @@ -35,11 +35,11 @@ class Mob(tut_objects.TutorialObject): self.scripts.add(tut_scripts.IrregularEvent) # this is a good attribute for exits to look for, to block - # a mob from entering certain exits. - self.db.is_mob = True - self.db.last_location = None - # only when True will the mob move. - self.db.roam_mode = True + # a mob from entering certain exits. + self.db.is_mob = True + self.db.last_location = None + # only when True will the mob move. + self.db.roam_mode = True def announce_move_from(self, destination): "Called just before moving" @@ -53,8 +53,8 @@ class Mob(tut_objects.TutorialObject): "Called at irregular intervals. Moves the mob." if self.roam_mode: 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. + 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] if new_exits: exits = new_exits @@ -67,15 +67,15 @@ class Mob(tut_objects.TutorialObject): #------------------------------------------------------------ # -# Enemy - mobile attacking object +# Enemy - mobile attacking object # -# An enemy is a mobile that is aggressive against players -# in its vicinity. An enemy will try to attack characters +# An enemy is a mobile that is aggressive against players +# in its vicinity. An enemy will try to attack characters # in the same location. It will also pursue enemies through -# exits if possible. +# exits if possible. # -# An enemy needs to have a Weapon object in order to -# attack. +# An enemy needs to have a Weapon object in order to +# attack. # # This particular tutorial enemy is a ghostly apparition that can only # be hurt by magical weapons. It will also not truly "die", but only @@ -90,44 +90,44 @@ class AttackTimer(Script): """ def at_script_creation(self): "This sets up the script" - self.key = "AttackTimer" + self.key = "AttackTimer" self.desc = "Drives an Enemy's combat." - self.interval = random.randint(2, 3) # how fast the Enemy acts + self.interval = random.randint(2, 3) # how fast the Enemy acts self.start_delay = True # wait self.interval before first call - self.persistent = True + self.persistent = True def at_repeat(self): - "Called every self.interval seconds." + "Called every self.interval seconds." if self.obj.db.inactive: - return + return #print "attack timer: at_repeat", self.dbobj.id, self.ndb.twisted_task, id(self.ndb.twisted_task) - if self.obj.db.roam_mode: + if self.obj.db.roam_mode: self.obj.roam() #return elif self.obj.db.battle_mode: #print "attack" self.obj.attack() - return + return elif self.obj.db.pursue_mode: #print "pursue" self.obj.pursue() #return else: - #dead mode. Wait for respawn. + #dead mode. Wait for respawn. dead_at = self.db.dead_at if not dead_at: self.db.dead_at = time.time() if (time.time() - self.db.dead_at) > self.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. - An enemy can be in four modes: + An enemy can be in four modes: roam (inherited from Mob) - where it just moves around randomly - battle - where it stands in one place and attacks players + battle - where it stands in one place and attacks players pursue - where it follows a player, trying to enter combat again dead - passive and invisible until it is respawned @@ -139,19 +139,19 @@ class Enemy(Mob): 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): "Called at object creation." super(Enemy, self).at_object_creation() - + self.db.tutorial_info = "This moving object will attack players in the same room." - - # state machine modes + + # state machine modes self.db.roam_mode = True self.db.battle_mode = False - self.db.pursue_mode = False + self.db.pursue_mode = False self.db.dead_mode = False # health (change this at creation time) self.db.full_health = 20 @@ -159,8 +159,8 @@ class Enemy(Mob): 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 - # store the last player to hit - self.db.last_attacker = None + # store the last player to hit + self.db.last_attacker = None # where to take defeated enemies self.db.defeat_location = "darkcell" self.scripts.add(AttackTimer) @@ -169,26 +169,26 @@ class Enemy(Mob): "the irregular event is inherited from Mob class" strings = self.db.irregular_echoes if strings: - self.location.msg_contents(strings[random.randint(0, len(strings) - 1)]) + self.location.msg_contents(strings[random.randint(0, len(strings) - 1)]) def roam(self): "Called by Attack timer. Will move randomly as long as exits are open." - # in this mode, the mob is healed. + # in this mode, the mob is healed. self.db.health = self.db.full_health - players = [obj for obj in self.location.contents + 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. Attack. - self.db.roam_mode = False + if players: + # we found players in the room. Attack. + self.db.roam_mode = False self.db.pursue_mode = False - self.db.battle_mode = True + self.db.battle_mode = True 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")] - if exits: - # Try to make it so the mob doesn't backtrack. + 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] if new_exits: exits = new_exits @@ -198,7 +198,7 @@ class Enemy(Mob): else: # no exits - a dead end room. Respawn back to start. self.move_to(self.home) - + def attack(self): """ This is the main mode of combat. It will try to hit players in @@ -206,11 +206,11 @@ class Enemy(Mob): to the defeat location. """ 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] + players = [obj for obj in self.location.contents + if utils.inherits_from(obj, BASE_CHARACTER_TYPECLASS) and not obj.is_superuser] if players: - - # find a target + + # find a target if last_attacker in players: # prefer to attack the player last attacking. target = last_attacker @@ -226,7 +226,7 @@ class Enemy(Mob): # analyze result. if target.db.health <= 0: # we reduced enemy to 0 health. Whisp them off to the prison room. - tloc = search_object(self.db.defeat_location, global_search=True) + tloc = search_object(self.db.defeat_location) tstring = self.db.defeat_text if not tstring: tstring = "You feel your conciousness slip away ... you fall to the ground as " @@ -240,24 +240,24 @@ class Enemy(Mob): target.location = tloc[0] tloc[0].at_object_receive(target, self.location) elif not ostring: - ostring = "%s falls to the ground!" % target.key + ostring = "%s falls to the ground!" % target.key self.location.msg_contents(ostring, exclude=[target]) else: # 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 - + def pursue(self): """ In pursue mode, the enemy tries to find players in adjoining rooms, preferably - those that previously attacked it. + those that previously attacked it. """ 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] + 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. + # before we had time to pursue them. Switch to battle mode. self.battle_mode = True self.roam_mode = False self.pursue_mode = False @@ -266,43 +266,43 @@ class Enemy(Mob): 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. + # 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)]: - players[obj] = dest + players[obj] = dest if players: # we found targets. Move to intercept. if last_attacker in players: # preferably the one that last attacked us self.move_to(players[last_attacker]) else: - # otherwise randomly. + # otherwise randomly. key = players.keys()[random.randint(0, len(players) - 1)] self.move_to(players[key]) else: - # we found no players nearby. Return to roam mode. + # we found no players nearby. Return to roam mode. self.battle_mode = False self.roam_mode = True self.pursue_mode = False - + def at_hit(self, weapon, attacker, damage): """ Called when this object is hit by an enemy's weapon Should return True if enemy is defeated, False otherwise. In the case of players attacking, we handle all the events - and information from here, so the return value is not used. + and information from here, so the return value is not used. """ - self.db.last_attacker = attacker + self.db.last_attacker = attacker if not self.db.battle_mode: # we were attacked, so switch to battle mode. self.db.roam_mode = False - self.db.pursue_mode = False - self.db.battle_mode = True + self.db.pursue_mode = False + self.db.battle_mode = True #self.scripts.add(AttackTimer) - + if not weapon.db.magic: # In the tutorial, the enemy is a ghostly apparition, so # only magical weapons can harm it. @@ -310,7 +310,7 @@ class Enemy(Mob): if not string: string = "Your weapon just passes through your enemy, causing no effect!" attacker.msg(string) - return + return else: # an actual hit health = float(self.db.health) @@ -319,10 +319,10 @@ class Enemy(Mob): if health <= 0: string = self.db.win_text if not string: - string = "After your last hit, %s folds in on itself, it seems to fade away into nothingness. " % self.key + string = "After your last hit, %s folds in on itself, it seems to fade away into nothingness. " % self.key string += "In a moment there is nothing left but the echoes of its screams. But you have a " string += "feeling it is only temporarily weakened. " - string += "You fear it's only a matter of time before it materializes somewhere again." + string += "You fear it's only a matter of time before it materializes somewhere again." attacker.msg(string) string = self.db.win_text_room if not string: @@ -331,28 +331,28 @@ class Enemy(Mob): string += "feeling it is only temporarily weakened. " 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. IrregularEvent will bring it back later. + + # put enemy in dead mode and hide it from view. IrregularEvent will bring it back later. self.db.roam_mode = False - self.db.pursue_mode = False - self.db.battle_mode = False - self.db.dead_mode = True + self.db.pursue_mode = False + self.db.battle_mode = False + self.db.dead_mode = True self.db.dead_at = time.time() - self.location = None + self.location = None else: self.location.msg_contents("%s wails, shudders and writhes." % self.key) - return False + return False def reset(self): "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 - self.db.pursue_mode = False - self.db.battle_mode = False - self.db.dead_mode = False - self.location = self.home + self.db.pursue_mode = False + self.db.battle_mode = False + self.db.dead_mode = False + self.location = self.home string = self.db.respawn_text - if not string: + if not string: string = "%s fades into existence from out of thin air. It's looking pissed." % self.key self.location.msg_contents(string) diff --git a/contrib/tutorial_world/objects.py b/contrib/tutorial_world/objects.py index be74480a37..6c48b6d6d0 100644 --- a/contrib/tutorial_world/objects.py +++ b/contrib/tutorial_world/objects.py @@ -1,32 +1,32 @@ """ TutorialWorld - basic objects - Griatch 2011 -This module holds all "dead" object definitions for -the tutorial world. Object-commands and -cmdsets +This module holds all "dead" object definitions for +the tutorial world. Object-commands and -cmdsets are also defined here, together with the object. -Objects: +Objects: TutorialObject -Readable +Readable Climbable -Obelisk -LightSource +Obelisk +LightSource CrumblingWall -Weapon +Weapon WeaponRack """ -import time, random +import time, random from ev import utils, create_object from ev import Object, Exit, Command, CmdSet, Script #------------------------------------------------------------ # -# TutorialObject +# TutorialObject # # The TutorialObject is the base class for all items # in the tutorial. They have an attribute "tutorial_info" @@ -35,7 +35,7 @@ from ev import Object, Exit, Command, CmdSet, Script # # TutorialObjects may also be "reset". What the reset means # is up to the object. It can be the resetting of the world -# itself, or the removal of an inventory item from a +# itself, or the removal of an inventory item from a # character's inventory when leaving the tutorial, for example. # #------------------------------------------------------------ @@ -51,7 +51,7 @@ class TutorialObject(Object): super(TutorialObject, self).at_object_creation() self.db.tutorial_info = "No tutorial info is available for this object." #self.db.last_reset = time.time() - + def reset(self): "Resets the object, whatever that may mean." self.location = self.home @@ -59,13 +59,13 @@ class TutorialObject(Object): #------------------------------------------------------------ # -# Readable - an object one can "read". +# Readable - an object one can "read". # #------------------------------------------------------------ class CmdRead(Command): """ - Usage: + Usage: read [obj] Read some text. @@ -82,8 +82,8 @@ class CmdRead(Command): else: obj = self.obj if not obj: - return - # we want an attribute read_text to be defined. + return + # we want an attribute read_text to be defined. readtext = obj.db.readable_text if readtext: string = "You read {C%s{n:\n %s" % (obj.key, readtext) @@ -100,7 +100,7 @@ class CmdSetReadable(CmdSet): class Readable(TutorialObject): """ This object defines some attributes and defines a read method on itself. - """ + """ def at_object_creation(self): "Called when object is created" super(Readable, self).at_object_creation() @@ -116,14 +116,14 @@ class Readable(TutorialObject): # # The climbable object works so that once climbed, it sets # a flag on the climber to show that it was climbed. A simple -# command 'climb' handles the actual climbing. +# command 'climb' handles the actual climbing. # #------------------------------------------------------------ class CmdClimb(Command): """ - Usage: - climb + Usage: + climb """ key = "climb" locks = "cmd:all()" @@ -140,7 +140,7 @@ class CmdClimb(Command): return if obj != self.obj: self.caller.msg("Try as you might, you cannot climb that.") - return + return ostring = self.obj.db.climb_text if not ostring: ostring = "You climb %s. Having looked around, you climb down again." % self.obj.name @@ -153,10 +153,10 @@ class CmdSetClimbable(CmdSet): "populate set" self.add(CmdClimb()) - + class Climbable(TutorialObject): "A climbable object." - + def at_object_creation(self): "Called at initial creation only" self.cmdset.add_default(CmdSetClimbable, permanent=True) @@ -165,14 +165,14 @@ class Climbable(TutorialObject): #------------------------------------------------------------ # -# Obelisk - a unique item +# Obelisk - a unique item # # The Obelisk is an object with a modified return_appearance -# method that causes it to look slightly different every -# time one looks at it. Since what you actually see -# is a part of a game puzzle, the act of looking also +# method that causes it to look slightly different every +# time one looks at it. Since what you actually see +# is a part of a game puzzle, the act of looking also # stores a key attribute on the looking object for later -# reference. +# reference. # #------------------------------------------------------------ @@ -181,36 +181,36 @@ OBELISK_DESCS = ["You can briefly make out the image of {ba woman with a blue bi "For the briefest moment you make out an engraving of {ba regal woman wearing a crown{n.", "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. """ - + def at_object_creation(self): "Called when object is created." super(Obelisk, self).at_object_creation() self.db.tutorial_info = "This object changes its desc randomly, and makes sure to remember which one you saw." # make sure this can never be picked up self.locks.add("get:false()") - + def return_appearance(self, caller): - "Overload the default version of this hook." + "Overload the default version of this hook." 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. " self.db.desc = string + OBELISK_DESCS[clueindex] # remember that this was the clue we got. - caller.db.puzzle_clue = clueindex + caller.db.puzzle_clue = clueindex # call the parent function as normal (this will use db.desc we just set) return super(Obelisk, self).return_appearance(caller) #------------------------------------------------------------ # -# LightSource +# LightSource # -# This object that emits light and can be +# This object that emits light and can be # turned on or off. It must be carried to use and has only # a limited burn-time. # When burned out, it will remove itself from the carrying @@ -228,7 +228,7 @@ class StateLightSourceOn(Script): self.key = "lightsourceBurn" self.desc = "Keeps lightsources burning." self.start_delay = True # only fire after self.interval s. - self.repeats = 1 # only run once. + self.repeats = 1 # only run once. self.persistent = True # survive a server reboot. def at_start(self): @@ -237,15 +237,15 @@ class StateLightSourceOn(Script): self.db.script_started = time.time() def at_repeat(self): - # this is only called when torch has burnt out + # this is only called when torch has burnt out self.obj.db.burntime = -1 self.obj.reset() def at_stop(self): """ - Since the user may also turn off the light + Since the user may also turn off the light prematurely, this hook will store the current - burntime. + burntime. """ # calculate remaining burntime, if object is not # already deleted (because it burned out) @@ -264,7 +264,7 @@ class StateLightSourceOn(Script): class CmdLightSourceOn(Command): """ - Switches on the lightsource. + Switches on the lightsource. """ key = "on" aliases = ["switch on", "turn on", "light"] @@ -273,16 +273,16 @@ class CmdLightSourceOn(Command): def func(self): "Implements the command" - + if self.obj.db.is_active: self.caller.msg("%s is already burning." % self.obj.key) else: # set lightsource to active - self.obj.db.is_active = True + self.obj.db.is_active = True # activate the script to track burn-time. - self.obj.scripts.add(StateLightSourceOn) + 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]) + 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. self.caller.location.scripts.validate() # look around @@ -313,7 +313,7 @@ class CmdLightSourceOff(Command): 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" @@ -322,69 +322,69 @@ class CmdSetLightSource(CmdSet): "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.is_active = False 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 + # 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 + 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 + # light burned out. Since the lightsources's "location" should be # a character, notify them this way. try: loc = self.location.location except AttributeError: loc = self.location loc.msg_contents("{c%s{n {Rburns out.{n" % self.key) - self.db.is_active = False + self.db.is_active = False try: - # validate in holders current room, if possible - self.location.location.scripts.validate() + # validate in holders current room, if possible + self.location.location.scripts.validate() except AttributeError: - # maybe it was dropped, try validating at current location. + # maybe it was dropped, try validating at current location. try: self.location.scripts.validate() except AttributeError,e: - pass + pass self.delete() #------------------------------------------------------------ -# +# # Crumbling wall - unique exit # -# This implements a simple puzzle exit that needs to be +# This implements a simple puzzle exit that needs to be # accessed with commands before one can get to traverse it. # -# The puzzle is currently simply to move roots (that have -# presumably covered the wall) aside until a button for a -# secret door is revealed. The original position of the -# roots blocks the button, so they have to be moved to a certain -# position - when they have, the "press button" command -# is made available and the Exit is made traversable. +# The puzzle is currently simply to move roots (that have +# presumably covered the wall) aside until a button for a +# secret door is revealed. The original position of the +# roots blocks the button, so they have to be moved to a certain +# position - when they have, the "press button" command +# is made available and the Exit is made traversable. # #------------------------------------------------------------ # There are four roots - two horizontal and two vertically # running roots. Each can have three positions: top/middle/bottom -# and left/middle/right respectively. There can be any number of -# roots hanging through the middle position, but only one each +# and left/middle/right respectively. There can be any number of +# roots hanging through the middle position, but only one each # along the sides. The goal is to make the center position clear. # (yes, it's really as simple as it sounds, just move the roots # to each side to "win". This is just a tutorial, remember?) @@ -396,35 +396,35 @@ class CmdShiftRoot(Command): shift blue root left/right shift red root left/right shift yellow root up/down - shift green root up/down + shift green root up/down - """ - key = "shift" + """ + key = "shift" aliases = ["move"] # the locattr() lock looks for the attribute is_dark on the current room. locks = "cmd:not locattr(is_dark)" help_category = "TutorialWorld" - def parse(self): + def parse(self): "custom parser; split input by spaces" self.arglist = self.args.strip().split() def func(self): """ - Implement the command. + Implement the command. blue/red - vertical roots yellow/green - horizontal roots """ - + if not self.arglist: self.caller.msg("What do you want to move, and in what direction?") - return + return if "root" in self.arglist: self.arglist.remove("root") # we accept arguments on the form if not len(self.arglist) > 1: self.caller.msg("You must define which colour of root you want to move, and in which direction.") - return + return color = self.arglist[0].lower() direction = self.arglist[1].lower() # get current root positions dict @@ -432,7 +432,7 @@ class CmdShiftRoot(Command): if not color in root_pos: self.caller.msg("No such root to move.") - return + return # first, vertical roots (red/blue) - can be moved left/right if color == "red": @@ -496,11 +496,11 @@ class CmdShiftRoot(Command): self.caller.msg("The root with yellow flowers gets in the way and is pushed upwards.") else: self.caller.msg("You cannot move the root in that direction.") - # store new position + # store new position self.obj.db.root_pos = root_pos # check victory condition if root_pos.values().count(0) == 0: # no roots in middle position - self.caller.db.crumbling_wall_found_button = True + 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): @@ -511,19 +511,19 @@ class CmdPressButton(Command): 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. help_category = "TutorialWorld" - + def func(self): "Implements the command" if self.caller.db.crumbling_wall_found_exit: # we already pushed the button self.caller.msg("The button folded away when the secret passage opened. You cannot push it again.") - return - - # pushing the button + return + + # pushing the button string = "You move your fingers over the suspicious depression, then gives it a " string += "decisive push. First nothing happens, then there is a rumble and a hidden " - string += "{wpassage{n opens, dust and pebbles rumbling as part of the wall moves aside." + string += "{wpassage{n opens, dust and pebbles rumbling as part of the wall moves aside." # we are done - this will make the exit traversable! self.caller.db.crumbling_wall_found_exit = True @@ -531,7 +531,7 @@ class CmdPressButton(Command): eloc = self.caller.search(self.obj.db.destination, global_search=True) if not eloc: self.caller.msg("The exit leads nowhere, there's just more stone behind it ...") - return + return self.obj.destination = eloc self.caller.msg(string) @@ -539,22 +539,22 @@ class CmdSetCrumblingWall(CmdSet): "Group the commands for crumblingWall" key = "crumblingwall_cmdset" def at_cmdset_creation(self): - "called when object is first created." + "called when object is first created." self.add(CmdShiftRoot()) self.add(CmdPressButton()) - + class CrumblingWall(TutorialObject, Exit): """ The CrumblingWall can be examined in various ways, but only if a lit light source is in the room. The traversal - itself is blocked by a traverse: lock on the exit that only + itself is blocked by a traverse: lock on the exit that only allows passage if a certain attribute is set on the trying player. Important attribute destination - this property must be set to make this a valid exit - whenever the button is pushed (this hides it as an exit - until it actually is) + whenever the button is pushed (this hides it as an exit + until it actually is) """ def at_object_creation(self): "called when the object is first created." @@ -567,17 +567,17 @@ class CrumblingWall(TutorialObject, Exit): 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. + # 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} - + def _translate_position(self, root, ipos): "Translates the position into words" rootnames = {"red": "The {rreddish{n vertical-hanging root ", @@ -595,10 +595,10 @@ class CrumblingWall(TutorialObject, Exit): string = rootnames[root] + hpos[ipos] else: string = rootnames[root] + vpos[ipos] - return string + 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 " @@ -609,11 +609,11 @@ class CrumblingWall(TutorialObject, Exit): string += "The roots (or whatever they are - some of them are covered in small non-descript flowers) " string += "crisscross the wall, making it hard to clearly see its stony surface.\n" for key, pos in self.db.root_pos.items(): - string += "\n" + self._translate_position(key, pos) - self.db.desc = string + string += "\n" + self._translate_position(key, pos) + self.db.desc = string # call the parent to continue execution (will use desc we just set) 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." del traverser.db.crumbling_wall_found_button @@ -621,7 +621,7 @@ class CrumblingWall(TutorialObject, Exit): self.reset() def at_failed_traverse(self, traverser): - "This is called if the player fails to pass the Exit." + "This is called if the player fails to pass the Exit." traverser.msg("No matter how you try, you cannot force yourself through %s." % self.key) def reset(self): @@ -629,9 +629,9 @@ class CrumblingWall(TutorialObject, 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. + # have to try again. del obj.db.crumbling_wall_found_exit - + # Reset the roots with some random starting positions for the roots: start_pos = [{"yellow":1, "green":0, "red":0, "blue":0}, {"yellow":0, "green":0, "red":0, "blue":0}, @@ -639,31 +639,31 @@ class CrumblingWall(TutorialObject, Exit): {"yellow":1, "green":0, "red":0, "blue":0}, {"yellow":0, "green":0, "red":0, "blue":1}] self.db.root_pos = start_pos[random.randint(0, 4)] - self.destination = None + self.destination = None #------------------------------------------------------------ # # Weapon - object type # # A weapon is necessary in order to fight in the tutorial -# world. A weapon (which here is assumed to be a bladed +# world. A weapon (which here is assumed to be a bladed # melee weapon for close combat) has three commands, # stab, slash and defend. Weapons also have a property "magic" # to determine if they are usable against certain enemies. # # Since Characters don't have special skills in the tutorial, # we let the weapon itself determine how easy/hard it is -# to hit with it, and how much damage it can do. -# +# to hit with it, and how much damage it can do. +# #------------------------------------------------------------ class CmdAttack(Command): """ - Attack the enemy. Commands: + Attack the enemy. Commands: - stab - slash - parry + stab + slash + parry 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. @@ -672,7 +672,7 @@ class CmdAttack(Command): """ # this is an example of implementing many commands as a single command class, - # using the given command alias to separate between them. + # using the given command alias to separate between them. key = "attack" aliases = ["hit","kill", "fight", "thrust", "pierce", "stab", "slash", "chop", "parry", "defend"] @@ -683,50 +683,50 @@ class CmdAttack(Command): "Implements the stab" 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) - return + return - # parry mode - if cmdstring in ("parry", "defend"): + # parry mode + if cmdstring in ("parry", "defend"): string = "You raise your weapon in a defensive pose, ready to block the next enemy attack." self.caller.msg(string) - self.caller.db.combat_parry_mode = True + self.caller.db.combat_parry_mode = True self.caller.location.msg_contents("%s takes a defensive stance" % self.caller, exclude=[self.caller]) - return + return if not self.args: self.caller.msg("Who do you attack?") - return + return target = self.caller.search(self.args.strip()) if not target: - return - + return + string = "" tstring = "" ostring = "" - if cmdstring in ("thrust", "pierce", "stab"): + 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 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 + 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 + 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) - self.caller.db.combat_parry_mode = False + self.caller.db.combat_parry_mode = False else: self.caller.msg("You fumble with your weapon, unable to choose an appropriate action...") self.caller.location.msg_contents("%s fumbles with their weapon." % self.obj.key) self.caller.db.combat_parry_mode = False - return + return if target.db.combat_parry_mode: # target is defensive; even harder to hit! @@ -737,17 +737,17 @@ class CmdAttack(Command): self.caller.msg(string + "{gIt's a hit!{n") target.msg(tstring + "{rIt's a hit!{n") self.caller.location.msg_contents(ostring + "It's a hit!", exclude=[target,self.caller]) - + # call enemy hook if hasattr(target, "at_hit"): # should return True if target is defeated, False otherwise. return target.at_hit(self.obj, self.caller, damage) elif target.db.health: - target.db.health -= damage + target.db.health -= damage else: # sorry, impossible to fight this enemy ... self.caller.msg("The enemy seems unaffacted.") - return False + return False else: self.caller.msg(string + "{rYou miss.{n") target.msg(tstring + "{gThey miss you.{n") @@ -775,9 +775,9 @@ class Weapon(TutorialObject): self.db.hit = 0.4 # hit chance self.db.parry = 0.8 # parry chance self.damage = 8.0 - self.magic = False + self.magic = False 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." if self.location.has_player and self.home == self.location: @@ -787,8 +787,8 @@ class Weapon(TutorialObject): self.location = self.home #------------------------------------------------------------ -# -# Weapon rack - spawns weapons +# +# Weapon rack - spawns weapons # #------------------------------------------------------------ @@ -809,7 +809,7 @@ class CmdGetWeapon(Command): rack_id = self.obj.db.rack_id if eval("self.caller.db.%s" % rack_id): - # we don't allow to take more than one weapon from rack. + # we don't allow to take more than one weapon from rack. self.caller.msg("%s has no more to offer." % self.obj.name) else: dmg, name, aliases, desc, magic = self.obj.randomize_type() @@ -834,8 +834,8 @@ class CmdSetWeaponRack(CmdSet): key = "weaponrack_cmdset" mergemode = "Replace" def at_cmdset_creation(self): - self.add(CmdGetWeapon()) - + self.add(CmdGetWeapon()) + class WeaponRack(TutorialObject): """ This will spawn a new weapon for the player unless the player already has one from this rack. @@ -852,7 +852,7 @@ class WeaponRack(TutorialObject): self.rack_id = "weaponrack_1" self.db.min_dmg = 1.0 self.db.max_dmg = 4.0 - self.db.magic = False + self.db.magic = False def randomize_type(self): """ @@ -867,26 +867,26 @@ class WeaponRack(TutorialObject): name = "Knife" desc = "A rusty kitchen knife. Better than nothing." elif dmg < 2.0: - name = "Rusty dagger" + name = "Rusty dagger" desc = "A double-edged dagger with nicked edge. It has a wooden handle." elif dmg < 3.0: - name = "Sword" + name = "Sword" desc = "A rusty shortsword. It has leather wrapped around the handle." - elif dmg < 4.0: - name = "Club" + elif dmg < 4.0: + name = "Club" desc = "A heavy wooden club with some rusty spikes in it." elif dmg < 5.0: - name = "Ornate Longsword" + name = "Ornate Longsword" aliases.extend(["longsword","ornate"]) desc = "A fine longsword." elif dmg < 6.0: - name = "Runeaxe" + name = "Runeaxe" aliases.extend(["rune","axe"]) desc = "A single-bladed axe, heavy but yet easy to use." elif dmg < 7.0: name = "Broadsword named Thruning" aliases.extend(["thruning","broadsword"]) - desc = "This heavy bladed weapon is marked with the name 'Thruning'. It is very powerful in skilled hands." + desc = "This heavy bladed weapon is marked with the name 'Thruning'. It is very powerful in skilled hands." elif dmg < 8.0: name = "Silver Warhammer" aliases.append("warhammer") @@ -901,8 +901,8 @@ class WeaponRack(TutorialObject): desc = "This massive sword is large as you are tall. Its metal shine with a bluish glow." else: name = "The Hawkblade" - aliases.append("hawkblade") + aliases.append("hawkblade") desc = "White surges of magical power runs up and down this runic blade. The hawks depicted on its hilt almost seems to have a life of their own." if dmg < 9 and magic: - desc += "\nThe metal seems to glow faintly, as if imbued with more power than what is immediately apparent." + desc += "\nThe metal seems to glow faintly, as if imbued with more power than what is immediately apparent." return dmg, name, aliases, desc, magic diff --git a/contrib/tutorial_world/rooms.py b/contrib/tutorial_world/rooms.py index f8abb3f5b9..a66a39886e 100644 --- a/contrib/tutorial_world/rooms.py +++ b/contrib/tutorial_world/rooms.py @@ -365,7 +365,7 @@ class TeleportRoom(TutorialRoom): # passed the puzzle teleport_to = self.db.success_teleport_to # this is a room name - results = search_object(teleport_to, global_search=True) + results = search_object(teleport_to) if not results or len(results) > 1: # we cannot move anywhere since no valid target was found. print "no valid teleport target for %s was found." % teleport_to