Fixed a bug in mob movement that had it ignore its own check for traversal-permission

This commit is contained in:
Griatch 2015-02-22 14:34:35 +01:00
parent 4e11b2b5b5
commit c1243a9d6d
4 changed files with 52 additions and 390 deletions

View file

@ -1026,17 +1026,22 @@ stairs down
# except one which is the one decided by the scene shown by the
# Obelisk last we looked.
#
@dig/tel Blue bird tomb
@dig Blue bird tomb
: tutorial_world.rooms.TeleportRoom
= Tomb with stone bird;bird;blue;stone
#
@desc Blue bird tomb =
The entrance to this tomb is decorated with a very lifelike blue bird.
#
Blue bird tomb
#
@set here/puzzle_value = 0
#
@set here/failure_teleport_to = tut#15
#
@set here/success_teleport_to = tut#16
#
@set here/failure_teleport_to =
@set here/failure_teleport_msg =
The tomb is dark. You fumble your way through it. You think you can
make out a coffin in front of you in the gloom.
@ -1065,17 +1070,25 @@ stairs down
#
@tel tut#14
#
@dig/teleport Tomb of woman on horse
@dig Tomb of woman on horse
: tutorial_world.rooms.TeleportRoom
= Tomb with statue of riding woman;horse;riding;
#
@desc Tomb of woman on horse =
The entrance to this tomb depicts a scene of a strong
warrior woman on a black horse. She shouts and brandishes
a glowing weapon as she charges down a hill towards
some enemy not depicted.
#
Tomb of woman on horse
#
@set here/puzzle_value = 1
#
@set here/failure_teleport_to = tut#15
#
@set here/success_teleport_to = tut#16
#
@set here/failure_teleport_to =
@set here/failure_teleport_msg =
The tomb is dark. You fumble your way through it. You think you can
make out a coffin in front of you in the gloom.
@ -1104,17 +1117,24 @@ stairs down
#
@tel tut#14
#
@dig/teleport Tomb of the crowned queen
@dig Tomb of the crowned queen
: tutorial_world.rooms.TeleportRoom
= Tomb with statue of a crowned queen;crown;queen
#
@desc Tomb of the crowned queen =
The entrance to this tomb shows a beautiful mural of a queen ruling
from her throne, respectful subjects kneeling before her. On her head
is a crown that seems to shine with magical power.
#
Tomb of the crowned queen
#
@set here/puzzle_value = 2
#
@set here/failure_teleport_to = tut#15
#
@set here/success_teleport_to = tut#16
#
@set here/failure_teleport_to =
@set here/failure_teleport_msg =
The tomb is dark. You fumble your way through it. You think you can
make out a coffin in front of you in the gloom.
@ -1143,17 +1163,25 @@ stairs down
#
@tel tut#14
#
@dig/teleport Tomb of the shield
@dig Tomb of the shield
: tutorial_world.rooms.TeleportRoom
= Tomb with shield of arms;shield
#
Tomb of the shield
#
@desc Tomb of the shield =
This tomb shows a warrior woman fighting shadowy creatures from the
top of a hill. Her sword lies broken on the ground before her but she
fights on with her battered shield - the scene depicts her just as she
rams the shield into an enemy in wild desperation.
#
@set here/puzzle_value = 3
#
@set here/failure_teleport_to = tut#15
#
@set here/success_teleport_to = tut#16
#
@set here/failure_teleport_to =
@set here/failure_teleport_msg =
The tomb is dark. You fumble your way through it. You think you can
make out a coffin in front of you in the gloom.
@ -1182,17 +1210,26 @@ stairs down
#
@tel tut#14
#
@dig/teleport Tomb of the hero
@dig Tomb of the hero
: tutorial_world.rooms.TeleportRoom
= Tomb depicting a heroine fighting a monster;knight;hero;monster;beast
#
@desc Tomb of the hero =
The entrance to this tomb shows a mural of an aging woman in a
warrior's outfit. She has white hair yet her sword-arm shows no sign
of weakness and her pose is straight. Children are gathered around her
feet and men and women from all the land come to seek the wisdom and
strength of the legendary hero.
#
Tomb of the hero
#
@set here/puzzle_value = 4
#
@set here/failure_teleport_to = tut#15
#
@set here/success_teleport_to = tut#16
#
@set here/failure_teleport_to =
@set here/failure_teleport_msg =
The tomb is dark. You fumble your way through it. You think you can
make out a coffin in front of you in the gloom.

View file

@ -13,7 +13,6 @@ from evennia import Command, CmdSet
from evennia import logger
from evennia.contrib.tutorial_world import objects as tut_objects
class CmdMobOnOff(Command):
"""
Activates/deactivates Mob
@ -290,7 +289,7 @@ class Mob(tut_objects.TutorialObject):
order to block the mob from moving outside its area while
allowing player-controlled characters to move normally.
"""
if random.random() < 0.01:
if random.random() < 0.01 and self.db.irregular_msgs:
self.location.msg_contents(random.choice(self.db.irregular_msgs))
if self.db.aggressive:
# first check if there are any targets in the room.
@ -303,7 +302,7 @@ class Mob(tut_objects.TutorialObject):
if exi.access(self, "traverse")]
if exits:
# randomly pick an exit
exit = random.choice(self.location.exits)
exit = random.choice(exits)
# move there.
self.move_to(exit.destination)
else:
@ -316,7 +315,7 @@ class Mob(tut_objects.TutorialObject):
scans adjacent rooms for enemies and moves towards them to
attack if possible.
"""
if random.random() < 0.01:
if random.random() < 0.01 and self.db.irregular_msgs:
self.location.msg_contents(random.choice(self.db.irregular_msgs))
if self.db.aggressive:
# first check if there are any targets in the room.
@ -348,7 +347,7 @@ class Mob(tut_objects.TutorialObject):
the mob will bring its weapons to bear on any targets
in the room.
"""
if random.random() < 0.01:
if random.random() < 0.01 and self.db.irregular_msgs:
self.location.msg_contents(random.choice(self.db.irregular_msgs))
# first make sure we have a target
target = self._find_target(self.location)
@ -414,376 +413,3 @@ class Mob(tut_objects.TutorialObject):
# we know it is a valid target.
if self.db.aggressive and not self.ndb.is_attacking:
self.start_attacking()
#
##------------------------------------------------------------
##
## Mob - mobile object
##
## This object utilizes exits and moves about randomly from
## room to room.
##
##------------------------------------------------------------
#
#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)").
# """
# def at_object_creation(self):
# "This is called when the object is first created."
# self.db.tutorial_info = "This is a moving object. It moves randomly from room to room."
#
# 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
# #
# self.db.move_from
# self.location.msg_contents("With a cold breeze, %s drifts in the direction of %s." % (self.key, destination.key))
#
# def announce_move_from(self, destination):
# "Called just before moving"
# self.location.msg_contents("With a cold breeze, %s drifts in the direction of %s." % (self.key, destination.key))
#
# def announce_move_to(self, source_location):
# "Called just after arriving"
# self.location.msg_contents("With a wailing sound, %s appears from the %s." % (self.key, source_location.key))
#
# def update_irregular(self):
# "Called at irregular intervals. Moves the mob."
# if self.roam_mode:
# exits = [ex for ex in self.location.exits
# if ex.access(self, "traverse")]
# 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
# self.db.last_location = self.location
# # execute_cmd() allows the mob to respect exit and
# # exit-command locks, but may pose a problem if there is more
# # than one exit with the same name.
# # - see Enemy example for another way to move
# self.execute_cmd("%s" % exits[random.randint(0, len(exits) - 1)].key)
#
#
#
##------------------------------------------------------------
##
## Enemy - mobile attacking object
##
## 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.
##
## 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
## teleport to another room. Players defeated by the apparition will
## conversely just be teleported to a holding room.
##
##------------------------------------------------------------
#
#class AttackTimer(DefaultScript):
# """
# This script is what makes an eneny "tick".
# """
# def at_script_creation(self):
# "This sets up the script"
# self.key = "AttackTimer"
# self.desc = "Drives an Enemy's combat."
# self.interval = random.randint(2, 3) # how fast the Enemy acts
# self.start_delay = True # wait self.interval before first call
# self.persistent = True
#
# def at_repeat(self):
# "Called every self.interval seconds."
# if self.obj.db.inactive:
# return
# # id(self.ndb.twisted_task)
# if self.obj.db.roam_mode:
# self.obj.roam()
# #return
# elif self.obj.db.battle_mode:
# #print "attack"
# self.obj.attack()
# return
# elif self.obj.db.pursue_mode:
# #print "pursue"
# self.obj.pursue()
# #return
# else:
# #dead mode. Wait for respawn.
# if not self.obj.db.dead_at:
# self.obj.db.dead_at = time.time()
# if (time.time() - self.obj.db.dead_at) > self.obj.db.dead_timer:
# self.obj.reset()
#
#
#class Enemy(Mob):
# """
# This is a ghostly enemy with health (hit points). Their chance to hit,
# damage etc is determined by the weapon they are wielding, same as
# characters.
#
# 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
# pursue - where it follows a player, trying to enter combat again
# dead - passive and invisible until it is respawned
#
# Upon creation, the following attributes describe the enemy's actions
# desc - description
# full_health - integer number > 0
# defeat_location - unique name or #dbref to the location the player is
# taken when defeated. If not given, will remain in room.
# defeat_text - text to show player when they are defeated (just before
# being whisped away to defeat_location)
# defeat_text_room - text to show other players in room when a player
# is defeated
# 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.
#
# """
# 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
# self.db.roam_mode = True
# self.db.battle_mode = False
# self.db.pursue_mode = False
# self.db.dead_mode = False
# # health (change this at creation time)
# self.db.full_health = 20
# self.db.health = 20
# self.db.dead_at = time.time()
# self.db.dead_timer = 100 # how long to stay dead
# # this is used during creation to make sure the mob doesn't move away
# self.db.inactive = True
# # store the last player to hit
# self.db.last_attacker = None
# # where to take defeated enemies
# self.db.defeat_location = "darkcell"
# self.scripts.add(AttackTimer)
#
# def update_irregular(self):
# "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)])
#
# def roam(self):
# "Called by Attack timer. Will move randomly as long as exits are open."
#
# # in this mode, the mob is healed.
# self.db.health = self.db.full_health
# 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
# self.db.pursue_mode = False
# 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.
# new_exits = [ex for ex in exits
# if ex.destination != self.db.last_location]
# if new_exits:
# exits = new_exits
# self.db.last_location = self.location
# # locks should be checked here
# self.move_to(exits[random.randint(0, len(exits) - 1)])
# 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
# the location. If players are defeated, it will whisp them off
# 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]
# if players:
#
# # find a target
# if last_attacker in players:
# # prefer to attack the player last attacking.
# target = last_attacker
# else:
# # otherwise attack a random player in location
# target = players[random.randint(0, len(players) - 1)]
#
# # try to use the weapon in hand
# attack_cmds = ("thrust", "pierce", "stab", "slash", "chop")
# cmd = attack_cmds[random.randint(0, len(attack_cmds) - 1)]
# self.execute_cmd("%s %s" % (cmd, target))
#
# # 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)
# tstring = self.db.defeat_text
# if not tstring:
# tstring = "You feel your conciousness slip away ... you fall to the ground as "
# tstring += "the misty apparition envelopes you ...\n The world goes black ...\n"
# target.msg(tstring)
# ostring = self.db.defeat_text_room
# if tloc:
# if not ostring:
# ostring = "\n%s envelops the fallen ... and then their body is suddenly gone!" % self.key
# # silently move the player to defeat location
# # (we need to call hook manually)
# target.location = tloc[0]
# tloc[0].at_object_receive(target, self.location)
# elif not ostring:
# ostring = "%s falls to the ground!" % target.key
# self.location.msg_contents(ostring, exclude=[target])
# # Pursue any stragglers after the battle
# self.battle_mode = False
# self.roam_mode = False
# self.pursue_mode = True
# 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.
# """
# last_attacker = self.db.last_attacker
# players = [obj for obj in self.location.contents if utils.inherits_from(obj, BASE_CHARACTER_TYPECLASS) and not obj.is_superuser]
# if players:
# # we found players in the room. Maybe we caught up with some,
# # or some walked in on us before we had time to pursue them.
# # Switch to battle mode.
# self.battle_mode = True
# self.roam_mode = False
# self.pursue_mode = False
# else:
# # find all possible destinations.
# destinations = [ex.destination for ex in self.location.exits
# if ex.access(self, "traverse")]
# # find all players in the possible destinations. OBS-we cannot
# # just use the player's current position to move the Enemy; this
# # might have changed when the move is performed, causing the enemy
# # to teleport out of bounds.
# 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
# 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.
# key = players.keys()[random.randint(0, len(players) - 1)]
# self.move_to(players[key])
# else:
# # 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.
# """
#
# 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.scripts.add(AttackTimer)
#
# if not weapon.db.magic:
# # In the tutorial, the enemy is a ghostly apparition, so
# # only magical weapons can harm it.
# string = self.db.weapon_ineffective_text
# if not string:
# string = "Your weapon just passes through your enemy, causing no effect!"
# attacker.msg(string)
# return
# else:
# # an actual hit
# health = float(self.db.health)
# health -= damage
# self.db.health = health
# 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 += "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."
# attacker.msg(string)
# string = self.db.win_text_room
# if not string:
# string = "After %s's last hit, %s folds in on itself, it seems to fade away into nothingness. " % (attacker.name, 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."
# self.location.msg_contents(string, exclude=[attacker])
#
# # put mob in dead mode and hide it from view.
# # AttackTimer will bring it back later.
# self.db.dead_at = time.time()
# self.db.roam_mode = False
# self.db.pursue_mode = False
# self.db.battle_mode = False
# self.db.dead_mode = True
# self.location = None
# else:
# self.location.msg_contents("%s wails, shudders and writhes." % self.key)
# 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
# string = self.db.respawn_text
# if not string:
# string = "%s fades into existence from out of thin air. It's looking pissed." % self.key
# self.location.msg_contents(string)

View file

@ -540,7 +540,6 @@ def has_player(accessing_obj, accessed_obj, *args, **kwargs):
This is a useful lock for traverse-locking Exits to restrain NPC
mobiles from moving outside their areas.
"""
print "lock:", accessing_obj, accessed_obj, accessing_obj.has_player
return hasattr(accessing_obj, "has_player") and accessing_obj.has_player
def serversetting(accessing_obj, accessed_obj, *args, **kwargs):

View file

@ -87,7 +87,7 @@ class Ticker(object):
"""
for store_key, (obj, args, kwargs) in self.subscriptions.items():
hook_key = yield kwargs.get("_hook_key", "at_tick")
if not obj:
if not obj or not obj.pk:
# object was deleted between calls
self.remove(store_key)
continue