mirror of
https://github.com/evennia/evennia.git
synced 2026-04-17 21:59:06 +02:00
Fixing tutorial world usage of search.
This commit is contained in:
parent
59ccd3eb38
commit
1b0544c261
3 changed files with 227 additions and 227 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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue