Page 1 of 1

Spells.dfn

Posted: Wed Oct 14, 2020 3:51 pm
by Mindless Automaton
Is there a doc that lists what the StaticEffect numbers mean in a spell like Clumsy and has more I can use?

Code: Select all

STATFX=37 4A 00 0F


Also this one:

Code: Select all

StaticEffect( 0x373A, 0, 15 );

Also the link to jsdocs is broken: Documentation->Scripting - JS Engine->JS Engine Documentation->UOX3 JS documentation (link)

Thanks!

Re: Spells.dfn

Posted: Wed Oct 14, 2020 4:58 pm
by Xuri
There's no list, per se, though that's maybe something to add to the docs!

The effect numbers refer to item IDs (4 first values) as well as the animation frame count (4 last values). Example:
STATFX=37 4A 00 0F refers to item ID 0x374A, and a framecount of 00 0f aka 15 frames that it will play after spawning. Previously I've just looked up these in InsideUO/UOFiddler. See example screenshot below for a visual explanation :)

Same thing for the other example you posted - reference to the same item ID, and a frame count of 15.

And thanks for the mention about the broken link in docs! Fixed on uox3.org version, and will also fix for next version bundled with UOX3. Thanks!
fx.JPG

Re: Spells.dfn

Posted: Wed Oct 14, 2020 11:19 pm
by Mindless Automaton
While I'm being clumsy, how about this one::

Code: Select all

DoTempEffect( 0, sourceChar, ourTarg, 3, (mChar.skills.magery / 100), 0, 0);
So we are doing a temporary effect, 0 is a character, then the caster, target, Target Number?, Intensity of spell based on magery skill, 0 and 0.

What I am not sure about is what is Target Number and the 0 and 0 at the end?

Also:

magic.cpp

Code: Select all

bool splClumsy( CChar *caster, CChar *target, CChar *src, SI08 curSpell )
{
	// This spell is now handled in JS/MAGIC/level1targ.js
	return false;
}
Clumsy & Create Food are actually their own files, not in level1targ.js. Not that its a big deal.

But then it brings up, is it better spells are in 1 file vs broken out per spell?

Also, where is the code of what clumsy does or am i just not reading the js correctly?
I mean I can see it here: https://www.uoguide.com/Clumsy but where is that code in UOX3?

Thanks!

Re: Spells.dfn

Posted: Thu Oct 15, 2020 6:03 am
by Xuri
Currently the effects of that spell (and other spells) are handled in code, with DoTempEffect just being a way to tell UOX3 to do the temporary effects associated with a particular ID in code. For instance, for the clumsy spell:
DoTempEffect( 0, sourceChar, ourTarg, 3, (mChar.skills.magery / 100), 0, 0);

The first value (0) just informs UOX3 whether the DoTempEffect target is a character (0) or an item (1). Then you have the source (character casting), target (character or item), followed by the effect number/ID (3) - which determines which temporary effect UOX3 will apply.

Then there's the three last parameters, which are called "more1", "more2" and "more3" in the JS docs. What these are used for depends on each specific temp effect, and for the Clumsy spell, this is the amount of dexterity to reduce for the target character, conveniently linked here to the caster's magery skill, so the higher their skill, the more effective the spell is. more2 and more3 have no effect for the Clumsy temp effect, so they are left at 0.

Unfortunately these temporary effects are not very well documented, and exist only in the source right now. This is something I want to address in the revamped documentation, but for now I'll post the relevant code bits here so at least there's some info to be had:
case 1: // Paralyse Spell
    dest->SetFrozen( true );
    toAdd->ExpireTime( BuildTimeValue( (R32)source->GetSkill( MAGERY ) / 100.0f ) );
    toAdd->Dispellable( true );
    break;
case 2: // Nightsight Potion (JS) and Spell (code)
    SI16 worldbrightlevel;
    worldbrightlevel = cwmWorldState->ServerData()->WorldLightBrightLevel();
    dest->SetFixedLight( static_cast<UI08>(worldbrightlevel) );
    doLight( tSock, static_cast<char>(worldbrightlevel) );
    toAdd->ExpireTime( BuildTimeValue( (R32)source->GetSkill( MAGERY ) / 2.0f ) );
    toAdd->Dispellable( true );
    break;
