[REQUEST] new function onSpawnEntity(_entity) function for entities/items/skills
Opened this issue · 3 comments
Is your feature request related to a problem? Please describe.
Currently no skill, item or entity can actively react to an entity spawning mid fight.
This ability would be useful for
- items and skills which emit an aura which can only be realised by having every other entity gain an aura-receiving-effect. Examples are the battle_standard_effect and captain_effect: these effects are currently added to every entity regardless of whether an emitter is present
- new effects similar to night debuff that are depending on some conditions. Examples: reaction to world climate (heat, cold, wet), vampire-debuff for fighting during daylight
Describe the solution you'd like
There is the function spawnEntity
in the BB root table that is used to spawn any entity via its scriptPath mid-fight.
That function should be hooked so that it calls the following new onSpawnEntity
function on the spawned entity before returning it
Add this new function to the entity.nut:
function onSpawnEntity()
{
if (!this.World.getTime().IsDaytime && player.getBaseProperties().IsAffectedByNight)
{
this.getSkills().add(::new("scripts/skills/special/night_effect"));
}
foreach (i, faction in this.getAllInstances())
{
foreach (actor in faction)
{
actor.getSkills().onSpawnEntity(this);
actor.getItems().onSpawnEntity(this);
actor.getSkills().update();
}
}
}
Similar functions would be added to skill_container.nut
, skill.nut
aswell as item_container.nut
and item.nut
. But here they wouldn't contain any inherent effects.
So as a nice side-effect the night effect is now automatically added to every entitiy that is spawned mid-fight. No longer do we need to do this manually for unleashable animals for example.
This is actually a pretty cool idea I think.
I've been working on this for quite some time and unfortunately it doesn't have a simple/clean solution. Ideally I'd like the onSpawnEntity
event to trigger after the entity has been properly set up i.e. its faction has been assigned and its items have been equipped.
My current solution consists of all of the following:
- Hook
setupEntity
in tactical_entity_manager and callonSpawn
from there. - Hook
onResurrect
in tactical_entity_manager and callonSpawn
from there. - The above functions are not called for
player
entities. So, hookaddEntity
andinsertEntity
inturn_sequence_bar
and check for faction being non-zero (faction is zero when an entity is first inserted into the turn sequence bar, except for player entities. These entities get their factions assigned later). Then callonSpawn
. - Because of this hook on turn sequence bar, I've had to keep a boolean
HasOnSpawnBeenCalled
in the actor, to prevent calling the event again and again when the entity is removed from map and placed on map again e.g. after being devoured whole.
An alternative is to call onSpawn
from onPlacedOnMap
in actor (will still require that Boolean above) - however, the issue here is also that this function is called when the entity's faction is 0 and its item container is empty.
Another alternative is to call onSpawn
from addInstance
in tactical_entity_manager
. However, that event is called via setFaction
in actor, so the faction is properly set, but it is called before their items have been set.
Summary:
Using hooks on setupEntity
, onResurrect
, addEntity
, insertEntity
, I am able to trigger the event reliably for entities at the start of a combat with all the info (faction, items etc.) been properly set up for the entity spawned. However, currently I do not have a solution for entities spawned mid-combat via the ::Tactical.spawnEntity
function as during this time their faction and items are 0.
After a lot more working here is a "dirty" solution that I have that currently seems to work. We basically call onSpawn
from the character's onSkillsUpdated
function but we build in several checks via Booleans here and there to ensure that it is really only called on the first "valid" skill container update after being spawned i.e. the update that happens after all faction and item setup is complete.
- Add the following variables in actor:
this.m.HasOnSpawnBeenCalled <- true;
this.m.IsInstanceAdded <- false;
this.m.IsAssigningRandomEquipment <- false;
- Add the variable
this.m.IsResurrecting
to tactical_entity_manager which is set totrue
at the start of theonResurrect
function and then tofalse
at the end of it. - Add a hookTree on
onAfterInit
of actor and setthis.m.HasOnSpawnBeenCalled
tofalse
. - Add a hookTree on
assignRandomEquipment
of actor and setthis.m.IsAssigningRandomEquipment
to true at the start and false at the end of the function. Manually callthis.onSpawn()
at the end of this function. - Add a hook on
onSkillsUpdated
of actor and do the following i.e. call theonSpawn
event if all these conditions are satisfied. This event will then iterate over all entities on the map and tell them that this entity has spawned.
if (this.isPlacedOnMap() && !this.m.IsAssigningRandomEquipment && this.m.IsInstanceAdded && !::Tactical.Entities.m.IsResurrecting)
this.onSpawn();
- Hook
addInstance
in tactical_entity_manager and if_actor.getFaction() != 0
set_actor.m.IsInstanceAdded = true;
So:
- Entities set
this.m.HasOnSpawnBeenCalled
to false after init. This means that the next call toonSpawn
will be allowed. This ensures that skills added duringonInit
do not trigger theonSpawn
event. - When their instance is added to the tactical entity manager, it sets
this.m.IsInstanceAdded
to true. - When their equipment is being assigned in
assignRandomEquipment
, then any skills added there do not callonSpawn
because of our hook ononSkillsUpdated
which checks forIsAssigningRandomEquipment
to be false. - Once all their equipment has been assigned, the manual call to
this.onSpawn()
triggers the event. If they were not assigning any equipment, then the event is triggered due to the hook ononSkillsUpdated
which is called when the character's skill container updates after spawning. Thethis.m.IsInstanceAdded
check in this case ensures that entities that spawn during the combat do not trigger the event before their faction has been properly set.
Other thoughts:
While this may work, and if it really works and is robust enough then perhaps it is worth it to do it like this. However, if it is fragile and if there are still edge cases where it may break, then perhaps it is better to just use a normal hook on addInstance
and trigger onSpawn
with faction info but with the limitation that the item container will be empty (and any skills added in assignRandomEquipment
or similar functions will not be present yet). We can then document this so people know.