Spell Interrption:

For ideas on how to make Second Age a better shard. Can it get any better? Maybe.
Forum rules
Posts in this forum are expected to be constructive, realistic and civil. Inflamatory or off topic posts will be removed.
Hiram
UOSA Donor!!
UOSA Donor!!
Posts: 84
Joined: Mon Jun 08, 2009 4:06 pm

Re: Spell Interrption:

Post by Hiram »

marmalade wrote:at the risk of sounding like im repeating myself..

can somebody post the actual spell interruption formula?

EDIT: nevermind, i'll try downloading the code myself see if i can make any sense of it ;s
I have used the formula to make a calculator here:

http://mhk.puddleboy.com/chance_to_disrupt.php

User avatar
Derrick
Posts: 9004
Joined: Thu Dec 13, 2007 7:49 pm
Location: Cove
Contact:

Re: Spell Interrption:

Post by Derrick »

Mephistopheles wrote:Making threads like this is like stroking your own flag for comfort. Did you really need the verbal support from Hemperor? Why even bother talking about this at all when it seems that any dissenting logic isn't even considered? Why bother going through the motions of making such post-structuralist responses? Nobody cares enough about this in the first place Faust & Co. It's really inviting when you simply ignore a person's easy request too.

More super secret 1337 demo code-vomit please.
This thread was a split from the poison thread. And there is nothing secret about the demo code, it's 100% public, however we're not going to post it ad-hoc all over the forums as discussed in other threads today.
Image
"The text in this article or section may be incoherent or very hard to understand, and should be reworded if the intended meaning can be determined."

User avatar
marmalade
Posts: 1531
Joined: Sun Apr 19, 2009 5:02 pm

Re: Spell Interrption:

Post by marmalade »

Hiram wrote:
marmalade wrote:at the risk of sounding like im repeating myself..

can somebody post the actual spell interruption formula?

EDIT: nevermind, i'll try downloading the code myself see if i can make any sense of it ;s
I have used the formula to make a calculator here:

http://mhk.puddleboy.com/chance_to_disrupt.php
thank you very much. very useful indeed.
Image

Anarcho
Second Age Staff
Second Age Staff
Posts: 350
Joined: Fri Nov 29, 2013 8:35 pm

Re: Spell Interrption:

Post by Anarcho »

This response is in tandem with this thread as well.

This has bugged me for some time, a couple years ago I realised that our interrupt code does not accurately reflect the demo formula.

The demo formula is written in such a way that their intent is clear: Magery level, spell circle cast, and damage taken should all be taken into account as to whether a spell should be interrupted.

There is an error in their math (a simple one) which results in any "hit" event causing the spell to interrupt, debuffs included.

I'm stating this as I can not find the direct reasoning behind our changes, Derrick can't recall, and this topic as well as the one listed above lead on with the presumption that we had (and have) a 100% representation of the demo formula.

In February 2009, a small (and obvious) fix was made to our interrupt formula to make it work as it would appear to intend to.

I've spent a lot of time looking for any solid indication as to which it should be, really any record from OSI of "Harm" spell interrupting 100% of the time would be concrete information in my books that our current approach is not correct (and no reason to defer at that point from the exact code in the demo), but I have come up empty so far.

This would also nullify the need for a double check on interrupt which was put in Summer of 2009 and allowed weapons to interrupt much more (although this still may be correct, as per double bandage slipping).

Just reviving this old discussion to see if we can bring any new insight or information to the table.

User avatar
Lambo
UOSA Donor!!
UOSA Donor!!
Posts: 745
Joined: Mon Jan 10, 2011 5:28 am

Re: Spell Interrption:

Post by Lambo »

Anarcho wrote:This response is in tandem with this thread as well.

This has bugged me for some time, a couple years ago I realised that our interrupt code does not accurately reflect the demo formula.

The demo formula is written in such a way that their intent is clear: Magery level, spell circle cast, and damage taken should all be taken into account as to whether a spell should be interrupted.

There is an error in their math (a simple one) which results in any "hit" event causing the spell to interrupt, debuffs included.

I'm stating this as I can not find the direct reasoning behind our changes, Derrick can't recall, and this topic as well as the one listed above lead on with the presumption that we had (and have) a 100% representation of the demo formula.

In February 2009, a small (and obvious) fix was made to our interrupt formula to make it work as it would appear to intend to.

I've spent a lot of time looking for any solid indication as to which it should be, really any record from OSI of "Harm" spell interrupting 100% of the time would be concrete information in my books that our current approach is not correct (and no reason to defer at that point from the exact code in the demo), but I have come up empty so far.

This would also nullify the need for a double check on interrupt which was put in Summer of 2009 and allowed weapons to interrupt much more (although this still may be correct, as per double bandage slipping).

Just reviving this old discussion to see if we can bring any new insight or information to the table.

At work, will try to do some research later. Regardless of accuracy I believe this would be an extremely welcome and refreshing change.
Buying Charged Hallys/Bards
Buying +20 Power and above Hallys
Buying Reflect Items 30 Charges and above

Roser
UOSA Subscriber!
UOSA Subscriber!
Posts: 3367
Joined: Sat Jan 30, 2010 12:01 am
Location: In your tree house with binoculars
Contact:

Re: Spell Interrption:

Post by Roser »

It's my understanding that harm is supposed to be a physical damage spell, and physical damage interrupts spell casting 100% of the time. Armor currently effects the damage that harm can do in the same way physical damage does yet the spell is still seen as magic damage.

I notice in Boom's event some of the highly magic resistant mobs are unaffected by harm in the way a full invul plate armor character would be yet they wear no armor.

So it seems that harm has some properties of a magical spell and some properties as a physical damage. Should it be some kind of a hybrid attack, should it be physical or should it be magical, and should magic resist play a role the way it does now?
Image

Anarcho
Second Age Staff
Second Age Staff
Posts: 350
Joined: Fri Nov 29, 2013 8:35 pm

Re: Spell Interrption:

Post by Anarcho »

I should have read this thread more carefully as I just spent some time doing exactly what Batlin outlines here.

tl;dr: Spell interrupts are checked twice in the demo (before and after halving), whilst weapons are only checked once (after halving)

It seems the important conversation dropped off after that point, as UOSA circumvented it's weapon interrupting issue by doing the double check on weapons as well.

Without the "math fix" to what the demo formula has that is implemented on UOSA, weapon hits would interrupt every single time.

Just some thoughts. It is impossible to know what OSI did to the interrupt code after it was implemented (if anything), all we have is this:
10/1/98 wrote:Spell casting interruption should now be correct. In the last upadate, a change was made to it which we have determined was not well-balanced. It has therefore been reverted back out.
Which suggests that an undocumented change was made and then reverted.

One thing to note is that with the demo formula debuffs will interrupt every single time. Some documented information regarding spells and/or weapons interrupting every single time would be of some assurance in moving this forward.

SighelmofWyrmgard
Posts: 881
Joined: Thu May 20, 2010 5:34 pm

Re: Spell Interrption:

Post by SighelmofWyrmgard »

I would like to interject two things: one is a publish note that may be of some relevance, and the other is simply a question.

The publish note: from Publish 1, Nov. 23/99, "Veterinary and Healing Changes", item 5 of 6,
The issue with double finger slips while healing when hit with a magical attack will be resolved. You will now only slip once.
Since "double-bandage-slipping" had been mentioned in connection to the interruption mechanics, I thought I'd point this out.

My question, regarding the interruption Mechanics Batlin said,
There is no difference made between monsters and players.
Should I take that to confirm that spellcasting monsters do indeed suffer spell interruption, and that my perceived observations to that effect were not only-my-imagination, after all?

SS
SighelmofWyrmgard wrote:
uosa44 wrote:For sale, by original owner:
1 Human Brain, never been used, only slightly damaged, still in original packaging.
$1, obo
FTFY.

SS
uosa44 wrote:The inability for this person to respond in such a crazy manner proves my point.

Kaivan
UOSA Donor!!
UOSA Donor!!
Posts: 2923
Joined: Wed Aug 13, 2008 11:07 pm

Re: Spell Interrption:

Post by Kaivan »

If you're interested, I can provide a detailed set of information regarding what is known about spell interruption in the demo when time allows. I suspect that what is in place on UOSA is based on very old information that hasn't been properly updated
UOSA Historian and former staff member: August 11, 2008 - June 19, 2016

Useful links for researching T2A Mechanics

Stratics - UO Latest Updates - Newsgroup 1 - Noctalis - UO98.org

Roser
UOSA Subscriber!
UOSA Subscriber!
Posts: 3367
Joined: Sat Jan 30, 2010 12:01 am
Location: In your tree house with binoculars
Contact:

Re: Spell Interrption:

Post by Roser »

Interested!
Image

Anarcho
Second Age Staff
Second Age Staff
Posts: 350
Joined: Fri Nov 29, 2013 8:35 pm

Re: Spell Interrption:

Post by Anarcho »

Kaivan wrote:If you're interested, I can provide a detailed set of information regarding what is known about spell interruption in the demo when time allows. I suspect that what is in place on UOSA is based on very old information that hasn't been properly updated
Of course, that is why I have revived this topic - mainly to lay out what we do and don't know, as a lot seems to have been forgotten or went undocumented.

SighelmofWyrmgard
Posts: 881
Joined: Thu May 20, 2010 5:34 pm

Re: Spell Interrption:

Post by SighelmofWyrmgard »

Rose wrote:Interested!
Yes, me too, please.

SS
SighelmofWyrmgard wrote:
uosa44 wrote:For sale, by original owner:
1 Human Brain, never been used, only slightly damaged, still in original packaging.
$1, obo
FTFY.

SS
uosa44 wrote:The inability for this person to respond in such a crazy manner proves my point.

Kaivan
UOSA Donor!!
UOSA Donor!!
Posts: 2923
Joined: Wed Aug 13, 2008 11:07 pm

Re: Spell Interrption:

Post by Kaivan »

Ok. I'll review what my best knowledge was at the time that most of these changes took place on UOSA, and the things that were discovered since then regarding the behavior of disrupts on the demo. So far as I know, these discoveries were never introduced into the UOSA mechanics in any form, and the code that we utilize is an approximation of what we thought was the intended effect of the mechanics at the time.