case 3: // Clumsy Spell (JS)
    if( dest->GetDexterity() < more1 )
        more1 = dest->GetDexterity();
    dest->IncDexterity2( -more1 );
    dest->SetStamina( UOX_MIN( dest->GetStamina(), dest->GetMaxStam() ) );
    //Halve effect-timer on resist
    spellResisted = Magic->CheckResist( source, dest, 1 );
    if( spellResisted )
        toAdd->ExpireTime( BuildTimeValue( (R32)source->GetSkill( MAGERY ) / 20.0f ) );
    else
        toAdd->ExpireTime( BuildTimeValue( (R32)source->GetSkill( MAGERY ) / 10.0f ) );
    toAdd->More1( more1 );
    toAdd->Dispellable( true );
    break;
case 4: // Feeblemind Spell (JS)
    if( dest->GetIntelligence() < more1 )
        more1 = dest->GetIntelligence();
    dest->IncIntelligence2( -more1 );
    dest->SetMana( UOX_MIN(dest->GetMana(), dest->GetMaxMana() ) );
    //Halve effect-timer on resist
    spellResisted = Magic->CheckResist( source, dest, 1 );
    if( spellResisted )
        toAdd->ExpireTime( BuildTimeValue( (R32)source->GetSkill( MAGERY ) / 20.0f ) );
    else
        toAdd->ExpireTime( BuildTimeValue( (R32)source->GetSkill( MAGERY ) / 10.0f ) );
    toAdd->More1( more1 );
    toAdd->Dispellable( true );
    break;
case 5: // Weaken Spell
    if( dest->GetStrength() < more1 )
        more1 = dest->GetStrength();
    dest->IncStrength2( -more1 );
    dest->SetHP( UOX_MIN( dest->GetHP(), static_cast<SI16>(dest->GetMaxHP()) ) );
    //Halve effect-timer on resist
    spellResisted = Magic->CheckResist( source, dest, 4 );
    if( spellResisted )
        toAdd->ExpireTime( BuildTimeValue( (R32)source->GetSkill( MAGERY ) / 20.0f ) );
    else
        toAdd->ExpireTime( BuildTimeValue( (R32)source->GetSkill( MAGERY ) / 10.0f ) );
    toAdd->More1( more1 );
    toAdd->Dispellable( true );
    break;
case 6: // Agility Potion (JS) and Spell (code)
    dest->IncDexterity( more1 );
    toAdd->ExpireTime( BuildTimeValue( (R32)source->GetSkill( MAGERY ) / 10.0f ) );
    toAdd->More1( more1 );
    toAdd->Dispellable( true );
    break;
case 7: // Cunning Spell
    dest->IncIntelligence2( more1 );
    toAdd->ExpireTime( BuildTimeValue( (R32)source->GetSkill( MAGERY ) / 10.0f ) );
    toAdd->More1( more1 );
    toAdd->Dispellable( true );
    break;
case 8: // Strength Potion (JS) and Spell (code)
    dest->IncStrength2( more1 );
    toAdd->ExpireTime( BuildTimeValue( (R32)source->GetSkill( MAGERY ) / 10.0f ) );
    toAdd->More1( more1 );
    toAdd->Dispellable( true );
    break;
case 9: // Grind Necro Reagent
    toAdd->ExpireTime( BuildTimeValue( (R32)more2 ) );
    toAdd->More1( more1 );
    toAdd->More2( more2 );
    toAdd->Dispellable( false );
    break;
case 10: // ???
    toAdd->ExpireTime( BuildTimeValue( 12.0f ) );
    toAdd->Dispellable( false );
    toAdd->More1( more1 );
    toAdd->More2( more2 );
    break;
case 11: // Bless Spell
    dest->IncStrength2( more1 );
    dest->IncDexterity2( more2 );
    dest->IncIntelligence2( more3 );
    toAdd->ExpireTime( BuildTimeValue( (R32)source->GetSkill( MAGERY ) / 10.0f ) );
    toAdd->More1( more1 );
    toAdd->More2( more2 );
    toAdd->More3( more3 );
    toAdd->Dispellable( true );
    break;
case 12: // Curse Spell
    if( dest->GetStrength() < more1 )
        more1 = dest->GetStrength();
    if( dest->GetDexterity() < more2 )
        more2 = dest->GetDexterity();
    if( dest->GetIntelligence() < more3 )
        more3 = dest->GetIntelligence();
    dest->IncStrength2( -more1 );
    dest->IncDexterity2( -more2 );
    dest->IncIntelligence2( -more3 );
    //Halve effect-timer on resist
    spellResisted = Magic->CheckResist( source, dest, 4 );
    if( spellResisted )
        toAdd->ExpireTime( BuildTimeValue( (R32)source->GetSkill( MAGERY ) / 20.0f ) );
    else
        toAdd->ExpireTime( BuildTimeValue( (R32)source->GetSkill( MAGERY ) / 10.0f ) );
    toAdd->More1( more1 );
    toAdd->More2( more2 );
    toAdd->More3( more3 );
    toAdd->Dispellable( true );
    break;
