FFXIAH.com

Language: JP EN DE FR
New Items
2023-11-19
users online
GearSwap Tutorial Pt2

GearSwap Tutorial (v0.1)


PART 2




There was one fairly big 'situational' bit left out of part 1: exactly what ability or spell are you trying to perform or cast? Cure potency doesn't help you when casting Barfira or Haste or Raise, nor does fast cast help your weaponskill.

Well, that parameter that's given to your function, 'spell', contains the info we need.
Code
function precast(spell)
    equip(sets.precast)
end


The 'spell' parameter is itself a table, and it contains lots of details about the spell you're trying to cast. Two values in particular are of interest: spell.name, and spell.english (or spell.french or spell.german or spell.japanese, as the case may be).

spell.name is the name of the action being performed, in the language of the system you're using. If you're using an English system, it will be the English name. If you're using a French system, it will be the French name. Etc.

spell.english, on the other hand, will always be the English name.

If you're only ever using your own lua scripts, you can just use spell.name and ignore the other details. If you're using or sharing your files with other people, you may sometimes want to specify exactly which language you're using, so that the comparison works regardless of what language is being used on the system that's running your script.

It's usually easiest to specify the language when checking things on input (eg: use spell.english when looking at the spell and deciding what to do), and use spell.name for any output (ie: notifying the user about whatever you're doing).

We'll stick with spell.english for anything else in this tutorial.


In addition, the 'spell' parameter contains certain general categories that describe the spell in question. The categories we're immediately interested in are:

spell.action_type -- This can be 'Magic' for any sort of magic spell, 'Ability' for any sort of ability or weaponskill, 'Ranged Attack' for ranged attacks, or 'Item' for item use.

spell.type -- This is the 'type' of the spell, as defined in Windower's resources. 'Haste' would be type 'WhiteMagic'. 'Fire Shot' would be type 'CorsairShot'. "Hunter's Roll" would be type 'CorsairRoll'. 'Penury' would be type 'Scholar'. "Curing Waltz II" would be type 'Waltz'. Etc.

spell.skill -- This is the skill that's used when casting magic spells, such as 'Enhancing Magic', 'Dark Magic', 'Ninjutsu', etc. Also, for weaponskills, it provides the skill the weaponskill is based on ('Hand-to-hand', 'Marksmanship', etc). All other types of abilities don't contain any value for skill.



In addition, we need to decide how to tell the program what sort of situation we're specifying. That is, we define the conditions under which certain parts of the program are run, using something called a 'conditional': an if-then statement.
Code
-- conditional
if value_a == condition_b then
    -- do stuff
end


It's expressed pretty much as you'd say it: if what I'm checking for is equal to some value, then I want to do something specific. If you want to check for "not equal to", you'd use ~= instead, and if you're comparing numbers you can use standard <, >, <= and >= symbols for less than and greater than type comparisons.


So going back to our whm, we want to be more specific about certain things. We want to use our fast cast gloves only for magical spells, not for anything else. We can determine whether we're performing a magic spell from spell.action_type. Therefore:
Code
function precast(spell)
    if spell.action_type == 'Magic' then
        equip(sets.precast)
    end
end


We probably also want to name our set a bit better, so that we know exactly what its purpose is. We can call it sets.precast.fastcast, or perhaps shorten it to sets.precast.FC. However in order to add FC to the precast table, we also have to make sure that the sets.precast table exists first.

Code
function get_sets()
    sets.precast = {} -- just making sure the table exists
    sets.precast.FC = {hands="Gendewitha Gages"}
    
    sets.midcast = {main="Tamaxchi", hands="Bokwus Gloves"}
    
    sets.aftercast = {main="Bolelabunga", sub="Genbu's Shield", hands="Serpentes Cuffs", feet="Herald's Gaiters"}
end

function precast(spell)
    if spell.action_type == 'Magic' then
        equip(sets.precast.FC)
    end
end

function midcast(spell)
    equip(sets.midcast)
end

function aftercast(spell)
    equip(sets.aftercast)
end



We'd also like to do something similar for our midcast set. We only want the Bokwus Gloves to be equipped when we're casting cures. Unfortunately we don't have anything specific enough in the spell variable to tell us that. At best, spell.skill is 'Healing Magic', which also includes -na spells and raises and such.

The long way is to list every possible option:
Code
if spell.name == 'Cure' or spell.name == 'Cure II' or spell.name == 'Cure III' or spell.name == 'Cure IV' or
   spell.name == 'Cure V' or spell.name == 'Cure VI' or spell.name == 'Curaga' or spell.name == 'Curaga II' or
   spell.name == 'Curaga III' or spell.name == 'Curaga IV' or spell.name == 'Curaga V' or spell.name == 'Cura' or
   spell.name == 'Cura II' or spell.name == 'Cura III' then
     equip(sets.midcast)
end


However that's a bit messy. Surely there's an easier way? Well, we can look at the spell name itself and realize that the spell names mostly all start with some of the same letters: 'Cure' for all the cures, and 'Cura' for all the cura/curagas.

Aside: Some would shorten this to just 'Cur' for all cures and curagas together, but 'Cur' will also match 'Cursna', so we don't want that.

To do that we'll use a handy string function called 'startswith' (see part 7, Library Tools). You can apply this to a string to find out if it does, in fact, start with some specified value.
Code
if spell.english:startswith('Cure') or spell.english:startswith('Cura') then
    equip(sets.midcast)
end


Aside: 'applying' a function to an object is a way of saying that that object inherently contains a function that can operate on itself. In this case, all strings have a function called "startswith" that can be used to find out if the string starts with some other string. To apply the function, use the colon (:) character rather than the period (.) character.

So the above has:

spell - this is a table that contains a bunch of info about the spell being cast
spell.english - this a string inside the table that holds the spell's name (in English)
spell.english:startswith - this is a function that a string can use
spell.english:startswith('Cure') - this checks if the spell's english name starts with the string 'Cure' (ie: Cure, Cure II, Cure III, etc).

Also note that this would be a case where spell.english can lead to different results than spell.name. In German, we'd want to check spell.name:startswith('Heilen'). In French, we'd want to check spell.name:startswith('Soin'). By explicitly making the comparison with spell.english, we don't have to worry about the different values spell.name might have.



Anyway, much simpler. Now we can also rename our midcast set so that it's clear what it's being used for.
Code
function get_sets()
    sets.precast = {} -- just making sure the table exists
    sets.precast.FC = {hands="Gendewitha Gages"}
    
    sets.midcast = {} -- just making sure the table exists
    sets.midcast.Cure = {main="Tamaxchi", hands="Bokwus Gloves"}
    
    sets.aftercast = {main="Bolelabunga", sub="Genbu's Shield", hands="Serpentes Cuffs"}
end

function precast(spell)
    if spell.action_type == 'Magic' then
        equip(sets.precast.FC)
    end
end

function midcast(spell)
    if spell.english:startswith('Cure') or spell.english:startswith('Cura') then
        equip(sets.midcast.Cure)
    end
end

function aftercast(spell)
    equip(sets.aftercast)
end



And finally, there are other bits of information available to us aside from the 'spell' parameter, that are always around. Things like 'player' and 'world' that are part of the environment, but not specific to the various event functions, so aren't passed in as parameters.

Of particular interest here is that we can find out what the player's status is by simply checking player.status. In the above, we actually only want to equip that aftercast gear set when we're idle. If we were meleeing, we'd want a proper melee set. So we need to check our status and only equip what's appropriate.

Code
if player.status == 'Idle' then
    equip(sets.aftercast)
end



And once again, we can rename our set to be more intuitive.
Code
function get_sets()
    sets.precast = {} -- just making sure the table exists
    sets.precast.FC = {hands="Gendewitha Gages"}
    
    sets.midcast = {}
    sets.midcast.Cure = {main="Tamaxchi", hands="Bokwus Gloves"}
    
    sets.idle = {main="Bolelabunga", sub="Genbu's Shield", hands="Serpentes Cuffs", feet="Herald's Gaiters"}
end

function precast(spell)
    if spell.action_type == 'Magic' then
        equip(sets.precast.FC)
    end
end

function midcast(spell)
    if spell.english:startswith('Cure') or spell.english:startswith('Cura') then
        equip(sets.midcast.Cure)
    end
end

function aftercast(spell)
    if player.status == 'Idle' then
        equip(sets.idle)
    end
end



After that, it's just adding more checks for more specific situations.



Navigation
Part 1 - Basic Sets and Events
Part 2 - Conditionals and Testing
Part 3 - More on Conditionals
Part 4 - Tables
Part 5 - Abstractions
Part 6 - Asking the Right Questions
Part 7 - Library Tools
Author: Motenten
Date Created: 2014-04-25 17:55:59
Date Last Modified: 2014-05-19 11:08:11
Updates: 6
Bytes: 9989