First, to review what was known at the time, there are 4 scripts for handling the casting of any spell: the specific script for casting the spell, the base script for executing the effect of the spell, the spelskil.c script (where many checks for casting a spell such as checking for whether you're casting another spell, whether your hands are empty, and whether you have the proper mana/reagents for a spell are done as well as calculating the actual spell damage and chance to resist a spell), and the casting.c script which handles the freezing/unfreezing of the caster, and most importantly - disruptions. The relevant code for the casting script is as follows, which had been recently successfully decompiled by Batlin earlier in the year back in 2009:

Code: Select all

object Q5UY;

#on creation()
{
  Q5UY = getObjVar(this, "spellObj");
  removeObjVar(this, "spellObj");
  setMobFlag(this, 0x02, 0x01);
  return(0x01);
}

#on washit(object attacker, integer damamt)
{
  integer Q4IB = (Q42S(Q5UY) - 0x01) * 0x03E8 / 0x07;
  Q4IB = Q4IB + damamt * 0x14;
  integer Q5NC = getSkillSuccessChance(this, 0x19, Q4IB, 0x28) - random(0x00, 0x03E7);
  if(Q5NC <= 0x00)
  {
    systemMessage(this, "Your concentration is disturbed, thus ruining thy spell.");
    Q4AR(this);
    return(0x01);
  }
  return(0x01);
}
From the above code for the #on event() functions (formally called triggers in the scripts), Batlin discovered that whenever a relevant event was detected in the server core it would send out the proper trigger to the scripts attached to the relevant objects to handle the occurrence of that event. It was later discovered that in the event of a spell causing damage, which would trigger the "was hit" event, a bug existed in the code for sending out that trigger which caused the trigger to be sent out twice for spell damage, once before and once after the damage had been properly halved. From this broad understanding, we were interested in how the function from above is actually calculated in order to understand the chance to be disrupted in any given scenario.

From the above event, we can see that the general code seems pretty clear. Q4IB is first calculated via this formula:

Code: Select all

Q4IB = (Spell circle - 1) * 1000 / 7
Q4IB then has 20 times the amount of damage done added to itself, and then Q5NC is calculated via a getSkillSuccessChance check against magery with the Q4IB being used in the check. If the resulting value for getSkillSuccessChance minus a random value from 0 to 999 turned out to be less than 1, then the spell was disturbed.

However, at the time, a problem existed: We didn't know what the getSkillSuccessChance calculation actually was. Back then, we really only had access to the scripts in that we could read through them, and we did not have any ability to inject our own code into the demo, nor had Batlin published any of his incredibly useful work on decompiling any of the core functions of the demo. As a result, we had to set out to build our own equation that approximated what we thought was the best representation of the intent of the January 1998 patch note and the available information. We knew that reports from that time and the era indicated that it was very easy to disrupt a spell, but we recognized that the patch note indicated that there was a chance to be interrupted based on the spell circle cast, and the magery of the caster. Thus, Derrick set out to create his own equation that allowed players to be disrupted to a very high degree, while allowing them to continue to cast in some cases even when hit by a spell with a double check for disrupts. While I am not privy to the equation that he came up with, it is obvious that any equation which is crafted to occasionally allow a cast to continue despite a double check with one check twice as hard as the other would not reliably disrupt on a single check (for half damage IIRC). This is likely why the same double check was put into place for melee damage, as there was no indication that a difference existed between the two.

That brings us up as far as I can track regarding the changes to spell disruption, and likely covers what is in our code. However, this particular implementation isn't actually correct, and so far as I know, hasn't been revisited since that time.

Looking back at the the demo casting script, we see that the washit event utilizes a simple equation for calculating the input value to getSkillSuccessChance, but we didn't know what was done with that value. In early 2011, Batlin gave me the relevant code the getSkillSuccessChance formula which was part of a skill simulator system that he was working on. At roughly the same time, we got the rudimentary ability to inject new code into the demo scripts, allowing us to test certain things. Out of an interest in exploring this issue, I wrote in some output lines to see what the actual input variables to the getSkillSuccessChance formula actually were on the demo. Thus, the washit event was modified to be as follows:

Code: Select all

on washit(object attacker, integer damamt)
{
  systemMessage(this, "Damage taken: " + damamt);
  integer Q4IB = (Q42S(Q5UY) - 0x01) * 0x03E8 / 0x07;
  systemMessage(this, "Circle difficulty: " + Q4IB);
  Q4IB = Q4IB + damamt * 0x14;
  systemMessage(this, "Total difficulty: " + Q4IB);
  integer Q5NC = getSkillSuccessChance(this, 0x19, Q4IB, 0x28) - random(0x00, 0x03E7);
  systemMessage(this, "Success chance: " + getSkillSuccessChance(this, 0x19, Q4IB, 0x28));
  if(Q5NC <= 0x00)
  {
    systemMessage(this, "Your concentration is disturbed, thus ruining thy spell.");
    Q4AR(this);
    return(0x01);
  }
  return(0x01);
}
The code for the getSkillSuccessChance equation is as follows:

Code: Select all

(this->GetSkillLevelReal(SkillNumber, 0) - Diff) * 100 / Focus) + 500;
With Diff being equal to Q4IB, Focus being equal to the the last value passed in when getSkillSuccessChance is called, and the skill level being on a scale of 0 to 1000.

When tested on the demo itself, the following values appeared when hit by a fire field while attempting to cast blade spirits with 100.0 magery:
casting bug.jpg
casting bug.jpg (103.89 KiB) Viewed 5268 times
As you can see from the screenshot, the total difficulty for casting the spell is astronomically high at 11420, while the damage taken is actually 0 due to standing in town. We also see that the difficulty for the circle is 571, which should output a value of 571 for the overall difficulty, so what's the problem? As it turns out, the part of the equation here...

Code: Select all

Q4IB = Q4IB + damamt * 0x14;
reveals a bug with the parsing engine for equations in the scripts. Specifically - order of operations is not properly followed.

While the demo does properly parse things like parenthesis, and it properly calculates the values within parenthesis first before evaluating terms outside of parenthesis, if a set of terms are on the same level, then the equation is simply parsed from left to right. The result is that for all disrupt checks, the spell circle difficulty is added to the damage, and then multiplied by 20. This results in virtually every disrupt check producing incredibly huge numbers that will always result in a disturbed spell. The one exception to this is first circle, which has a very low chance be disrupted except in the most extreme cases.

To run some numbers, let's take an attempt to cast second circle spell while taking 0 damage, due to being in town, by a caster with 100 magery. The equation, as parsed by the demo will be as follows:

Code: Select all

Q4IB = 1000 / 7 = 142
Q4IB = 142 + 0 * 20 = 2840
Inputting this value into getSkillSuccessChance (where order of operations is followed properly), we get the following output:

Code: Select all

(1000 - 2840) * 100 / 40 + 500 = -4100
Which is filtered to 0 via the rest of the core function for being a very negative number.

In essence, we can see that when a player is hit, even for 0 damage, that if they are casting even a second circle spell, they will always be disturbed regardless of their magery skill. On the other hand, if a player is casting a first circle spell, we will get very different results. Running some number again, let's assume that a player is casting a first circle spell and is hit for 50 damage. The input difficulty will be calculated as follows:

Code: Select all

Q4IB = 0 / 7 = 0
Q4IB = 0 + 50 * 20 = 1000
Inputting into getSkillSuccessChance, we get the following:

Code: Select all

(1000 - 1000) * 100 / 40 + 500 = 500
Thus, even at rather high numbers, first circle spells are extremely difficult to disrupt. Combined with the fast cast time, and the fact that there is only 1 tick where the spell is even vulnerable to being disrupted makes first circle spells virtually uninterruptable.

With an understanding of the bug itself, the obvious fix is to add in parenthesis to cause the equation to conform to the proper order of operations. However, by doing so, the results of the equation are radically altered. As an example, suppose a player with 100 magery is casting a 6th circle spell and is hit for 20 damage in an attempt to disturb the spell. The difficulty would be calculated as follows:

Code: Select all

Q4IB = 5000 / 7 = 714
Q4IB = 714 + (20 * 20) = 1114
Inputting this into getSkillSuccessChance, we get the following:

Code: Select all

(1000 - 1114) * 100 / 40 + 500 = 215
As you can see, despite a pretty reliable amount of damage being done, there is still a reasonable chance the the spell will be cast (21.5%). The chance to disturb gets far worse for lower circle spells, with spells below 5th circle being impossible to disturb at low damage values (>18 damage for 4th circle at GM Magery, >25 for 3rd, and >32 for 2nd). It is likely that this error was seen, corrected, and later reverted out in a later patch which documents the reversion to "correct" spell disruption.

So that covers the relevant part for disturbing a spell. That is: on the demo, any spell beyond a first circle spell will always be disrupted at all skill levels no matter the damage done. However, there is more to the problem than that. With 100% effective disruption, we have to consider our current design for disrupting a spell where a caster must wait out the rest of the cast time before being allowed to attempt to cast another spell. Referring to the above screenshot of the demo, you'll notice that the last line in that screenshot is the message "You are already casting a spell.". This was triggered by attempting to cast a spell immediately after being disturbed, and actually represents a second bug related to spell casting and disruption that was likely fixed with the September 1998 patch which attempted to fix this class of bug. The bug behaves as follows and will connect code from a few places:

If a spell is disturbed in the demo, the following piece of code executes:

Code: Select all

  if(Q5NC <= 0x00)
  {
    systemMessage(this, "Your concentration is disturbed, thus ruining thy spell.");
    Q4AR(this);
    return(0x01);
  }
From here, we can see that a function, Q4AR, is called. This function, which is in the casting script, is as follows:

Code: Select all

void Q4AR(object it)
{
  setMobFlag(this, 0x02, 0x00);
  detachScript(it, "casting");
  return();
}
This function is simply meant to end the casting process, by detaching the casting script and unfreezing the caster. However, this function is used in a generic fashion both for the casting process being disturbed, and for the casting process ending normally.

This is relevant because a function in the spelskil script, Q4M9, acts as the set up function for beginning the casting process of a spell. The code of this function is as follows:

Code: Select all

void Q4M9(object spell, object caster)
{
  if(Q4YT(caster) || Q507(caster))
  {
    systemMessage(caster, "You are already casting a spell.");
    return();
  }
  if(getMobFlag(caster, 0x02))
  {
    systemMessage(caster, "You can not cast a spell while frozen.");
    return();
  }
  integer Q5UX = Q4T2(spell);
  integer Q5US = Q4SY(Q5UX);
  integer Q55B = Q4SX(Q5US);
  if(!Q49Q(caster, Q55B))
  {
    return();
  }
  setObjVar(caster, "spellObj", spell);
  attachScript(caster, "casting");
  integer Q4H9 = Q4SV(Q5US, Q5UX);
  shortcallback(caster, Q4H9, 0x80);
  shortcallback(caster, 0x00, 0x82);
  bark(caster, Q4T5(Q4T2(spell)));
  return();
}
This function, which is the first function called when attempting to cast a spell, first performs several checks to see if a player can begin casting a spell, including seeing whether a player is already casting a spell, whether they're frozen, whether their hands are empty, and whether they do or don't have the required reagents and mana to cast the spell. If these checks are successful, the casting process is started, and the casting script is attached to the player for the duration of the casting time, which then freezes them until they are disrupted or complete the casting process. The relevant lines of code to achieve that are as follows:

Code: Select all

  attachScript(caster, "casting");
  integer Q4H9 = Q4SV(Q5US, Q5UX);
  shortcallback(caster, Q4H9, 0x80);
The final line, shortcallback, refers to the relevant piece of code for this bug found in the casting script, with the value Q4H9 referring to the number of ticks before this particular piece of code is triggered (based on the spell circle). The code for the actual callback found in the casting script is as follows:

Code: Select all

#on callback<0x80>()
{
  list Q5A8;
  appendToList(Q5A8, this);
  message(Q5UY, "castspell", Q5A8);
  Q4AR(this);
  return(0x00);
}
This piece of code ends the casting process, and prepares the spell to be cast by the caster, but notably, this code also calls the Q4AR function found above as the final piece of ending the casting script. This is notable, because of where this particular call to the function occurs, specifically within the callback trigger itself.

Looking back at function Q4M9, we see two functions are called at the beginning of the function, Q4YT and Q507. Function Q4YT is the important function here, as it checks to see if the person who is attempting to begin casting a spell is already in the middle of casting another spell. The code for Q4YT is as follows:

Code: Select all

integer Q4YT(object Q68S)
{
  if(hasCallback(Q68S, 0x80))
  {
    return(0x01);
  }
  return(0x00);
}
Here, we see a core function call, which simply looks to see if a callback with a specific ID number is already queued up for the caster. In this case, callback ID 0x80, which happens to be the callback ID for ending the casting process. This makes sense as a general barometer for whether someone is casting a spell, because the only time that they should have that callback is if they attempted to start casting a spell earlier. However, a problem does exist with this approach as it relates to a spell being disturbed.

Looking back up a bit to the piece of code that triggers when a spell is disturbed, we can see where a problem might occur in the overall casting process. To visualize this, we can set up some timelines of events for when a spell is cast and compare the sequence of events. The following is a timeline for a cast that starts and ends normally:
  • Player attempts to cast a spell.
  • Function Q4M9 checks to see if they can cast the spell (not casting, not targeting, reagents, mana, hands)
  • Function Q4M9 sets up the spell (attaches casting script, sets cast time, sets callbacks, words of power)
  • Casting script freezes character, and starts casting animation.
  • Cast time is completed, and callback 0x80 is triggered.
  • Callback 0x80 prepares spell to be cast by player.
  • Callback 0x80 calls function Q4AR.
  • Function Q4AR unfreezes caster and detaches casting script.
We can also set up a timeline to visualize what would happen if a player is disturbed when attempting to cast a spell:
  • Player attempts to cast a spell.
  • Function Q4M9 checks to see if they can cast the spell (not casting, not targeting, reagents, mana hands)
  • Function Q4M9 sets up the spell (attaches casting script, sets cast time, sets callbacks, words of power)
  • Casting script freeses character and starts casting animation.
  • Spell is disturbed after some number of ticks.
  • Casting script calls function Q4AR.
  • Function Q4AR unfreezes caster and detaches casting script.
  • Callback 0x80 attempts to fire and gracefully exits as no script with that callback ID is attached to the caster.
From the above procedure, we can see that callback 0x80 is left hanging to gracefully exit and do nothing if the spell is disturbed. However, if a player attempts to cast a spell immediately after being disturbed, then depending on how long left they had in the casting process, the following bug might occur:
  • Player attempts to cast a spell.
  • Function Q4M9 checks to see if they can cast the spell (not casting, not targeting, reagents, mana hands)
  • Function Q4M9 sets up the spell (attaches casting script, sets cast time, sets callbacks, words of power)
  • Casting script freeses character and starts casting animation.
  • Spell is disturbed after some number of ticks.
  • Casting script calls function Q4AR.
  • Function Q4AR unfreezes caster and detaches casting script.
    • Player immediately attempts to cast another spell.
    • Funtion Q4M9 checks to see if they cast the spell, and sees that they already have a callback for 0x80, cancelling the attempt with the system message "You are already casting a spell.".
  • Callback 0x80 attempts to fire and gracefully exits as no script with that callback ID is attached to the caster.
From the bolded text, we can see that when a player is disturbed, they cannot attempt to cast another spell, because function Q4M9 will see the leftover callback to 0x80 queued for the caster from the previous spell, and prevent them from casting the spell. This functionally makes a player have to wait until the rest of the casting time is done for their spell in order to start a new one, but causing them to do so is strictly a bug. This bug was likely fixed with the September 1998 patch note which states the following:
The "already casting" spell bug should not recur.
At the time, a large suite of different bugs would potentially cause a player to become glitched and stuck with a spell they couldn't cast, including targeting certain floor tiles (mostly carpet), targeting an innocent and cancelling the criminal action queue, targeting someone just as they moved off the tile, and thus "targeting" the ground where they stood, as well as this bug (and probably more). The assumption is that the generic wording of the bug fix was intended to cover these broad causes for the same bug, but there is no guarantee that this specific bug was indeed fixed. The only other relevant information is that no other documentation exists regarding later bug fixes to an "already casting" bug, and that on live OSI servers, circa 2011, it was possible to immediately attempt to begin casting a spell when disturbed.

That's pretty much it. I know that this post is extremely long and contains some relatively technical information, but it is important that this information is understood, both so you can present the information as best as possible given the current information, and that you can understand the implications of the changes.

Relevant to that decision making process is the effect that changing the disturb rates will have on combat. Specifically, since we do know that until UOR, each time a debuff was cast (even if it produced the "fizzle" animation), the spell effectively "hit" the target for 0 damage. With an accurate view of disturb rates, we know that this was a reliable strategy for disturbing players at the time of the demo, and that the few examples of in-era tactics where spells like weaken were reliably used to disturb opponents have a basis in fact. It is important to consider that if a change is made to disturb rates, then a change to whether a player does or doesn't need to wait out the cast time of a spell is equally important, as the disruption tactic will need an equalizer in terms of the player being disturbed. Without that change, which is backed up by the available evidence, disruptions via debuff tactics would have no reliable answer to them (e.g. zero chance to recall from a PK, etc.).

I hope this explanation has been informative.
UOSA Historian and former staff member: August 11, 2008 - June 19, 2016

Useful links for researching T2A Mechanics

Stratics - UO Latest Updates - Newsgroup 1 - Noctalis - UO98.org

SighelmofWyrmgard
Posts: 881
Joined: Thu May 20, 2010 5:34 pm

Re: Spell Interrption:

Post by SighelmofWyrmgard »

Wow, monster-post, Kaivan. Thanks: we asked for it ...

Forgive the following "stream-of-unconsciousness", I began writing while I was sill analysing; stuff in Italics is me "editing", but I kept all of it in so that you can follow my reasoning ...

For one thing, there's an algorithmic error in the interaction of Q4M9 and 0x80 when Q4AR is invoked due to casting-disruption: rather than Q4AR, the casting script should call 0x80 "and apply a disrupt flag" when there is a disruption event, and then 0x80 would call Q4AR as it should do, normally <- not required if Q4AR wipes all related functions/flags, which I bet it doesn't ... (at which time Q4AR exits all related scripts and resets all flags); the disrupt event is creating a "double exit" from the function Q4M9, leaving a dangling flag as an artifact, which is picked-up again by Q4M9, and that impasse persists until that original casting-time expires.

Now, this does not adequately explain to me why "disrupt Q4AR" doesn't wipe the casting-timer when it's invoked ... oh cripes: I bet Q4AR isn't written to wipe the casting-timer flag; is Q4AR written in such a way that it assumes that the casting-timer has already expired before it is called, itself?

If I'm right, is this something that can be re-written without risk of cascade into other functions/systems?

SS
SighelmofWyrmgard wrote:
uosa44 wrote:For sale, by original owner:
1 Human Brain, never been used, only slightly damaged, still in original packaging.
$1, obo
FTFY.

SS
uosa44 wrote:The inability for this person to respond in such a crazy manner proves my point.

Kaivan
UOSA Donor!!
UOSA Donor!!
Posts: 2923
Joined: Wed Aug 13, 2008 11:07 pm

Re: Spell Interrption:

Post by Kaivan »

Q4AR is invoked from 2 locations, callback 0x80 and from the disruption code. In normal operation, callback 0x80 calls Q4AR, and as a result effectively "cleans up" the cast timer, as the callback is triggered at the end of the cast time and never sets up a second callback (callbacks can set up to call themselves again later if needed). Thus, Q4AR doesn't need to clean up any remaining casting time when it's invoked. The fix for the problem is quite literally 1 line, and properly causes the disrupt code to behave as a clean up for the remaining cast time. OSI's fix probably looked like this:

Code: Select all

  if(Q5NC <= 0x00)
  {
    systemMessage(this, "Your concentration is disturbed, thus ruining thy spell.");
    removeCallback(this, 0x80);
    Q4AR(this);
    return(0x01);
  }
With the 3rd line being the important line.
UOSA Historian and former staff member: August 11, 2008 - June 19, 2016

Useful links for researching T2A Mechanics

Stratics - UO Latest Updates - Newsgroup 1 - Noctalis - UO98.org

Post Reply