New functions + Change install method
Created a number of new functions for redundant code, including to initialize characters for combat and spending actions - also changed the suggested method of import, having the user import and add the commands. Adding the command set to BattleCharacter at creation was not persistent across reloads.
This commit is contained in:
parent
4e3b59e486
commit
9e6627aabd
1 changed files with 97 additions and 69 deletions
|
|
@ -16,7 +16,8 @@ is easily extensible and can be used as the foundation for implementing
|
||||||
the rules from your turn-based tabletop game of choice or making your
|
the rules from your turn-based tabletop game of choice or making your
|
||||||
own battle system.
|
own battle system.
|
||||||
|
|
||||||
To install and test, import this module's BattleCharacter object:
|
To install and test, import this module's BattleCharacter object into
|
||||||
|
your game's character.py module:
|
||||||
|
|
||||||
from evennia.contrib.turnbattle import BattleCharacter
|
from evennia.contrib.turnbattle import BattleCharacter
|
||||||
|
|
||||||
|
|
@ -24,6 +25,21 @@ And change your game's character typeclass to inherit from BattleCharacter
|
||||||
instead of the default:
|
instead of the default:
|
||||||
|
|
||||||
class Character(BattleCharacter):
|
class Character(BattleCharacter):
|
||||||
|
|
||||||
|
Next, import the combat commands into your default_cmdsets.py module:
|
||||||
|
|
||||||
|
from evennia.contrib.turnbattle import CmdFight, CmdAttack, CmdRest, CmdPass, CmdDisengage
|
||||||
|
|
||||||
|
And add the commands to your default command set:
|
||||||
|
|
||||||
|
#
|
||||||
|
# any commands you add below will overload the default ones.
|
||||||
|
#
|
||||||
|
self.add(CmdFight())
|
||||||
|
self.add(CmdAttack())
|
||||||
|
self.add(CmdRest())
|
||||||
|
self.add(CmdPass())
|
||||||
|
self.add(CmdDisengage())
|
||||||
|
|
||||||
This module is meant to be heavily expanded on, so you may want to copy it
|
This module is meant to be heavily expanded on, so you may want to copy it
|
||||||
to your game's 'world' folder and modify it there rather than importing it
|
to your game's 'world' folder and modify it there rather than importing it
|
||||||
|
|
@ -65,25 +81,6 @@ def roll_init(character):
|
||||||
This way, characters with a higher dexterity will go first more often.
|
This way, characters with a higher dexterity will go first more often.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def start_turn(character):
|
|
||||||
"""
|
|
||||||
Readies a character for the start of their turn by replenishing their
|
|
||||||
available actions and notifying them that their turn has come up.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
character (obj): Character to be readied.
|
|
||||||
"""
|
|
||||||
character.db.Combat_ActionsLeft = 1 # 1 action per turn.
|
|
||||||
"""
|
|
||||||
Here, you only get one action per turn, but you might want to allow more than
|
|
||||||
one per turn, or even grant a number of actions based on a character's
|
|
||||||
attributes. You can even add multiple different kinds of actions, I.E. actions
|
|
||||||
separated for movement, by adding "character.db.Combat_MovesLeft = 3" or
|
|
||||||
something similar.
|
|
||||||
"""
|
|
||||||
# Prompt the character for their turn and give some information.
|
|
||||||
character.msg("|wIt's your turn! You have %i HP remaining.|n" % character.db.hp)
|
|
||||||
|
|
||||||
def get_attack(attacker, defender):
|
def get_attack(attacker, defender):
|
||||||
"""
|
"""
|
||||||
Returns a value for an attack roll.
|
Returns a value for an attack roll.
|
||||||
|
|
@ -243,6 +240,29 @@ def is_turn(character):
|
||||||
if character == currentchar:
|
if character == currentchar:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def spend_action(character, actions, action_name=None):
|
||||||
|
"""
|
||||||
|
Spends a character's available combat actions and checks for end of turn.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
character (obj): Character spending the action
|
||||||
|
actions (int) or 'all': Number of actions to spend, or 'all' to spend all actions
|
||||||
|
|
||||||
|
Kwargs:
|
||||||
|
action_name (str or None): If a string is given, sets character's last action in
|
||||||
|
combat to provided string
|
||||||
|
"""
|
||||||
|
if action_name:
|
||||||
|
character.db.Combat_LastAction = action_name
|
||||||
|
if actions == 'all': # If spending all actions
|
||||||
|
character.db.Combat_ActionsLeft = 0 # Set actions to 0
|
||||||
|
else:
|
||||||
|
character.db.Combat_ActionsLeft -= actions # Use up actions.
|
||||||
|
if character.db.Combat_ActionsLeft < 0:
|
||||||
|
character.db.Combat_ActionsLeft = 0 # Can't have fewer than 0 actions
|
||||||
|
character.db.Combat_TurnHandler.turn_end_check(character) # Signal potential end of turn.
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
||||||
|
|
@ -261,7 +281,6 @@ class BattleCharacter(DefaultCharacter):
|
||||||
Called once, when this object is first created. This is the
|
Called once, when this object is first created. This is the
|
||||||
normal hook to overload for most object types.
|
normal hook to overload for most object types.
|
||||||
"""
|
"""
|
||||||
self.cmdset.add('contrib.turnbattle.BattleCmdSet') # Add combat commands
|
|
||||||
self.db.max_hp = 100 # Set maximum HP to 100
|
self.db.max_hp = 100 # Set maximum HP to 100
|
||||||
self.db.hp = self.db.max_hp # Set current HP to maximum
|
self.db.hp = self.db.max_hp # Set current HP to maximum
|
||||||
"""
|
"""
|
||||||
|
|
@ -295,24 +314,7 @@ class BattleCharacter(DefaultCharacter):
|
||||||
self.caller.msg("You can't move, you've been defeated!")
|
self.caller.msg("You can't move, you've been defeated!")
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
class BattleCmdSet(default_cmds.CharacterCmdSet):
|
|
||||||
"""
|
|
||||||
Adds combat commands to the default command set.
|
|
||||||
"""
|
|
||||||
key = "BattleCmdSet"
|
|
||||||
|
|
||||||
def at_cmdset_creation(self):
|
|
||||||
"""
|
|
||||||
Populates the cmdset
|
|
||||||
"""
|
|
||||||
super(default_cmds.CharacterCmdSet, self).at_cmdset_creation()
|
|
||||||
self.add(CmdFight())
|
|
||||||
self.add(CmdAttack())
|
|
||||||
self.add(CmdRest())
|
|
||||||
self.add(CmdPass())
|
|
||||||
self.add(CmdDisengage())
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
||||||
COMMANDS START HERE
|
COMMANDS START HERE
|
||||||
|
|
@ -401,9 +403,7 @@ class CmdAttack(Command):
|
||||||
|
|
||||||
"If everything checks out, call the attack resolving function."
|
"If everything checks out, call the attack resolving function."
|
||||||
resolve_attack(attacker, defender)
|
resolve_attack(attacker, defender)
|
||||||
self.caller.db.Combat_LastAction = "attack"
|
spend_action(self.caller, 1, action_name="attack") # Use up one action.
|
||||||
self.caller.db.Combat_ActionsLeft -= 1 # Use up one action.
|
|
||||||
self.caller.db.Combat_TurnHandler.turn_end_check(self.caller) # Signal potential end of turn.
|
|
||||||
|
|
||||||
class CmdPass(Command):
|
class CmdPass(Command):
|
||||||
"""
|
"""
|
||||||
|
|
@ -433,9 +433,7 @@ class CmdPass(Command):
|
||||||
return
|
return
|
||||||
|
|
||||||
self.caller.location.msg_contents("%s takes no further action, passing the turn." % self.caller)
|
self.caller.location.msg_contents("%s takes no further action, passing the turn." % self.caller)
|
||||||
self.caller.db.Combat_LastAction = "pass"
|
spend_action(self.caller, 'all', action_name="pass") # Spend all remaining actions.
|
||||||
self.caller.db.Combat_ActionsLeft = 0
|
|
||||||
self.caller.db.Combat_TurnHandler.turn_end_check(self.caller) # Signal end of turn.
|
|
||||||
|
|
||||||
class CmdDisengage(Command):
|
class CmdDisengage(Command):
|
||||||
"""
|
"""
|
||||||
|
|
@ -466,9 +464,11 @@ class CmdDisengage(Command):
|
||||||
return
|
return
|
||||||
|
|
||||||
self.caller.location.msg_contents("%s disengages, ready to stop fighting." % self.caller)
|
self.caller.location.msg_contents("%s disengages, ready to stop fighting." % self.caller)
|
||||||
self.caller.db.Combat_LastAction = "disengage" # This is checked by the turn handler to end combat if all disengage.
|
spend_action(self.caller, 'all', action_name="disengage") # Spend all remaining actions.
|
||||||
self.caller.db.Combat_ActionsLeft = 0
|
"""
|
||||||
self.caller.db.Combat_TurnHandler.turn_end_check(self.caller) # Signal end of turn.
|
The action_name kwarg sets the character's last action to "disengage", which is checked by
|
||||||
|
the turn handler script to see if all fighters have disengaged.
|
||||||
|
"""
|
||||||
|
|
||||||
class CmdRest(Command):
|
class CmdRest(Command):
|
||||||
"""
|
"""
|
||||||
|
|
@ -523,23 +523,25 @@ class TurnHandler(DefaultScript):
|
||||||
self.interval = 10 # Once every 10 seconds
|
self.interval = 10 # Once every 10 seconds
|
||||||
self.persistent = True
|
self.persistent = True
|
||||||
self.db.fighters = []
|
self.db.fighters = []
|
||||||
|
|
||||||
# Add all fighters in the room with at least 1 HP to the combat."
|
# Add all fighters in the room with at least 1 HP to the combat."
|
||||||
for object in self.obj.contents:
|
for object in self.obj.contents:
|
||||||
if object.db.hp:
|
if object.db.hp:
|
||||||
self.db.fighters.append(object)
|
self.db.fighters.append(object)
|
||||||
|
|
||||||
# Initialize each fighter for combat
|
# Initialize each fighter for combat
|
||||||
for fighter in self.db.fighters:
|
for fighter in self.db.fighters:
|
||||||
combat_cleanup(fighter) #Clean up leftover combat attributes beforehand, just in case.
|
self.initialize_for_combat(fighter)
|
||||||
fighter.db.Combat_ActionsLeft = 1 #Actions remaining - start of turn adds to this, turn ends when it reaches 0
|
|
||||||
fighter.db.Combat_TurnHandler = self #Add a reference to this script to the character
|
|
||||||
fighter.db.Combat_LastAction = "null" #Track last action taken in combat
|
|
||||||
# Roll initiative and sort the list of fighters depending on who rolls highest to determine turn order.
|
# Roll initiative and sort the list of fighters depending on who rolls highest to determine turn order.
|
||||||
# The initiative roll is determined by the roll_init function and can be customized easily.
|
# The initiative roll is determined by the roll_init function and can be customized easily.
|
||||||
ordered_by_roll = sorted(self.db.fighters, key=roll_init, reverse=True)
|
ordered_by_roll = sorted(self.db.fighters, key=roll_init, reverse=True)
|
||||||
self.db.fighters = ordered_by_roll
|
self.db.fighters = ordered_by_roll
|
||||||
|
|
||||||
# Announce the turn order.
|
# Announce the turn order.
|
||||||
self.obj.msg_contents("Turn order is: %s " % ", ".join(obj.key for obj in self.db.fighters))
|
self.obj.msg_contents("Turn order is: %s " % ", ".join(obj.key for obj in self.db.fighters))
|
||||||
"Set up the current turn and turn timeout delay."
|
|
||||||
|
#Set up the current turn and turn timeout delay.
|
||||||
self.db.turn = 0
|
self.db.turn = 0
|
||||||
self.db.timer = 30 # 30 seconds
|
self.db.timer = 30 # 30 seconds
|
||||||
|
|
||||||
|
|
@ -563,21 +565,37 @@ class TurnHandler(DefaultScript):
|
||||||
|
|
||||||
# Force current character to disengage if timer runs out.
|
# Force current character to disengage if timer runs out.
|
||||||
if self.db.timer <= 0:
|
if self.db.timer <= 0:
|
||||||
currentchar.db.Combat_LastAction = "disengage" # Set last action to 'disengage'
|
|
||||||
currentchar.db.Combat_ActionsLeft = 0 # Set actions remaining to 0
|
|
||||||
self.obj.msg_contents("%s's turn timed out!" % currentchar)
|
self.obj.msg_contents("%s's turn timed out!" % currentchar)
|
||||||
self.next_turn()
|
spend_action(currentchar, 'all', action_name="disengage") # Spend all remaining actions.
|
||||||
|
|
||||||
def turn_end_check(self, character):
|
|
||||||
|
def initialize_for_combat(self, character):
|
||||||
"""
|
"""
|
||||||
Tests to see if a character's turn is over, and cycles to the next turn if it is.
|
Prepares a character for combat when starting or entering a fight.
|
||||||
|
"""
|
||||||
|
combat_cleanup(character) # Clean up leftover combat attributes beforehand, just in case.
|
||||||
|
character.db.Combat_ActionsLeft = 0 # Actions remaining - start of turn adds to this, turn ends when it reaches 0
|
||||||
|
character.db.Combat_TurnHandler = self # Add a reference to this turn handler script to the character
|
||||||
|
character.db.Combat_LastAction = "null" # Track last action taken in combat
|
||||||
|
|
||||||
|
def start_turn(self, character):
|
||||||
|
"""
|
||||||
|
Readies a character for the start of their turn by replenishing their
|
||||||
|
available actions and notifying them that their turn has come up.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
character (obj): Character to test for end of turn
|
character (obj): Character to be readied.
|
||||||
"""
|
"""
|
||||||
if not character.db.Combat_ActionsLeft: # Character has no actions remaining
|
character.db.Combat_ActionsLeft = 1 # 1 action per turn.
|
||||||
self.next_turn()
|
"""
|
||||||
return
|
Here, you only get one action per turn, but you might want to allow more than
|
||||||
|
one per turn, or even grant a number of actions based on a character's
|
||||||
|
attributes. You can even add multiple different kinds of actions, I.E. actions
|
||||||
|
separated for movement, by adding "character.db.Combat_MovesLeft = 3" or
|
||||||
|
something similar.
|
||||||
|
"""
|
||||||
|
# Prompt the character for their turn and give some information.
|
||||||
|
character.msg("|wIt's your turn! You have %i HP remaining.|n" % character.db.hp)
|
||||||
|
|
||||||
def next_turn(self):
|
def next_turn(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -613,9 +631,22 @@ class TurnHandler(DefaultScript):
|
||||||
if self.db.turn > len(self.db.fighters) - 1:
|
if self.db.turn > len(self.db.fighters) - 1:
|
||||||
self.db.turn = 0 # Go back to the first in the turn order once you reach the end.
|
self.db.turn = 0 # Go back to the first in the turn order once you reach the end.
|
||||||
newchar = self.db.fighters[self.db.turn]
|
newchar = self.db.fighters[self.db.turn]
|
||||||
self.db.timer = 30 # Reset the timer.
|
# Reset the timer.
|
||||||
|
self.db.timer = 30 + self.interval
|
||||||
|
self.force_repeat()
|
||||||
self.obj.msg_contents("%s's turn ends - %s's turn begins!" % (currentchar, newchar))
|
self.obj.msg_contents("%s's turn ends - %s's turn begins!" % (currentchar, newchar))
|
||||||
start_turn(newchar) # Start the new character's turn.
|
self.start_turn(newchar) # Start the new character's turn.
|
||||||
|
|
||||||
|
def turn_end_check(self, character):
|
||||||
|
"""
|
||||||
|
Tests to see if a character's turn is over, and cycles to the next turn if it is.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
character (obj): Character to test for end of turn
|
||||||
|
"""
|
||||||
|
if not character.db.Combat_ActionsLeft: # Character has no actions remaining
|
||||||
|
self.next_turn()
|
||||||
|
return
|
||||||
|
|
||||||
def join_fight(self, character):
|
def join_fight(self, character):
|
||||||
"""
|
"""
|
||||||
|
|
@ -624,12 +655,9 @@ class TurnHandler(DefaultScript):
|
||||||
Args:
|
Args:
|
||||||
character (obj): Character to be added to the fight.
|
character (obj): Character to be added to the fight.
|
||||||
"""
|
"""
|
||||||
# Inserts the fighter to the turn order behind whoever's turn it currently is.
|
# Inserts the fighter to the turn order, right behind whoever's turn it currently is.
|
||||||
self.db.fighters.insert(self.db.turn, character)
|
self.db.fighters.insert(self.db.turn, character)
|
||||||
# Tick the turn counter forward one to compensate.
|
# Tick the turn counter forward one to compensate.
|
||||||
self.db.turn += 1
|
self.db.turn += 1
|
||||||
# Initialize the character like you do at the start.
|
# Initialize the character like you do at the start.
|
||||||
combat_cleanup(fighter) # Clean up leftover combat attributes beforehand, just in case.
|
self.initialize_for_combat(character)
|
||||||
fighter.db.Combat_ActionsLeft = 0 # Actions remaining - start of turn adds to this, turn ends when it reaches 0
|
|
||||||
fighter.db.Combat_TurnHandler = self # Add a reference to this scrip to the character
|
|
||||||
fighter.db.Combat_LastAction = "null" # Track last action taken in combat
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue