-
Notifications
You must be signed in to change notification settings - Fork 3
Effects Handling
In this wiki page, you'll learn more about the Bane Of Wargs game engine, and more specifically about how the game engine handle effects. I thought it'd be interesting to do and it might help understanding better how effect types works and how they really affect the player. We'll go over every different effects types and how they're handling, because, even if they're handled the same way, they all have different parameters, options, systems and actions in the game engine.
Note that this wiki page complements the Effects Types wiki page, which also complements this one. So make sure you've check the Effect Types wiki page before checking this one.
Here's an extract from the source code of the game engine where the effects are handled:
Source Code Extract
main.py
class, l.1021-1143
# All the checks for the player active effects
# are here
#
# If the player has any active effects, load
# them one by one and update them depending
# on their dictionary content and type
global player_damage_coefficient, time_elapsing_coefficient
player_damage_coefficient = 1
time_elapsing_coefficient = 1
if player["held item"] != " ":
player["critical hit chance"] = item[player["held item"]]["critical hit chance"]
else:
player["critical hit chance"] = 0
if player["active effects"] != {}:
for i in list(player["active effects"]):
current_effect = player["active effects"][i]
effect_over = False
# Run the actions for every effect type
if current_effect["type"] == 'healing':
# Check if the effect duration's over
if (
(
current_effect["effect duration"] + current_effect["effect starting time"]
) < player["elapsed time game days"]
):
# Remove that effect from the player
# active effects and set the player
# modified stats to before the effect
# happened
player["active effects"].pop(i)
player["health"] = current_effect["before stats"]["health"]
player["max health"] = current_effect["before stats"]["max health"]
effect_over = True
# Check if the effect has already been
# applied or not
if not current_effect["already applied"] and not effect_over:
# Apply that effect changes now
if current_effect["effects"]["health changes"] >= 999:
player["health"] = player["max health"]
else:
player["health"] += current_effect["effects"]["health changes"]
player["max health"] += current_effect["effects"]["max health changes"]
player["active effects"][i]["already applied"] = True
elif current_effect["type"] == 'protection':
# Check if the effect duration's over
if (
(
current_effect["effect duration"] + current_effect["effect starting time"]
) < player["elapsed time game days"] and current_effect["effect duration"] != 999
):
# Remove that effect from the player
# active effects
player["active effects"].pop(i)
effect_over = True
# Apply the effect effects if the
# effect isn't over
if not effect_over:
player["armor protection"] = player["armor protection"] * current_effect[
"effects"
]["protection coefficient"]
elif current_effect["type"] == 'strength':
# Check if the effect duration's over
if (
(
current_effect["effect duration"] + current_effect["effect starting time"]
) < player["elapsed time game days"] and current_effect["effect duration"] != 999
):
# Remove that effect from the player
# active effects
player["active effects"].pop(i)
effect_over = True
# Apply the effect effects if the
# effect isn't over
if not effect_over:
player["critical hit chance"] = player["critical hit chance"] * current_effect["effects"][
"critical hit chance coefficient"
]
# If the player already has an effect that changes
# the damage coefficient and that's greater, don't
# apply the current effect coefficient
# = keep the greater one
if not player_damage_coefficient > current_effect["effects"]["damage coefficient"]:
player_damage_coefficient = current_effect["effects"]["damage coefficient"]
elif current_effect["type"] == 'agility':
# Check if the effect duration's over
if (
(
current_effect["effect duration"] + current_effect["effect starting time"]
) < player["elapsed time game days"] and current_effect["effect duration"] != 999
):
# Remove that effect from the player
# active effects
player["active effects"].pop(i)
effect_over = True
# Apply the effect effects if the
# effect isn't over
if not effect_over:
player["agility"] = player["agility"] * current_effect[
"effects"
]["agility coefficient"]
elif current_effect["type"] == 'time elapsing':
# Check if the effect duration's over
if (
(
current_effect["effect duration"] + current_effect["effect starting time"]
) < player["elapsed time game days"] and current_effect["effect duration"] != 999
):
# Remove that effect from the player
# active effects
player["active effects"].pop(i)
effect_over = True
# Apply the effect effects if the
# effect isn't over
if not effect_over:
# If the player already has an effect that changes
# the damage coefficient, make so that the global
# coefficient gets added that effect coefficient
if time_elapsing_coefficient != 1:
time_elapsing_coefficient = (
time_elapsing_coefficient * current_effect["effects"]["time elapsing coefficient"]
)
else:
time_elapsing_coefficient = current_effect["effects"]["time elapsing coefficient"]
consumable_handling
class, l.16-359
def get_healing_effect_changes(effect_data):
health_changes = 0
max_health_changes = 0
if "augmentation" in list(effect_data["health change"]):
augmentation = effect_data["health change"]["augmentation"]
health_changes += augmentation
if "diminution" in list(effect_data["health change"]):
diminution = effect_data["health change"]["diminution"]
health_changes -= diminution
if "max health" in list(effect_data["health change"]):
if "augmentation" in list(effect_data["health change"]["max health"]):
augmentation = effect_data["health change"]["max health"]["augmentation"]
max_health_changes += augmentation
if "diminution" in list(effect_data["health change"]["max health"]):
diminution = effect_data["health change"]["max health"]["diminution"]
max_health_changes -= diminution
return health_changes, max_health_changes
def get_exp_changes_effect_changes(effect_data):
exp_changes = 0
if "augmentation" in list(effect_data["exp change"]):
augmentation = effect_data["exp change"]["augmentation"]
exp_changes += augmentation
if "diminution" in list(effect_data["exp change"]):
diminution = effect_data["exp change"]["diminution"]
exp_changes -= diminution
return exp_changes
def healing_effect(effect_data, player):
# Generate a UUID for that new
# effect
effect_uuid = str(uuid_handling.generate_random_uuid())
# If this effect has a timer, create
# the effect dictionary that will be
# added to the player save data and then
# handled by the main.py function
#
# If not, just apply the effects of that
# effect one by one
if "effect time" in effect_data:
effects = {}
# Create the applied effects dictionary
health_changes, max_health_changes = get_healing_effect_changes(effect_data)
effects = {
"health changes": health_changes,
"max health changes": max_health_changes
}
effect_dictionary = {
"effect duration": effect_data["effect time"],
"effect starting time": player["elapsed time game days"],
"type": effect_data["type"],
"already applied": False,
"before stats": {
"health": player["health"],
"max health": player["max health"]
},
"effects": effects
}
# Add the effect dictionary to the player
# active effects dictionary
player["active effects"][effect_uuid] = effect_dictionary
else:
if effect_data["health change"] is not None:
health_changes, max_health_changes = get_healing_effect_changes(effect_data)
if health_changes >= 999:
player["health"] = player["max health"]
else:
player["health"] += health_changes
player["max health"] += max_health_changes
def protection_effect(effect_data, player):
# Generate a UUID for that new
# effect
effect_uuid = str(uuid_handling.generate_random_uuid())
# Create the effect dictionary that will
# be added to the player save data and then
# handled by the main.py function
effects = {}
# Create the applied effects dictionary
if "coefficient" in list(effect_data["protection change"]):
protection_coefficient = effect_data["protection change"]["coefficient"]
else:
protection_coefficient = 1
effects = {
"protection coefficient": protection_coefficient
}
effect_dictionary = {
"effect duration": effect_data["effect time"],
"effect starting time": player["elapsed time game days"],
"type": effect_data["type"],
"effects": effects
}
# Add the effect dictionary to the player
# active effects dictionary
player["active effects"][effect_uuid] = effect_dictionary
def strength_effect(effect_data, player):
# Generate a UUID for that new
# effect
effect_uuid = str(uuid_handling.generate_random_uuid())
# Create the effect dictionary that will
# be added to the player save data and then
# handled by the main.py function
effects = {}
# Create the applied effects dictionary
damage_coefficient = 1
critical_hit_chance_coefficient = 1
if effect_data["strength change"] is not None:
if "damage coefficient" in list(effect_data["strength change"]):
damage_coefficient = effect_data["strength change"]["damage coefficient"]
if "critical hit chance coefficient" in list(effect_data["strength change"]):
critical_hit_chance_coefficient = effect_data["strength change"]["critical hit chance coefficient"]
effects = {
"damage coefficient": damage_coefficient,
"critical hit chance coefficient": critical_hit_chance_coefficient
}
effect_dictionary = {
"effect duration": effect_data["effect time"],
"effect starting time": player["elapsed time game days"],
"type": effect_data["type"],
"effects": effects
}
# Add the effect dictionary to the player
# active effects dictionary
player["active effects"][effect_uuid] = effect_dictionary
def agility_effect(effect_data, player):
# Generate a UUID for that new
# effect
effect_uuid = str(uuid_handling.generate_random_uuid())
# Create the effect dictionary that will
# be added to the player save data and then
# handled by the main.py function
effects = {}
# Create the applied effects dictionary
if "coefficient" in list(effect_data["agility change"]):
agility_coefficient = effect_data["agility change"]["coefficient"]
else:
agility_coefficient = 1
effects = {
"agility coefficient": agility_coefficient
}
effect_dictionary = {
"effect duration": effect_data["effect time"],
"effect starting time": player["elapsed time game days"],
"type": effect_data["type"],
"effects": effects
}
# Add the effect dictionary to the player
# active effects dictionary
player["active effects"][effect_uuid] = effect_dictionary
def time_elapsing_effect(effect_data, player):
# Generate a UUID for that new
# effect
effect_uuid = str(uuid_handling.generate_random_uuid())
# Create the effect dictionary that will
# be added to the player save data and then
# handled by the main.py function
effects = {}
# Create the applied effects dictionary
if "coefficient" in list(effect_data["time change"]):
time_elapsing_coefficient = effect_data["time change"]["coefficient"]
else:
time_elapsing_coefficient = 1
effects = {
"time elapsing coefficient": time_elapsing_coefficient
}
effect_dictionary = {
"effect duration": effect_data["effect time"],
"effect starting time": player["elapsed time game days"],
"type": effect_data["type"],
"effects": effects
}
# Add the effect dictionary to the player
# active effects dictionary
player["active effects"][effect_uuid] = effect_dictionary
def attributes_addition_effect(current_effect_data, player):
# Check if there're effects to add, and
# if yes, add them one by one
if "attributes addition" in list(current_effect_data):
for i in current_effect_data["attributes addition"]:
player["attributes"] += [i]
def dialog_displaying_effect(current_effect_data, player, dialog, preferences, text_replacements_generic, drinks):
print("")
text_handling.print_separator("=")
dialog_handling.print_dialog(current_effect_data["dialog"], dialog, preferences, text_replacements_generic, player, drinks)
text_handling.print_separator("=")
print("")
def enemy_spawning_effect(
current_effect_data, player, lists, map_location, enemy, item,
start_player, preferences, drinks, npcs, zone, mounts, mission,
dialog, player_damage_coefficient, text_replacements_generic
):
enemy_list = lists[current_effect_data["enemy list"]]
enemies_number = current_effect_data["enemies number"]
enemy_handling.spawn_enemy(
map_location, enemy_list, enemies_number, enemy, item, lists, start_player, map, player,
preferences, drinks, npcs, zone, mounts, mission, dialog, player_damage_coefficient,
text_replacements_generic
)
def exp_change_effect(current_effect_data, player):
exp_changes = get_exp_changes_effect_changes(current_effect_data)
player["xp"] += exp_changes
def coordinates_change_effect(current_effect_data, player):
if "x" in list(current_effect_data["coordinates change"]):
player["x"] = current_effect_data["coordinates change"]["x"]
if "y" in list(current_effect_data["coordinates change"]):
player["y"] = current_effect_data["coordinates change"]["y"]
def inventory_change_effect(current_effect_data, player):
if "removals" in list(current_effect_data["inventory change"]):
for i in current_effect_data["inventory change"]["removals"]:
player["inventory"].remove(i)
if "additions" in list(current_effect_data["inventory change"]):
for i in current_effect_data["inventory change"]["additions"]:
player["inventory"].append(i)
def consume_consumable(
item_data, consumable_name, player,
dialog, preferences, text_replacements_generic,
lists, map_location, enemy, item, drinks,
start_player, npcs, zone,
mounts, mission, player_damage_coefficient
):
# First, load the consumable data and stores
# it in a variable, then remove the item
# from the player's inventory
logger_sys.log_message(f"INFO: Loading consumable '{consumable_name}' data")
consumable_data = item_data[consumable_name]
logger_sys.log_message(f"INFO: Loaded consumable '{consumable_name}' data:\n{consumable_data}")
player["inventory"].remove(consumable_name)
logger_sys.log_message(f"INFO: Removing item '{consumable_name}' form the player inventory")
# If the consumable is a food, load the
# health regeneration and apply them
if consumable_data["type"] == "Food":
if consumable_data["healing level"] == 999:
player["health"] = player["max health"]
else:
player["health"] += consumable_data["healing level"]
player["max health"] += consumable_data["max bonus"]
else:
# Then, load the consumable effects 1 by 1
# and apply the effects 1 by 1
logger_sys.log_message(f"INFO: Getting consumable '{consumable_name}' effects")
if consumable_data["effects"] is not None:
effects = consumable_data["effects"]
logger_sys.log_message(f"INFO: Loaded consumable '{consumable_name}' effects:\n{effects}")
count = 0
for effect in consumable_data["effects"]:
current_effect_data = consumable_data["effects"][count]
current_effect_type = current_effect_data["type"]
logger_sys.log_message(
f"INFO: Running consumable effect with '{current_effect_type}' parameter;\n{current_effect_data}"
)
if current_effect_type == "healing":
healing_effect(current_effect_data, player)
elif current_effect_type == "protection":
protection_effect(current_effect_data, player)
elif current_effect_type == "strength":
strength_effect(current_effect_data, player)
elif current_effect_type == "agility":
agility_effect(current_effect_data, player)
elif current_effect_type == "time elapsing":
time_elapsing_effect(current_effect_data, player)
elif current_effect_type == "attributes addition":
attributes_addition_effect(current_effect_data, player)
elif current_effect_type == "dialog displaying":
dialog_displaying_effect(current_effect_data, player, dialog, preferences, text_replacements_generic, drinks)
elif current_effect_type == "enemy spawning":
enemy_spawning_effect(
current_effect_data, player, lists, map_location, enemy, item,
start_player, preferences, drinks, npcs, zone, mounts, mission,
dialog, player_damage_coefficient, text_replacements_generic
)
elif current_effect_type == "exp change":
exp_change_effect(current_effect_data, player)
elif current_effect_type == "coordinates change":
coordinates_change_effect(current_effect_data, player)
elif current_effect_type == "inventory change":
inventory_change_effect(current_effect_data, player)
count += 1
else:
logger_sys.log_message(f"INFO: Found no effects for consumable '{consumable_name}'")
There are currently 11 different types of effects in the current game engine:
- healing # change player health and max health (for a defined amount of time if defined)
- protection # change player global armor protection (for a defined amount of time)
- strength # increase the player global damage and critical hit chance (for a defined amount of time)
- agility # change player global agility (for a defined amount of time)
- time elapsing # increase/decrease time elapsing (for a defined amount of time)
- *attributes addition # add custom attributes to the player
- *dialog displaying # display a dialog
- *enemy spawning # spawn an enemy/enemies
- exp change # change player experience stat
- *coordinates change # change the player's location
- *inventory change # give/remove items for the player's inventory
Note that all the effect starting with a *
do not display on the consumable effect info in the inventory management UI (they're invisible).
Every active effects are stored in the player save data active effects
dictionary. Here's how it can look:
[...]
active effects: {} # here, no effects are active
[...]
[...]
active effects:
457f110d-9bea-4ecf-96f0-b59a9768b501:
effect duration: 0.5
effect starting time: 554.5899999999987
effects:
protection coefficient: 1.4
type: protection
[...]
As you notice, each effect has a specific UUID, generated from the uuid_handling.py
class' function generate_random_uuid
, which uses the built-in python uuid
module uuid4 generation method. This makes so that each effects, even if they're from the same type, are unique. Once the effect is over, the effect dictionary is removed from the active effects
dictionary. This means that the active effects
key can be empty, it'll have as a value only {}
.
Hint: you can check the player save data using the secret $player$data$
command, while being in game.
- Running The Game
- Gameplay Guide
- GitHub Discussions
- Building Source Code
- Game Preferences
- The Game Folder
- The World Of Bane Of Wargs
- Game Timeline Plot
- Yaml Syntax
- Creating Mods
- Creating Starts
- Creating Map Points
- Creating Enemies
- Creating Enemies Categories
- Creating Map Zones
- Creating Items
- Creating Drinks
- Writing Dialogs
- Creating Missions
- Creating Events
- Creating NPCS
- Creating Mounts
Additional Knowledge