case 15: // Reactive Armor Spell
    toAdd->ExpireTime( BuildTimeValue( (R32)source->GetSkill( MAGERY ) / 10.0f ) );
    toAdd->Dispellable( true );
    break;
case 16: // Explosion potion messages (JS)
    toAdd->ExpireTime( BuildTimeValue( (R32)more2 ) );
    toAdd->More1( more1 ); //item/potion
    toAdd->More2( more2 ); //seconds
    toAdd->More3( more3 ); //countdown#
    toAdd->Dispellable( false );
    break;
case 18: // Polymorph Spell
    toAdd->ExpireTime( cwmWorldState->ServerData()->BuildSystemTimeValue( tSERVER_POLYMORPH ) );
    toAdd->Dispellable( false );

    UI16 k;
    // Grey flag when polymorphed
    dest->SetTimer( tCHAR_CRIMFLAG, cwmWorldState->ServerData()->BuildSystemTimeValue( tSERVER_POLYMORPH ) );
    if( dest->IsOnHorse() )
        DismountCreature( dest );
    k = ( more1<<8 ) + more2;

    if( k <= 0x03e2 ) // body-values >0x3e1 crash the client
        dest->SetID( k );
    break;
case 19: // Incognito Spell
    toAdd->ExpireTime( BuildTimeValue( 90.0f ) ); // 90 seconds
    toAdd->Dispellable( false );
    break;
case 21: // Protection Spell
    toAdd->ExpireTime( BuildTimeValue( 120.0f ) );
    toAdd->Dispellable( true );
    toAdd->More1( more1 );
    dest->SetBaseSkill( dest->GetBaseSkill( PARRYING ) + more1, PARRYING );
    break;
case 25: // Temporarily set item as disabled
    toAdd->ExpireTime( BuildTimeValue( (R32)more1 ) );
    toAdd->ObjPtr( dest );
    dest->SetDisabled( true );
    toAdd->More2( 1 );
    break;
case 26: // Temporarily disable the usage of potions
    toAdd->ExpireTime( cwmWorldState->ServerData()->BuildSystemTimeValue( tSERVER_POTION ) );
    dest->SetUsingPotion( true );
    break;
case 27: // Explosion Spell
    toAdd->ExpireTime( BuildTimeValue( static_cast<R32>(cwmWorldState->ServerData()->CombatExplodeDelay()) ) );
    toAdd->More1( more1 );
    break;
case 40: // Used by JS timers
    toAdd->ExpireTime( BuildTimeValue( ( (R32)more1 + (R32)more2 / 1000.0f ) ) );
    toAdd->More1( more3 );
    break;
case 41: // creating item
    toAdd->ExpireTime( BuildTimeValue( (R32)(more1) / 100.0f ) );
    toAdd->More2( more2 );
    break;
case 42: // delayed sound effect for crafting
    toAdd->ExpireTime( BuildTimeValue( (R32)(more1) / 100.0f ) );
    toAdd->More2( more2 );
    break;
case 43: // regain wool for sheeps (JS)
    toAdd->ExpireTime( BuildTimeValue( (R32)(more1) ) );
    break;

When it comes to magic and spells... I've been working on/off on porting spells from code to JS, but it's a huge effort, and it's going very slowly due to distractions with other things (like fixing bugs and trying to make sure other features that are not actually working at all see some work done). The approach I'm taking there is actually to split the spells into multiple files, not based on individual spells or even spell circles, but based on the effects and requirements of each spell. So... all stat-modifying spells like Clumsy, Weaken, Agility, Strength, Bless, Curse, etc. in one file, all effect buffs/debuffs like Magic Armor, Protection, Poison, Paralyze, Incognito, etc. in one file, all summon spells in one file, all direct damage spells in one file, and so on.

Each of those files will have a common entry point though, where all the basic, shared spellcasting requirements are taken care of, like validating character stats, reagents, checking for spellbooks (or scrolls, or wands), checking whether spellcasting is allowed in the caster's region, etc. Then it branches off into the individual files based on the spell that is cast.

But as mentioned, it's a huge undertaking, and progress on that is slow :X