In which we read a lot of code, and try a lot of things, to little effect.
Test Every Day
Goal: Test everything in PlayerEffects that actually does something
As we found out previously, not all of the effects can be imposed on a player by adding to the
PlayerEffects table. So let’s dig into the server and see what actually has an impact:
void CharacterEffectEvent(object sender, System.Timers.ElapsedEventArgs e)
{
if (!this.target.IsPC || this.target.PCState == Globals.ePlayerState.PLAYING)
{
if (this.duration > 0)
{
this.duration--;
}
try
{
if (this.duration == 0)
{
if (this.effectType == EffectType.Hide_In_Shadows)
{
if (this.caster != null)
{
if (this.caster.IsPC)
{
if (this.caster.IsHidden)
{
Map.checkHiddenStatus(this.caster);
}
if (!this.caster.IsHidden)
{
this.effectTimer.Stop();
this.StopCharacterEffect();
}
}
}
}
else
{
this.effectTimer.Stop();
this.StopCharacterEffect();
}
}
else
{
switch (this.effectType)
{
case EffectType.Balm:
Effect.DoBalmEffect(this.target, this);
break;
}
}
}
catch (Exception ex)
{
this.duration = 1;
Utils.LogException(ex);
}
}
}
Which is a lot of lines but not much action (full disclosure: I strongly prefer
K&R style braces over the Allman style
used in this code). Currently concerned with DB-driven effects (where the caster doesn’t exist), we can boil
this down to:
The duration is decremented each round.
If duration is zero, the effect is stopped unless it is Hide_In_Shadows.
If the duration is not zero, the Balm effect occurs.
At first glance, it looks like this: heals and consumes half of the remaining effectAmount each
turn, until either a) the character is fully healed, b) the duration has ended, or c) the
effectAmount has diminished to zero; and then fully heals the character anyway?
But we know from CharacterEffectEvent that this is only called when duration is non-zero, and
duration is only decremented when above zero, so we have no chance of getting here with a duration
of zero or less. (Assuming an effect is not created with a zero or negative duration.)
And the effect amount is diminished by half its value truncated to an int. As long as it started
out positive, it’ll never reach zero. At one, it will stay at one, healing zero hits per turn.
So the tripartite conditional in DoBalmEffect is probably historical in origin, and doesn’t
actually cause the issues we were worried about.
Reality: Trying to Figure Out One Test Takes Forever
After a little trial and error, here’s a test that passes:
Scenario: Balm effect fades correctly when limited by duration
Given I use the "minimal" database
And I add player and character "TestBalm01"And I set the character's max HP to "30"
And I set the character's current HP to "1"And I give the character a balm effect of "20"for"3" turns
And the server is started
When I log on as "TestBalm01"And I enter the game
And after "0" turns I have a current HP of "16"And after "1" turns I have a current HP of "18"And after "1" turns I have a current HP of "20"And after "1" turns I have a current HP of "22"And after "1" turns I have a current HP of "22"And after "1" turns I have a current HP of "23"And after "1" turns I have a current HP of "23"And after "1" turns I have a current HP of "23"And after "1" turns I have a current HP of "24"
That seems a little counter-intuitive. To make some sense of it, we need to recall that the effect
triggers immediately on being created, and to know about the ThirdRoundEvent:
#region Timer Related
protectedvoid ThirdRoundEvent(object obj, ElapsedEventArgs e)
{
if (this.IsPC && this.PCState != Globals.ePlayerState.PLAYING)
return;
if (!this.IsDead)
{
//TODO: modify stats gain to reflect additional stats due to temporary stat effects
if (this.Hits < this.HitsFull) // gain a point of health
{
this.Hits++;
this.updateHits = true;
A whole set of things happen every third round the character is in the game, including one point
of healing.
So let’s attempt to annotate that test:
And I enter the game
# 1 + 10 (initial effect) = 11 (amount now 10, duration now 3)
And after "0" turns I have a current HP of "16"
# 11 + 5 (effect on initial turn) = 16 (amount now 5, duration now 2)
And after "1" turns I have a current HP of "18"
# 16 + 2 (effect) = 18 (amount now 3, duration now 1)
And after "1" turns I have a current HP of "20"
# 18 + 1 (effect) = 19 (amount now 2, duration now 0)
# 19 + 1 (third round healing) = 20
And after "1" turns I have a current HP of "22"
# ???
It makes sense up to the round where I suddenly have 22 HP. I’ll have to actually add some debug to
figure this one out.
9/30/2016 0:00:06 AM: {Unknown} Round 0: Character TestBalm01_name receives balm effect. effectAmount 20, duration 3.
9/30/2016 0:00:06 AM: {Unknown} Round 0: Character TestBalm01_name received balm effect. Healed 10 HP to make current HP 11, effectAmount now 10.
9/30/2016 0:00:06 AM: {Unknown} Round 0: Character TestBalm01_name receives balm effect. effectAmount 10, duration 3.
9/30/2016 0:00:06 AM: {Unknown} Round 0: Character TestBalm01_name received balm effect. Healed 5 HP to make current HP 16, effectAmount now 5.
9/30/2016 0:00:11 AM: {Unknown} Round 1: Character TestBalm01_name receives balm effect. effectAmount 5, duration 2.
9/30/2016 0:00:11 AM: {Unknown} Round 1: Character TestBalm01_name received balm effect. Healed 2 HP to make current HP 18, effectAmount now 3.
9/30/2016 0:00:16 AM: {Unknown} Round 2: Character TestBalm01_name receives balm effect. effectAmount 3, duration 1.
9/30/2016 0:00:16 AM: {Unknown} Round 2: Character TestBalm01_name received balm effect. Healed 1 HP to make current HP 19, effectAmount now 2.
9/30/2016 0:00:19 AM: {Unknown} Round 3: Character TestBalm01_name received ThirdRoundEvent healing, current HP now 20.
9/30/2016 0:00:34 AM: {Unknown} Round 6: Character TestBalm01_name received ThirdRoundEvent healing, current HP now 23.
9/30/2016 0:00:49 AM: {Unknown} Round 9: Character TestBalm01_name received ThirdRoundEvent healing, current HP now 24.
My expectations are confirmed, but there’s some extra healing going on that I don’t know about. I
looked through the code but couldn’t see what was going on. In a final desperate effort I added
code to print out System.Environment.StackTrace every time the character’s HP changed.
9/30/2016 0:12:23 AM: {Unknown} Round 3: Character TestBalm01_name had their Hits set to 22 (was 20).
9/30/2016 0:12:23 AM: {Unknown} Stack trace: at System.Environment.get_StackTrace()
at DragonsSpine.Character.set_Hits(Int32 value) in
k:\301days\Code\drag-spin-exp\DragonsSpine\GameObjects\GameLiving\Character\Character.cs:line 1000
at DragonsSpine.Effect.StopCharacterEffect() in
k:\301days\Code\drag-spin-exp\DragonsSpine\GameSystems\Effects\Effect.cs:line 555
and there it was. I had somehow missed what was going on in StopCharacterEffect; once the
duration has elapsed, there’s a kind of “catch-up” clause that applies the remaining amount:
case EffectType.Balm: // healing over time
if (this.effectAmount > 0)
{
this.target.Hits += this.effectAmount;
if (this.target.Hits > this.target.HitsFull)
this.target.Hits = this.target.HitsFull;
}
break;
default:
break;
}
I’ll add some debug output there just to make sure:
9/30/2016 0:28:03 AM: {Unknown} Round 0: Character TestBalm01_name receives balm effect. effectAmount 20, duration 3.
9/30/2016 0:28:03 AM: {Unknown} Round 0: Character TestBalm01_name received balm effect. Healed 10 HP to make current HP 11, effectAmount now 10.
9/30/2016 0:28:03 AM: {Unknown} Round 0: Character TestBalm01_name receives balm effect. effectAmount 10, duration 3.
9/30/2016 0:28:03 AM: {Unknown} Round 0: Character TestBalm01_name received balm effect. Healed 5 HP to make current HP 16, effectAmount now 5.
9/30/2016 0:28:08 AM: {Unknown} Round 1: Character TestBalm01_name receives balm effect. effectAmount 5, duration 2.
9/30/2016 0:28:08 AM: {Unknown} Round 1: Character TestBalm01_name received balm effect. Healed 2 HP to make current HP 18, effectAmount now 3.
9/30/2016 0:28:13 AM: {Unknown} Round 2: Character TestBalm01_name receives balm effect. effectAmount 3, duration 1.
9/30/2016 0:28:13 AM: {Unknown} Round 2: Character TestBalm01_name received balm effect. Healed 1 HP to make current HP 19, effectAmount now 2.
9/30/2016 0:28:16 AM: {Unknown} Round 3: Character TestBalm01_name received ThirdRoundEvent healing, current HP now 20.
9/30/2016 0:28:18 AM: {Unknown} Round 3: Character TestBalm01_name received final balm effect. Healed 2 HP to make current HP 22.
9/30/2016 0:28:31 AM: {Unknown} Round 6: Character TestBalm01_name received ThirdRoundEvent healing, current HP now 23.
9/30/2016 0:28:46 AM: {Unknown} Round 9: Character TestBalm01_name received ThirdRoundEvent healing, current HP now 24.
Scenario: Balm effect processes correctly when limited by duration
Given I use the "minimal" database
And I add player and character "TestBalm01"
And I set the character's max HP to "30"
And I set the character's current HP to "1"
And I give the character a balm effect of "20" for "3" turns
And the server is started
When I log on as "TestBalm01"
And I enter the game
# 1 + 10 (initial effect) = 11 (amount now 10, duration now 3)And after "0" turns I have a current HP of "16"
# 11 + 5 (effect on initial turn) = 16 (amount now 5, duration now 2)And after "1" turns I have a current HP of "18"
# 16 + 2 (effect) = 18 (amount now 3, duration now 1)And after "1" turns I have a current HP of "20"
# 18 + 1 (effect) = 19 (amount now 2, duration now 0) # 19 + 1 (third round healing) = 20And after "1" turns I have a current HP of "22"
# 20 + 2 (effect) = 22 (effect completed)And after "1" turns I have a current HP of "22"
And after "1" turns I have a current HP of "23"
# 22 + 1 (third round healing) = 23
And it even passes. One more to make sure we understand how this logic works:
Scenario: Balm effect processes correctly when limited by effect
Given I use the "minimal" database
And I add player and character "TestBalm02"
And I set the character's max HP to "30"
And I set the character's current HP to "1"
And I give the character a balm effect of "10" for "4" turns
And the server is started
When I log on as "TestBalm02"
And I enter the game
# 1 + 5 (initial effect) = 6 (amount now 5, duration now 4)And after "0" turns I have a current HP of "8"
# 6 + 2 (effect on initial turn) = 8 (amount now 3, duration now 3)And after "1" turns I have a current HP of "9"
# 8 + 1 (effect) = 9 (amount now 2, duration now 2)And after "1" turns I have a current HP of "11"
# 9 + 1 (effect) = 10 (amount now 1, duration now 1) # 10 + 1 (third round healing) = 11And after "1" turns I have a current HP of "11"
# 11 + 0 (effect) = 11 (amount still 1, duration now 0)And after "1" turns I have a current HP of "12"
# 11 + 1 (effect) = 12 (effect completed)And after "1" turns I have a current HP of "13"
# 12 + 1 (third round healing) = 13
Ok, that’s one effect down, many to go. Unfortunately database connection issues keep getting in the way of running through
the complete test suite. I’ll need to tackle that once and for all. Tomorrow.