mirror of
https://github.com/evennia/evennia.git
synced 2026-04-03 06:27:17 +02:00
Merging mainline changes.
This commit is contained in:
commit
fe54326d5f
10 changed files with 525 additions and 366 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 <object>
|
||||
Usage:
|
||||
climb <object>
|
||||
"""
|
||||
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 <color> <direction>
|
||||
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 <enemy>
|
||||
slash <enemy>
|
||||
parry
|
||||
stab <enemy>
|
||||
slash <enemy>
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
|
||||
|
||||
Room Typeclasses for the TutorialWorld.
|
||||
|
||||
"""
|
||||
|
|
@ -12,11 +12,11 @@ from contrib.tutorial_world.objects import LightSource, TutorialObject
|
|||
|
||||
#------------------------------------------------------------
|
||||
#
|
||||
# Tutorial room - parent room class
|
||||
#
|
||||
# This room is the parent of all rooms in the tutorial.
|
||||
# Tutorial room - parent room class
|
||||
#
|
||||
# This room is the parent of all rooms in the tutorial.
|
||||
# It defines a tutorial command on itself (available to
|
||||
# all who is in a tutorial room).
|
||||
# all who is in a tutorial room).
|
||||
#
|
||||
#------------------------------------------------------------
|
||||
|
||||
|
|
@ -39,9 +39,9 @@ class CmdTutorial(Command):
|
|||
def func(self):
|
||||
"""
|
||||
All we do is to scan the current location for an attribute
|
||||
called `tutorial_info` and display that.
|
||||
called `tutorial_info` and display that.
|
||||
"""
|
||||
|
||||
|
||||
caller = self.caller
|
||||
|
||||
if not self.args:
|
||||
|
|
@ -49,11 +49,11 @@ class CmdTutorial(Command):
|
|||
else:
|
||||
target = caller.search(self.args.strip())
|
||||
if not target:
|
||||
return
|
||||
return
|
||||
helptext = target.db.tutorial_info
|
||||
if helptext:
|
||||
if helptext:
|
||||
caller.msg("{G%s{n" % helptext)
|
||||
else:
|
||||
else:
|
||||
caller.msg("{RSorry, there is no tutorial help available here.{n")
|
||||
|
||||
class TutorialRoomCmdSet(CmdSet):
|
||||
|
|
@ -65,7 +65,7 @@ class TutorialRoomCmdSet(CmdSet):
|
|||
|
||||
class TutorialRoom(Room):
|
||||
"""
|
||||
This is the base room type for all rooms in the tutorial world.
|
||||
This is the base room type for all rooms in the tutorial world.
|
||||
It defines a cmdset on itself for reading tutorial info about the location.
|
||||
"""
|
||||
def at_object_creation(self):
|
||||
|
|
@ -82,14 +82,14 @@ class TutorialRoom(Room):
|
|||
#------------------------------------------------------------
|
||||
#
|
||||
# Weather room - scripted room
|
||||
#
|
||||
# The weather room is called by a script at
|
||||
#
|
||||
# The weather room is called by a script at
|
||||
# irregular intervals. The script is generally useful
|
||||
# and so is split out into tutorialworld.scripts.
|
||||
#
|
||||
#------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
class WeatherRoom(TutorialRoom):
|
||||
"""
|
||||
This should probably better be called a rainy room...
|
||||
|
|
@ -99,7 +99,7 @@ class WeatherRoom(TutorialRoom):
|
|||
inherit from this.
|
||||
|
||||
"""
|
||||
def at_object_creation(self):
|
||||
def at_object_creation(self):
|
||||
"Called when object is first created."
|
||||
super(WeatherRoom, self).at_object_creation()
|
||||
|
||||
|
|
@ -133,7 +133,7 @@ class WeatherRoom(TutorialRoom):
|
|||
#
|
||||
# Dark Room - a scripted room
|
||||
#
|
||||
# This room limits the movemenets of its denizens unless they carry a and active
|
||||
# This room limits the movemenets of its denizens unless they carry a and active
|
||||
# LightSource object (LightSource is defined in tutorialworld.objects.LightSource)
|
||||
#
|
||||
#-----------------------------------------------------------------------------------
|
||||
|
|
@ -141,7 +141,7 @@ class WeatherRoom(TutorialRoom):
|
|||
class CmdLookDark(Command):
|
||||
"""
|
||||
Look around in darkness
|
||||
|
||||
|
||||
Usage:
|
||||
look
|
||||
|
||||
|
|
@ -155,7 +155,7 @@ class CmdLookDark(Command):
|
|||
def func(self):
|
||||
"Implement the command."
|
||||
caller = self.caller
|
||||
# we don't have light, grasp around blindly.
|
||||
# we don't have light, grasp around blindly.
|
||||
messages = ("It's pitch black. You fumble around but cannot find anything.",
|
||||
"You don't see a thing. You feel around, managing to bump your fingers hard against something. Ouch!",
|
||||
"You don't see a thing! Blindly grasping the air around you, you find nothing.",
|
||||
|
|
@ -163,25 +163,25 @@ class CmdLookDark(Command):
|
|||
"You are completely blind. For a moment you think you hear someone breathing nearby ... \n ... surely you must be mistaken.",
|
||||
"Blind, you think you find some sort of object on the ground, but it turns out to be just a stone.",
|
||||
"Blind, you bump into a wall. The wall seems to be covered with some sort of vegetation, but its too damp to burn.",
|
||||
"You can't see anything, but the air is damp. It feels like you are far underground.")
|
||||
"You can't see anything, but the air is damp. It feels like you are far underground.")
|
||||
irand = random.randint(0, 10)
|
||||
if irand < len(messages):
|
||||
caller.msg(messages[irand])
|
||||
else:
|
||||
# check so we don't already carry a lightsource.
|
||||
# check so we don't already carry a 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.
|
||||
return
|
||||
#if we are lucky, we find the light source.
|
||||
lightsources = [obj for obj in self.obj.contents if utils.inherits_from(obj, LightSource)]
|
||||
if lightsources:
|
||||
lightsource = lightsources[0]
|
||||
else:
|
||||
# create the light source from scratch.
|
||||
lightsource = create_object(LightSource, key="torch")
|
||||
lightsource.location = caller
|
||||
lightsource = create_object(LightSource, key="torch")
|
||||
lightsource.location = caller
|
||||
string = "Your fingers bump against a piece of wood in a corner. Smelling it you sense the faint smell of tar. A {c%s{n!"
|
||||
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 % lightsource.key)
|
||||
|
|
@ -199,7 +199,7 @@ class CmdDarkHelp(Command):
|
|||
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):
|
||||
|
|
@ -222,37 +222,37 @@ class DarkCmdSet(CmdSet):
|
|||
self.add(CmdDarkNoMatch())
|
||||
self.add(CmdSay)
|
||||
#
|
||||
# Darkness room two-state system
|
||||
# Darkness room two-state system
|
||||
#
|
||||
|
||||
class DarkState(Script):
|
||||
"""
|
||||
The darkness state is a script that keeps tabs on when
|
||||
a player in the room carries an active light source. It places
|
||||
The darkness state is a script that keeps tabs on when
|
||||
a player in the room carries an active light source. It places
|
||||
a new, very restrictive cmdset (DarkCmdSet) on all the players
|
||||
in the room whenever there is no light in it. Upon turning on
|
||||
a light, the state switches off and moves to LightState.
|
||||
in the room whenever there is no light in it. Upon turning on
|
||||
a light, the state switches off and moves to LightState.
|
||||
"""
|
||||
def at_script_creation(self):
|
||||
"This setups the script"
|
||||
self.key = "tutorial_darkness_state"
|
||||
self.desc = "A dark room"
|
||||
self.persistent = True
|
||||
def at_start(self):
|
||||
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]:
|
||||
if char.is_superuser:
|
||||
char.msg("You are Superuser, so you are not affected by the dark state.")
|
||||
else:
|
||||
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."
|
||||
"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]:
|
||||
char.cmdset.delete(DarkCmdSet)
|
||||
for char in [char for char in self.obj.contents if char.has_player]:
|
||||
char.cmdset.delete(DarkCmdSet)
|
||||
self.obj.db.is_dark = False
|
||||
self.obj.scripts.add(LightState)
|
||||
|
||||
|
|
@ -264,29 +264,29 @@ class LightState(Script):
|
|||
"Called when script is first created."
|
||||
self.key = "tutorial_light_state"
|
||||
self.desc = "A room lit up"
|
||||
self.persistent = True
|
||||
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."
|
||||
"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
|
||||
objects entering. The script is responsible for making sure it is
|
||||
objects entering. The script is responsible for making sure it is
|
||||
valid (that is, that there is no light source shining in the room).
|
||||
"""
|
||||
def is_lit(self):
|
||||
"""
|
||||
Helper method to check if the room is lit up. It checks all
|
||||
characters in room to see if they carry an active object of
|
||||
type LightSource.
|
||||
"""
|
||||
return any([any([True for obj in char.contents
|
||||
if utils.inherits_from(obj, LightSource) and obj.is_active])
|
||||
characters in room to see if they carry an active object of
|
||||
type LightSource.
|
||||
"""
|
||||
return any([any([True for obj in char.contents
|
||||
if utils.inherits_from(obj, LightSource) and obj.is_active])
|
||||
for char in self.contents if char.has_player])
|
||||
|
||||
def at_object_creation(self):
|
||||
|
|
@ -309,34 +309,34 @@ class DarkRoom(TutorialRoom):
|
|||
health = character.db.health_max
|
||||
if not health:
|
||||
health = 20
|
||||
character.db.health = health
|
||||
character.db.health = health
|
||||
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
|
||||
self.scripts.validate()
|
||||
|
||||
|
||||
#------------------------------------------------------------
|
||||
#
|
||||
# Teleport room - puzzle room
|
||||
# Teleport room - puzzle room
|
||||
#
|
||||
# This is a sort of puzzle room that requires a certain
|
||||
# attribute on the entering character to be the same as
|
||||
# an attribute of the room. If not, the character will
|
||||
# be teleported away to a target location. This is used
|
||||
# This is a sort of puzzle room that requires a certain
|
||||
# attribute on the entering character to be the same as
|
||||
# an attribute of the room. If not, the character will
|
||||
# be teleported away to a target location. This is used
|
||||
# by the Obelisk - grave chamber puzzle, where one must
|
||||
# have looked at the obelisk to get an attribute set on
|
||||
# oneself, and then pick the grave chamber with the
|
||||
# oneself, and then pick the grave chamber with the
|
||||
# matching imagery for this attribute.
|
||||
#
|
||||
#------------------------------------------------------------
|
||||
|
||||
class TeleportRoom(TutorialRoom):
|
||||
"""
|
||||
Teleporter - puzzle room.
|
||||
Teleporter - puzzle room.
|
||||
|
||||
Important attributes (set at creation):
|
||||
Important attributes (set at creation):
|
||||
puzzle_key - which attr to look for on character
|
||||
puzzle_value - what char.db.puzzle_key must be set to
|
||||
teleport_to - where to teleport to in case of failure to match
|
||||
|
|
@ -347,7 +347,7 @@ 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.
|
||||
# the target of the success 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"
|
||||
|
|
@ -355,33 +355,33 @@ class TeleportRoom(TutorialRoom):
|
|||
def at_object_receive(self, character, source_location):
|
||||
"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.
|
||||
# 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
|
||||
# we didn't pass the puzzle. See if we can teleport.
|
||||
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, 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.
|
||||
# we cannot move anywhere since no valid target was found.
|
||||
print "no valid teleport target for %s was found." % teleport_to
|
||||
return
|
||||
return
|
||||
if character.player.is_superuser:
|
||||
# superusers don't get teleported
|
||||
# superusers don't get teleported
|
||||
character.msg("Superuser block: You would have been teleported to %s." % results[0])
|
||||
return
|
||||
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)
|
||||
|
||||
#------------------------------------------------------------
|
||||
#
|
||||
# Bridge - unique room
|
||||
# Bridge - unique room
|
||||
#
|
||||
# Defines a special west-eastward "bridge"-room, a large room it takes
|
||||
# several steps to cross. It is complete with custom commands and a
|
||||
|
|
@ -389,10 +389,10 @@ class TeleportRoom(TutorialRoom):
|
|||
# instead the exiting are handled by custom commands set on the player
|
||||
# upon first entering the room.
|
||||
#
|
||||
# Since one can enter the bridge room from both ends, it is
|
||||
# Since one can enter the bridge room from both ends, it is
|
||||
# divided into five steps:
|
||||
# westroom <- 0 1 2 3 4 -> eastroom
|
||||
#
|
||||
#
|
||||
#------------------------------------------------------------
|
||||
|
||||
|
||||
|
|
@ -404,25 +404,25 @@ class CmdEast(Command):
|
|||
aliases = ["e"]
|
||||
locks = "cmd:all()"
|
||||
help_category = "TutorialWorld"
|
||||
|
||||
|
||||
def func(self):
|
||||
"move forward"
|
||||
caller = self.caller
|
||||
|
||||
|
||||
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])
|
||||
else:
|
||||
caller.msg("No east exit was found for this room. Contact an admin.")
|
||||
return
|
||||
return
|
||||
caller.db.tutorial_bridge_position = bridge_step
|
||||
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):
|
||||
"""
|
||||
|
|
@ -432,11 +432,11 @@ class CmdWest(Command):
|
|||
aliases = ["w"]
|
||||
locks = "cmd:all()"
|
||||
help_category = "TutorialWorld"
|
||||
|
||||
|
||||
def func(self):
|
||||
"move forward"
|
||||
caller = self.caller
|
||||
|
||||
|
||||
bridge_step = max(-1, caller.db.tutorial_bridge_position - 1)
|
||||
|
||||
if bridge_step < 0:
|
||||
|
|
@ -446,14 +446,14 @@ class CmdWest(Command):
|
|||
caller.move_to(wexit[0])
|
||||
else:
|
||||
caller.msg("No west exit was found for this room. Contact an admin.")
|
||||
return
|
||||
return
|
||||
caller.db.tutorial_bridge_position = bridge_step
|
||||
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.
|
||||
looks around at the bridge.
|
||||
"""
|
||||
key = 'look'
|
||||
aliases = ["l"]
|
||||
|
|
@ -463,14 +463,14 @@ class CmdLookBridge(Command):
|
|||
def func(self):
|
||||
"Looking around, including a chance to fall."
|
||||
bridge_position = self.caller.db.tutorial_bridge_position
|
||||
|
||||
|
||||
|
||||
|
||||
messages =("You are standing {wvery close to the the bridge's western foundation{n. If you go west you will be back on solid ground ...",
|
||||
"The bridge slopes precariously where it extends eastwards towards the lowest point - the center point of the hang bridge.",
|
||||
"You are {whalfways{n out on the unstable bridge.",
|
||||
"The bridge slopes precariously where it extends westwards towards the lowest point - the center point of the hang bridge.",
|
||||
"You are standing {wvery close to the bridge's eastern foundation{n. If you go east you will be back on solid ground ...")
|
||||
moods = ("The bridge sways in the wind.", "The hanging bridge creaks dangerously.",
|
||||
moods = ("The bridge sways in the wind.", "The hanging bridge creaks dangerously.",
|
||||
"You clasp the ropes firmly as the bridge sways and creaks under you.",
|
||||
"From the castle you hear a distant howling sound, like that of a large dog or other beast.",
|
||||
"The bridge creaks under your feet. Those planks does not seem very sturdy.",
|
||||
|
|
@ -481,27 +481,27 @@ class CmdLookBridge(Command):
|
|||
"The section of rope you hold onto crumble in your hands, parts of it breaking apart. You sway trying to regain balance.")
|
||||
message = "{c%s{n\n" % self.obj.key + messages[bridge_position] + "\n" + moods[random.randint(0, len(moods) - 1)]
|
||||
chars = [obj for obj in self.obj.contents if obj != self.caller and obj.has_player]
|
||||
if chars:
|
||||
if chars:
|
||||
message += "\n You see: %s" % ", ".join("{c%s{n" % char.key for char in chars)
|
||||
|
||||
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.
|
||||
# we fall on 5% of the times.
|
||||
fexit = search_object(self.obj.db.fall_exit)
|
||||
if fexit:
|
||||
if fexit:
|
||||
string = "\n Suddenly the plank you stand on gives way under your feet! You fall!"
|
||||
string += "\n You try to grab hold of an adjoining plank, but all you manage to do is to "
|
||||
string += "divert your fall westwards, towards the cliff face. This is going to hurt ... "
|
||||
string += "\n ... The world goes dark ...\n"
|
||||
# note that we move silently so as to not call look hooks (this is a little trick to leave
|
||||
string += "\n ... The world goes dark ...\n"
|
||||
# note that we move silently so as to not call look hooks (this is a little trick to leave
|
||||
# the player with the "world goes dark ..." message, giving them ample time to read it. They
|
||||
# have to manually call look to find out their new location). Thus we also call the
|
||||
# at_object_leave hook manually (otherwise this is done by move_to()).
|
||||
# have to manually call look to find out their new location). Thus we also call the
|
||||
# at_object_leave hook manually (otherwise this is done by move_to()).
|
||||
self.caller.msg("{r%s{n" % string)
|
||||
self.obj.at_object_leave(self.caller, fexit)
|
||||
self.caller.location = fexit[0] # stealth move, without any other hook calls.
|
||||
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
|
||||
|
|
@ -522,7 +522,7 @@ class CmdBridgeHelp(Command):
|
|||
self.caller.msg(string)
|
||||
|
||||
class BridgeCmdSet(CmdSet):
|
||||
"This groups the bridge commands. We will store it on the room."
|
||||
"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):
|
||||
|
|
@ -531,14 +531,14 @@ class BridgeCmdSet(CmdSet):
|
|||
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
|
||||
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
|
||||
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.
|
||||
|
||||
We divide the bridge into steps:
|
||||
|
|
@ -547,7 +547,7 @@ class BridgeRoom(TutorialRoom):
|
|||
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.
|
||||
special move commands will increase/decrease the counter until the bridge is crossed.
|
||||
|
||||
"""
|
||||
def at_object_creation(self):
|
||||
|
|
@ -557,7 +557,7 @@ class BridgeRoom(TutorialRoom):
|
|||
# at irregular intervals, this will call self.update_irregular()
|
||||
self.scripts.add(tut_scripts.IrregularEvent)
|
||||
# this identifies the exits from the room (should be the command
|
||||
# needed to leave through that exit). These are defaults, but you
|
||||
# needed to leave through that exit). These are defaults, but you
|
||||
# could of course also change them after the room has been created.
|
||||
self.db.west_exit = "cliff"
|
||||
self.db.east_exit = "gate"
|
||||
|
|
@ -583,12 +583,12 @@ class BridgeRoom(TutorialRoom):
|
|||
"Some sort of large bird sweeps by overhead, giving off an eery screech. Soon it has disappeared in the gloom.",
|
||||
"The bridge sways from side to side in the wind.")
|
||||
self.msg_contents("{w%s{n" % strings[random.randint(0, 7)])
|
||||
|
||||
|
||||
def at_object_receive(self, character, source_location):
|
||||
"""
|
||||
This hook is called by the engine whenever the player is moved
|
||||
into this room.
|
||||
"""
|
||||
"""
|
||||
if character.has_player:
|
||||
# we only run this if the entered object is indeed a player object.
|
||||
# check so our east/west exits are correctly defined.
|
||||
|
|
@ -598,8 +598,8 @@ class BridgeRoom(TutorialRoom):
|
|||
if not wexit or not eexit or not fexit:
|
||||
character.msg("The bridge's exits are not properly configured. Contact an admin. Forcing west-end placement.")
|
||||
character.db.tutorial_bridge_position = 0
|
||||
return
|
||||
if source_location == eexit[0]:
|
||||
return
|
||||
if source_location == eexit[0]:
|
||||
character.db.tutorial_bridge_position = 4
|
||||
else:
|
||||
character.db.tutorial_bridge_position = 0
|
||||
|
|
@ -618,13 +618,13 @@ 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.
|
||||
# that is needed for the tutorial.
|
||||
#
|
||||
#------------------------------------------------------------
|
||||
|
||||
class IntroRoom(TutorialRoom):
|
||||
"""
|
||||
Intro room
|
||||
Intro room
|
||||
|
||||
properties to customize:
|
||||
char_health - integer > 0 (default 20)
|
||||
|
|
@ -634,15 +634,15 @@ class IntroRoom(TutorialRoom):
|
|||
"""
|
||||
Assign properties on characters
|
||||
"""
|
||||
|
||||
# setup
|
||||
|
||||
# setup
|
||||
health = self.db.char_health
|
||||
if not health:
|
||||
health = 20
|
||||
|
||||
if character.has_player:
|
||||
character.db.health = health
|
||||
character.db.health_max = health
|
||||
character.db.health = health
|
||||
character.db.health_max = health
|
||||
|
||||
if character.is_superuser:
|
||||
string = "-"*78
|
||||
|
|
@ -655,7 +655,7 @@ class IntroRoom(TutorialRoom):
|
|||
#------------------------------------------------------------
|
||||
#
|
||||
# Outro room - unique room
|
||||
#
|
||||
#
|
||||
# Cleans up the character from all tutorial-related properties.
|
||||
#
|
||||
#------------------------------------------------------------
|
||||
|
|
@ -664,16 +664,16 @@ class OutroRoom(TutorialRoom):
|
|||
"""
|
||||
Outro room.
|
||||
"""
|
||||
|
||||
|
||||
def at_object_receive(self, character, source_location):
|
||||
"""
|
||||
Do cleanup.
|
||||
"""
|
||||
"""
|
||||
if character.has_player:
|
||||
del character.db.health
|
||||
del character.db.health
|
||||
del character.db.has_climbed
|
||||
del character.db.puzzle_clue
|
||||
del character.db.combat_parry_mode
|
||||
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)]:
|
||||
tut_obj.reset()
|
||||
|
|
|
|||
1
ev.py
1
ev.py
|
|
@ -236,3 +236,4 @@ class SystemCmds(object):
|
|||
del cmdhandler
|
||||
syscmdkeys = SystemCmds()
|
||||
del SystemCmds
|
||||
|
||||
|
|
|
|||
|
|
@ -65,15 +65,15 @@ for inum in range(len(commands)):
|
|||
print "leaving run ..."
|
||||
"""
|
||||
_PROCPOOL_BATCHCODE_SOURCE = """
|
||||
from src.commands.default.batchprocess import batch_cmd_exec, step_pointer, BatchSafeCmdSet
|
||||
caller.ndb.batch_stack = commands
|
||||
from src.commands.default.batchprocess import batch_code_exec, step_pointer, BatchSafeCmdSet
|
||||
caller.ndb.batch_stack = codes
|
||||
caller.ndb.batch_stackptr = 0
|
||||
caller.ndb.batch_batchmode = "batch_commands"
|
||||
caller.ndb.batch_batchmode = "batch_code"
|
||||
caller.cmdset.add(BatchSafeCmdSet)
|
||||
for inum in range(len(commands)):
|
||||
print "command:", inum
|
||||
for inum in range(len(codes)):
|
||||
print "code:", inum
|
||||
caller.cmdset.add(BatchSafeCmdSet)
|
||||
if not batch_cmd_exec(caller):
|
||||
if not batch_code_exec(caller):
|
||||
break
|
||||
step_pointer(caller, 1)
|
||||
print "leaving run ..."
|
||||
|
|
@ -272,7 +272,14 @@ class CmdBatchCommands(MuxCommand):
|
|||
else:
|
||||
caller.msg("Running Batch-command processor - Automatic mode for %s (this might take some time) ..." % python_path)
|
||||
|
||||
if False:#TODO - need to add a procpool solution. settings.PROCPOOL_ENABLED:
|
||||
procpool = False
|
||||
if "PythonProcPool" in utils.server_services():
|
||||
if utils.uses_database("sqlite3"):
|
||||
caller.msg("Batchprocessor disabled ProcPool under SQLite3.")
|
||||
else:
|
||||
procpool=True
|
||||
|
||||
if procpool:
|
||||
# run in parallel process
|
||||
def callback(r):
|
||||
caller.msg(" {GBatchfile '%s' applied." % python_path)
|
||||
|
|
@ -366,7 +373,13 @@ class CmdBatchCode(MuxCommand):
|
|||
else:
|
||||
caller.msg("Running Batch-code processor - Automatic mode for %s ..." % python_path)
|
||||
|
||||
if False: #TODO Add procpool solution. settings.PROCPOOL_ENABLED:
|
||||
procpool = False
|
||||
if "PythonProcPool" in utils.server_services():
|
||||
if utils.uses_database("sqlite3"):
|
||||
caller.msg("Batchprocessor disabled ProcPool under SQLite3.")
|
||||
else:
|
||||
procpool=True
|
||||
if procpool:
|
||||
# run in parallel process
|
||||
def callback(r):
|
||||
caller.msg(" {GBatchfile '%s' applied." % python_path)
|
||||
|
|
@ -374,10 +387,10 @@ class CmdBatchCode(MuxCommand):
|
|||
def errback(e):
|
||||
caller.msg(" {RError from processor: '%s'" % e)
|
||||
purge_processor(caller)
|
||||
utils.run_async(_PROCPOOL_BATCHCODE_SOURCE, commands=commands, caller=caller, at_return=callback, at_err=errback)
|
||||
utils.run_async(_PROCPOOL_BATCHCODE_SOURCE, codes=codes, caller=caller, at_return=callback, at_err=errback)
|
||||
else:
|
||||
# un in-process (will block)
|
||||
for inum in range(len(commands)):
|
||||
for inum in range(len(codes)):
|
||||
# loop through the batch file
|
||||
if not batch_cmd_exec(caller):
|
||||
return
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ class CmdSetObjAlias(MuxCommand):
|
|||
objname = self.lhs
|
||||
|
||||
# Find the object to receive aliases
|
||||
obj = caller.search(objname, global_search=True)
|
||||
obj = caller.search(objname)
|
||||
if not obj:
|
||||
return
|
||||
if self.rhs == None:
|
||||
|
|
@ -1232,7 +1232,7 @@ class CmdSetAttribute(ObjManipCommand):
|
|||
# Use literal_eval to parse python structure exactly.
|
||||
try:
|
||||
return _LITERAL_EVAL(strobj)
|
||||
except ValueError:
|
||||
except (SyntaxError, ValueError):
|
||||
# treat as string
|
||||
string = "{RNote: Value was converted to string. If you don't want this, "
|
||||
string += "use proper Python syntax, like enclosing strings in quotes.{n"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
"""
|
||||
Custom manager for Objects.
|
||||
"""
|
||||
try: import cPickle as pickle
|
||||
except ImportError: import pickle
|
||||
from django.db.models import Q
|
||||
from django.conf import settings
|
||||
#from django.contrib.auth.models import User
|
||||
|
|
@ -8,10 +10,11 @@ from django.db.models.fields import exceptions
|
|||
from src.typeclasses.managers import TypedObjectManager
|
||||
from src.typeclasses.managers import returns_typeclass, returns_typeclass_list
|
||||
from src.utils import utils
|
||||
from src.utils.utils import to_unicode, make_iter, string_partial_matching
|
||||
from src.utils.utils import to_unicode, make_iter, string_partial_matching, to_str
|
||||
|
||||
__all__ = ("ObjectManager",)
|
||||
_GA = object.__getattribute__
|
||||
_DUMPS = lambda inp: to_unicode(pickle.dumps(inp))
|
||||
|
||||
# Try to use a custom way to parse id-tagged multimatches.
|
||||
|
||||
|
|
@ -126,8 +129,13 @@ class ObjectManager(TypedObjectManager):
|
|||
not make sense to offer an "exact" type matching for this.
|
||||
"""
|
||||
cand_restriction = candidates and Q(db_obj__pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q()
|
||||
attrs= self.model.objattribute_set.related.model.objects.select_related("db_obj").filter(cand_restriction & Q(db_key=attribute_name))
|
||||
return [attr.db_obj for attr in attrs if attribute_value == attr.value]
|
||||
if type(attribute_value) in (basestring, int, float):
|
||||
# simple attribute_value - do direct lookup
|
||||
return self.model.objattribute_set.related.model.objects.select_related("db_obj").filter(cand_restriction & Q(db_key=attribute_name) & Q(db_value=_DUMPS(("simple", attribute_value))))
|
||||
else:
|
||||
# go via attribute conversion
|
||||
attrs= self.model.objattribute_set.related.model.objects.select_related("db_obj").filter(cand_restriction & Q(db_key=attribute_name))
|
||||
return [attr.db_obj for attr in attrs if attribute_value == attr.value]
|
||||
|
||||
@returns_typeclass_list
|
||||
def get_objs_with_db_property(self, property_name, candidates=None):
|
||||
|
|
@ -137,7 +145,7 @@ class ObjectManager(TypedObjectManager):
|
|||
candidates - list of candidate objects to search
|
||||
"""
|
||||
property_name = "db_%s" % property_name.lstrip('db_')
|
||||
cand_restriction = candidates and Q(pk__in=[_GA(obj, "in") for obj in make_iter(candidates) if obj]) or Q()
|
||||
cand_restriction = candidates and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q()
|
||||
try:
|
||||
return self.filter(cand_restriction).exclude(Q(property_name=None))
|
||||
except exceptions.FieldError:
|
||||
|
|
@ -151,7 +159,7 @@ class ObjectManager(TypedObjectManager):
|
|||
if isinstance(property_value, basestring):
|
||||
property_value = to_unicode(property_value)
|
||||
property_name = "db_%s" % property_name.lstrip('db_')
|
||||
cand_restriction = candidates and Q(pk__in=[_GA(obj, "in") for obj in make_iter(candidates) if obj]) or Q()
|
||||
cand_restriction = candidates and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q()
|
||||
try:
|
||||
return self.filter(cand_restriction & Q(property_name=property_value))
|
||||
except exceptions.FieldError:
|
||||
|
|
@ -178,7 +186,7 @@ class ObjectManager(TypedObjectManager):
|
|||
candidates_id = [_GA(obj, "id") for obj in make_iter(candidates) if obj]
|
||||
cand_restriction = candidates and Q(pk__in=candidates_id) or Q()
|
||||
if exact:
|
||||
return self.filter(cand_restriction & (Q(db_key__iexact=ostring) | Q(alias__db_key__iexact=ostring)))
|
||||
return self.filter(cand_restriction & (Q(db_key__iexact=ostring) | Q(alias__db_key__iexact=ostring))).distinct()
|
||||
else:
|
||||
if candidates:
|
||||
# fuzzy matching - only check the candidates
|
||||
|
|
@ -196,7 +204,7 @@ class ObjectManager(TypedObjectManager):
|
|||
return []
|
||||
else:
|
||||
# fuzzy matching - first check with keys, then with aliases
|
||||
key_candidates = self.filter(Q(db_key__istartswith=ostring) | Q(alias__db_key__istartswith=ostring))
|
||||
key_candidates = self.filter(Q(db_key__istartswith=ostring) | Q(alias__db_key__istartswith=ostring)).distinct()
|
||||
key_strings = key_candidates.values_list("db_key", flat=True)
|
||||
matches = string_partial_matching(key_candidates, ostring, reg_index=False)
|
||||
if matches:
|
||||
|
|
@ -209,7 +217,6 @@ class ObjectManager(TypedObjectManager):
|
|||
|
||||
@returns_typeclass_list
|
||||
def object_search(self, ostring, caller=None,
|
||||
global_search=False,
|
||||
attribute_name=None,
|
||||
candidates=None,
|
||||
exact=True):
|
||||
|
|
@ -241,16 +248,16 @@ class ObjectManager(TypedObjectManager):
|
|||
"""
|
||||
def _searcher(ostring, exact=False):
|
||||
"Helper method for searching objects"
|
||||
if ostring.startswith("*"):
|
||||
# Player search - try to find obj by its player's name
|
||||
player_match = self.get_object_with_player(ostring, candidates=candidates)
|
||||
if player_match is not None:
|
||||
return [player_match]
|
||||
if attribute_name:
|
||||
# attribute/property search (always exact).
|
||||
matches = self.get_objs_with_db_property_value(attribute_name, ostring, candidates=candidates)
|
||||
if not matches:
|
||||
return self.get_objs_with_attr_value(attribute_name, ostring, candidates=candidates)
|
||||
if ostring.startswith("*"):
|
||||
# Player search - try to find obj by its player's name
|
||||
player_match = self.get_object_with_player(ostring, candidates=candidates)
|
||||
if player_match is not None:
|
||||
return [player_match]
|
||||
else:
|
||||
# normal key/alias search
|
||||
return self.get_objs_with_key_or_alias(ostring, exact=exact, candidates=candidates)
|
||||
|
|
|
|||
109
src/objects/migrations/0012_index_objattr_values.py
Normal file
109
src/objects/migrations/0012_index_objattr_values.py
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding index on 'ObjAttribute', fields ['db_value']
|
||||
db.create_index('objects_objattribute', ['db_value'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Removing index on 'ObjAttribute', fields ['db_value']
|
||||
db.delete_index('objects_objattribute', ['db_value'])
|
||||
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'objects.alias': {
|
||||
'Meta': {'object_name': 'Alias'},
|
||||
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'objects.objattribute': {
|
||||
'Meta': {'object_name': 'ObjAttribute'},
|
||||
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']"}),
|
||||
'db_value': ('django.db.models.fields.TextField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'objects.objectdb': {
|
||||
'Meta': {'object_name': 'ObjectDB'},
|
||||
'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'db_destination': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'destinations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||
'db_home': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'homes_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'db_location': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locations_set'", 'null': 'True', 'to': "orm['objects.ObjectDB']"}),
|
||||
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'db_player': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['players.PlayerDB']", 'null': 'True', 'blank': 'True'}),
|
||||
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'objects.objectnick': {
|
||||
'Meta': {'unique_together': "(('db_nick', 'db_type', 'db_obj'),)", 'object_name': 'ObjectNick'},
|
||||
'db_nick': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']"}),
|
||||
'db_real': ('django.db.models.fields.TextField', [], {}),
|
||||
'db_type': ('django.db.models.fields.CharField', [], {'default': "'inputline'", 'max_length': '16', 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'players.playerdb': {
|
||||
'Meta': {'object_name': 'PlayerDB'},
|
||||
'db_cmdset_storage': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
|
||||
'db_date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'db_is_connected': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'db_key': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'db_lock_storage': ('django.db.models.fields.CharField', [], {'max_length': '512', 'blank': 'True'}),
|
||||
'db_obj': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['objects.ObjectDB']", 'null': 'True', 'blank': 'True'}),
|
||||
'db_permissions': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'db_typeclass_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['objects']
|
||||
|
|
@ -268,7 +268,7 @@ class Attribute(SharedMemoryModel):
|
|||
|
||||
db_key = models.CharField('key', max_length=255, db_index=True)
|
||||
# access through the value property
|
||||
db_value = models.TextField('value', blank=True, null=True)
|
||||
db_value = models.TextField('value', blank=True, null=True, db_index=True)
|
||||
# Lock storage
|
||||
db_lock_storage = models.CharField('locks', max_length=512, blank=True)
|
||||
# references the object the attribute is linked to (this is set
|
||||
|
|
|
|||
|
|
@ -461,6 +461,35 @@ def format_table(table, extra_space=1):
|
|||
for icol, col in enumerate(table)])
|
||||
return ftable
|
||||
|
||||
def server_services():
|
||||
"""
|
||||
Lists all services active on the Server. Observe that
|
||||
since services are launced in memory, this function will
|
||||
only return any results if called from inside the game.
|
||||
"""
|
||||
from src.server.sessionhandler import SESSIONS
|
||||
if hasattr(SESSIONS, "server") and hasattr(SESSIONS.server, "services"):
|
||||
server = SESSIONS.server.services.namedServices
|
||||
else:
|
||||
print "This function must be called from inside the evennia process."
|
||||
server = {}
|
||||
del SESSIONS
|
||||
return server
|
||||
|
||||
def uses_database(name="sqlite3"):
|
||||
"""
|
||||
Checks if the game is currently using a given database. This is a
|
||||
shortcut to having to use the full backend name
|
||||
|
||||
name - one of 'sqlite3', 'mysql', 'postgresql_psycopg2' or 'oracle'
|
||||
"""
|
||||
try:
|
||||
engine = settings.DATABASES["default"]["ENGINE"]
|
||||
except KeyError:
|
||||
engine = settings.DATABASE_ENGINE
|
||||
return engine == "django.db.backends.%s" % name
|
||||
|
||||
|
||||
|
||||
_FROM_MODEL_MAP = None
|
||||
_TO_DBOBJ = lambda o: (hasattr(o, "dbobj") and o.dbobj) or o
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue