Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Affordability preview improved 2 #354

Open
wants to merge 13 commits into
base: development
Choose a base branch
from

Conversation

LordMidas
Copy link
Member

@LordMidas LordMidas commented May 10, 2024

Should be used instead of #346 because this implements it in a way where the affordability preview is inherently usable in all pre-existing functions instead of introducing new functions.

Contains a few perf and refactor changes. But primarily:

  • Implements a new affordability preview system which is based on strategically placed update calls to skill_container while flipping a Boolean inside actor. This allows modders to check that an actor is previewing by accessing that Boolean from anywhere.
  • Moves the older preview system to a conditional hook system to improve efficiency as no one should be using that anymore.

The meat of this PR is the singular feat commit so you may wanna look at the diff of that commit to understand how the new system works.

This is a massive improvement over the current Affordability Preview system we have in MSU which I implemented in #88. That system is convoluted to work with from the user's perspective and is also limited in certain aspects. The new system is far more intuitive and in fact covers some edge cases which the old system failed in.

Old System (the one this PR deprecates):

  • Basically requires you to use modifyPreviewField and modifyPreviewProperty functions from inside a skill's onAffordablePreview function. The parameters of those functions are convoluted to work with.
  • The system calculates the overall change by first "undoing" the change from the skill in its onUpdate, onAfterUpdate, and executeScheduledChanges functions and then applies the new change.
  • A major limitation of this system is that the changes are applied at the end, so during the affordability preview function you don't have access to the values of other skills which would be in the regular update order by the time this skill's function comes up.

New System:

  • Basically any function can check for the actor's previewing state and therefore we can do a lot of powerful things. This allows directly checking for previewing within the onUpdate, onAfterUpdate and even any other function.
  • This makes the system very straightforward.
  • On the back end the system achieves this by strategically placing extra updates of the skill_container while flipping a Boolean in actor to switch between previewing and regular updates. This is probably less "efficient" than the old system but honestly this is better and I wish I had done it this way the first time around.

Example:
Let's say I have a skill which after at least 2 tiles reduces the AP cost of all attacks by 1. But this effect expires when you use any skill.

Old System usage:

function onAfterUpdate( _properties )
{
	if (this.getContainer().getActor().getTile().getDistanceTo(this.m.StartingTile) >= 2)
	{
		foreach (skill in this.getContainer().getAllSkillsOfType(::Const.SkillType.Active))
		{
			if (skill.isAttack() && skill.m.ActionPointCost > 1) // Notice we only want to decrease the AP cost if it is 2 or more
				skill.m.ActionPointCost -= 1;
		}
	}
}

function onAffordablePreview( _skill, _movementTile )
{
	// The character is previewing the usage of a skill, so we want to remove the AP cost reduction
	if (_skill != null)
	{
		foreach (skill in this.getContainer().getAllSkillsOfType(::Const.SkillType.Active))
		{			
			this.modifyPreviewField(skill, "ActionPointCost", 0, false);
		}
	}
	// The character is previewing a movement, so we want to apply the AP cost reduction if applicable
	else if (_movementTile != null)
	{
		// If we have already traveled at least 2 tiles this turn, we don't want to reduce the AP cost further
		if (this.getContainer().getActor().getTile().getDistanceTo(this.m.StartingTile) >= 2)
			return;

		if (_movementTile.getDistanceTo(this.getContainer().getActor().getTile()) >= 2)
		{
			foreach (skill in this.getContainer().getAllSkillsOfType(::Const.SkillType.Active))
			{	
				// Notice there is no way for us to first check here if the skill's AP cost 		
				// is actually 2 or more at this point in the update cycle, because this onAffordablePreview function
				// doesn't work like that
			if (skill.isAttack())
				this.modifyPreviewField(skill, "ActionPointCost", -1 , false);
			}
		}
	}
}

New System:

function onAfterUpdate( _properties )
{
	local actor = this.getContainer().getActor();
	local isValid = false;
	if (actor.isPreviewing())
	{
		isValid = actor.getPreviewMovement() != null && actor.getPreviewMovement().End.getDistanceTo(this.m.StartingTile) >= 2;
	}
	else
	{
		isValid = actor.getTile().getDistanceTo(this.m.StartingTile) >= 2;
	}

	if (isValid)
	{
		foreach (skill in this.getContainer().getAllSkillsOfType(::Const.SkillType.Active))
		{
			if (skill.isAttack() && skill.m.ActionPointCost > 1) // Notice we only want to decrease the AP cost if it is 2 or more
				skill.m.ActionPointCost -= 1;
		}
	}
}

Help needed:
One thing that I need Taro/Enduriel to improve in this system is that if the affordability preview would make a skill that is currently unaffordable affordable again, then we need to convey this information somehow. Currently, that skill's icon stays black&white because the vanilla affordability preview system only considers the case of currently affordable skills potentially becoming unaffordable and hence puts a "prohibited" icon on them. It does not expect currently unaffordable skills to become affordable. An idea for this case could be to put a green check mark on such skills to counter the red prohibited sign.

Relevant functions for achieving this are:

// in `turnsequencebar_module.js`:
TacticalScreenTurnSequenceBarModule.prototype.addSkillToList
TacticalScreenTurnSequenceBarModule.prototype.updateEntitySkillsPreview

// in `turn_sequence_bar.nut:`
setActiveEntityCostsPreview
resetActiveEntityCostsPreview

LordMidas added 8 commits May 4, 2024 00:31
Instead of having it in every skill. This should be more memory efficient.
- This allows directly modifying fields/properties inside the onUpdate and onAfterUpdate functions for the preview case.
- Is extensible automatically to all functions e.g. is usable within onUpdate, onAfterUpdate, isUsable etc.
This improves performance by hooking only the relevant skills which may still be using the older deprecated system instead of doing a full pseudo-update cycle on all skills. It leverages the fact that the newer system already does an update during preview.
LordMidas added 5 commits May 24, 2024 14:19
Otherwise the vanilla preview system completely breaks down (i.e. doesn't even show selected skill or preview fatigue or etc.) while a skill is being previewed. This happens because we do skill_container.update calls during the setActiveEntityCostsPreview in turn_sequence_bar and the update function calls setDirty which forces the actor's UI to update. This somehow causes some conflicts.
The entire point of the switcheroo on JSHandle is so that the original function is called before our skill container event (onAffordablePreview) so that the values set by the original function happen before our event.
Because it was getting reset during the skill_container.update call in setActiveEntityCostsPreview.
So that in the cost string of skill tooltips the color of the property (e.g. Action points or Fatigue) which will make a skill unaffordable will be properly colored red.
@LordMidas
Copy link
Member Author

Postponed as I am going to first implement, test and polish this system over at the Modular Vanilla mod.

@LordMidas LordMidas added the postponed Something to work on eventually, but not now label Aug 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
postponed Something to work on eventually, but not now
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant