Jump to content
  • 0

Updating @stats - Using string variables (words) to replace number variables?


Humble_Bee

Question


  • Group:  Members
  • Topic Count:  54
  • Topics Per Day:  0.03
  • Content Count:  112
  • Reputation:   9
  • Joined:  09/22/19
  • Last Seen:  

Howdy all. I'm working on updating @stats on my server to show more useful info (I'm not finished with what I want yet, but I'm adding bit by bit). Can someone tell me how I can get this table to pop up the elements, race, and etc instead of numbers? I am able to show my armor element in-game already as a number (Neutral shows as 0, Water shows as 1, etc), but I want it to show a word instead. I think I'm getting close, as the debugger only shows "term does not evaluate to a function taking 1 arguments" as my only error. I just don't know how to finish it. Of course, if you have an easier way so a @stat changes a number variable into a word when it outputs the text in chat, I'm open to that as well. Here is my code:

 

Spoiler

ACMD_FUNC(stats)
{
    unsigned char msize[SZ_ALL][7] = { "Small", "Medium", "Large" };
    unsigned char mrace[RC_ALL][11] = { "Formless", "Undead", "Beast", "Plant", "Insect", "Fish", "Demon", "Demi-Human", "Angel", "Dragon", "Player" };
    unsigned char melement[ELE_ALL][8] = { "Neutral", "Water", "Earth", "Fire", "Wind", "Poison", "Holy", "Dark", "Ghost", "Undead" };
    char job_jobname[100];
    char element[8];
    char output[CHAT_SIZE_MAX];
    int i;
    struct {
        const char* format;
        char details;
        int value;
    } output_table[] = {
        { "Base Level - %d", 0 },
        { NULL, 0 },
        { "Perfect Dodge - %3d", 0 },
        { "Perfect Hit- %3d", 0 },
        { "Crit Attack Bonus - %3d", 0 },
        { "Armor Element - %u", 0 },
        { "HP Regen Rate- %d", 0 },
        { "SP Regen Rate- %d", 0 },
        { "Race - %u", 0 },
        { "Size - %u", 0 },
        { NULL, 0 },
        { "Zeny also - %d", 0 },
        { "Zeny - %d", 0 },
        { "Free SK Points - %d", 0 },
        { "JobChangeLvl (2nd) - %d", 0 },
        { "JobChangeLvl (3rd) - %d", 0 },
        { NULL, 0 }
    };
    memset(element, '\0', sizeof(element));
    memset(job_jobname, '\0', sizeof(job_jobname));
    memset(output, '\0', sizeof(output));

    //direct array initialization with variables is not standard C compliant.
    output_table[0].value = sd->status.base_level;
    output_table[1].format = job_jobname;
    output_table[1].value = sd->status.job_level;
    output_table[2].value = sd->battle_status.flee2/10;
    output_table[3].value = sd->bonus.perfect_hit_add;
    output_table[4].value = sd->bonus.crit_atk_rate;
    output_table[5].value = sd->battle_status.def_ele;
    output_table[6].value = sd->hprecov_rate;
    output_table[7].value = sd->sprecov_rate;
    output_table[8].value = sd->battle_status.race;
    output_table[9].value = sd->battle_status.size;
    output_table[10].format = element;
    output_table[10].value = sd->battle_status.ele_lv;
    output_table[11].value = sd->status.zeny;
    output_table[12].value = sd->status.zeny;
    output_table[13].value = sd->status.skill_point;
    output_table[14].value = sd->change_level_2nd;
    output_table[15].value = sd->change_level_3rd;
    

    sprintf(element(melement[sd->battle_status.def_ele]), "Element: %s", sd->battle_status.ele_lv, "(Level %u)");
    sprintf(job_jobname, "Job - %s %s", job_name(sd->status.class_), "(level %d)");
    sprintf(output, msg_txt(sd,53), sd->status.name); // '%s' stats:

    clif_displaymessage(fd, output);
    
    for (i = 0; output_table.format != NULL; i++) {
        sprintf(output, output_table.format, output_table.value);
        clif_displaymessage(fd, output);
    }

    return 0;
}
 

The only line it throws the error I mentioned on is this one:
 

Spoiler

  sprintf(element(melement[sd->battle_status.def_ele]), "Element: %s", sd->battle_status.ele_lv, "(Level %u)");

Thanks for anyone familiar with the C++ code!

Edited by Humble_Bee
Link to comment
Share on other sites

8 answers to this question

Recommended Posts

  • 0

  • Group:  Members
  • Topic Count:  34
  • Topics Per Day:  0.01
  • Content Count:  215
  • Reputation:   45
  • Joined:  05/03/13
  • Last Seen:  

Hello

sprintf(element(melement[sd->battle_status.def_ele]), "Element: %s", sd->battle_status.ele_lv, "(Level %u)");

to

sprintf(output, "Element: %s (Level %u)",sd->battle_status.ele_lv,element(melement[sd->battle_status.def_ele]));

Parameters in order:
-your string variable
-the string data to put in
-the data to replace the % inside the string data

But if I'm not wrong, sprintf erase evrything and replace what's inside your string variable by your new string data, you should do one big sprintf with all the parameter you want clif_displaymessage it then sprintf again for another line.

Edited by Kreustoo
  • Upvote 1
Link to comment
Share on other sites

  • 0

  • Group:  Members
  • Topic Count:  54
  • Topics Per Day:  0.03
  • Content Count:  112
  • Reputation:   9
  • Joined:  09/22/19
  • Last Seen:  

On 6/9/2020 at 2:05 AM, Kreustoo said:

Hello


sprintf(element(melement[sd->battle_status.def_ele]), "Element: %s", sd->battle_status.ele_lv, "(Level %u)");

to


sprintf(output, "Element: %s (Level %u)",sd->battle_status.ele_lv,element(melement[sd->battle_status.def_ele]));

Parameters in order:
-your string variable
-the string data to put in
-the data to replace the % inside the string data

But if I'm not wrong, sprintf erase evrything and replace what's inside your string variable by your new string data, you should do one big sprintf with all the parameter you want clif_displaymessage it then sprintf again for another line.


Your code didn't work, but your explanation of how the variables worked in the sprint setup helped me unlock a lot! I'd say I could kiss you, but I won't do that! Thank you so much!!! Here are some pics of the changes in action, as well as the code it got changed to so that it worked:
 

49999685053_38e1536f4a_o_d.jpg

Spoiler

50000204701_b5f61afb48_o_d.jpg


The items near the bottom of the code that are "//" out are stuff I'm still working on. If it says "Equips + Items" next to it, it means it only includes bonuses read from those, same for atk rate, but atk rate includes 100% base I added in as well.
 

ACMD_FUNC(stats)
{
    unsigned char msize[SZ_ALL][7] = { "Small", "Medium", "Large" };
    unsigned char mrace[RC_ALL][11] = { "Formless", "Undead", "Beast", "Plant", "Insect", "Fish", "Demon", "Demi-Human", "Angel", "Dragon", "Player" };
    unsigned char melement[ELE_ALL][8] = { "Neutral", "Water", "Earth", "Fire", "Wind", "Poison", "Holy", "Dark", "Ghost", "Undead" };
    unsigned char mrweaponelement[ELE_ALL][8] = { "Neutral", "Water", "Earth", "Fire", "Wind", "Poison", "Holy", "Dark", "Ghost", "Undead" };
    unsigned char mlweaponelement[ELE_ALL][8] = { "Neutral", "Water", "Earth", "Fire", "Wind", "Poison", "Holy", "Dark", "Ghost", "Undead" };
    char xelement[50];
    char xrace[50];
    char xsize[50];
    char rweaponelement[100];
    char lweaponelement[100];
    char output[CHAT_SIZE_MAX];
    int i;
    struct {
        const char* format;
        char details;
        int value;
    } output_table[] = {
        { NULL, 0 }, //Race
        { NULL, 0 }, //Armor Element
        { NULL, 0 }, //Size
        { NULL, 0 }, //Right-Handed Weapon Element 
        { NULL, 0 }, //Left-Handed Weapon Element
        { "Walk Speed: %d", 0 },
        { "HP Regen Rate: %d%%", 0 },
        { "SP Regen Rate: %d%%", 0 },
        { "Atk Rate: %d%%   (Without Skill Bonuses)", 0 },
        { "Matk Rate: %d%%", 0 },
        { "Physical Def:  %d%%   (Hard)", 0 },
        { "Magic Def:  %d%%   (Hard)",  0 },
        { "Perfect Dodge: %3d%%", 0 },
        { "Perfect Hit Bonus: %3d%%   (Equips + Items)", 0 },
        { "Crit Chance: %3d%%", 0 },
        { "Crit Damage Rate: %3d%%", 0 },
        { "Crit Def Rate: %3d%%", 0 },
        { "Var Cast Bonus: %3d%%   (Equips + Items)", 0 },
        { "Fixed Cast Bonus: %3d%%   (Equips + Items)", 0 },
        { "Skill Delay Rate: %3d%%", 0 },
        { "Skill SP Use Rate: %3d%%", 0 },
        { "Heal Power Bonus: %3d%%   (Equips + Items)", 0 },
        { "Reflect Bonus (Melee): %3d%%   (Equips + Items)", 0 },
        { NULL, 0 }
    };
    memset(xrace, '\0', sizeof(xrace));
    memset(xelement, '\0', sizeof(xelement));
    memset (xsize, '\0', sizeof(xsize));
    memset(rweaponelement, '\0', sizeof(rweaponelement));
    memset(lweaponelement, '\0', sizeof(lweaponelement));
    memset(output, '\0', sizeof(output));

    //direct array initialization with variables is not standard C compliant.
    output_table[0].format = xrace;
    output_table[1].format = xelement;
    output_table[2].format = xsize;            
    output_table[3].format = rweaponelement;               
    output_table[4].format = lweaponelement;
    output_table[5].value = sd->battle_status.speed;
    output_table[6].value = sd->hprecov_rate;                         
    output_table[7].value = sd->sprecov_rate;                      
    output_table[8].value = 100 + sd->bonus.atk_rate;     
    output_table[9].value = sd->matk_rate;
    output_table[10].value = 100-((int)(100 * ((double)(4000 + sd->battle_status.def) / (4000 + sd->battle_status.def * 10))));
    output_table[11].value = 100-((int)(100 * ((double)(1000 + sd->battle_status.mdef) / (1000 + sd->battle_status.mdef * 10))));
    output_table[12].value = (sd->battle_status.flee2/10 * (sd->flee2_rate))/100;
    output_table[13].value = sd->bonus.perfect_hit_add;
    output_table[14].value = (sd->battle_status.cri/10 * (sd->critical_rate))/100;
    output_table[15].value = 40 + sd->bonus.crit_atk_rate;
    output_table[16].value = sd->bonus.critical_def;
    output_table[17].value = -1*(sd->bonus.varcastrate);
    output_table[18].value = sd->bonus.fixcastrate;
    output_table[19].value = sd->delayrate;
    output_table[20].value = sd->dsprate;
    output_table[21].value = sd->bonus.add_heal_rate;
    output_table[22].value = sd->bonus.short_weapon_damage_return; // + (sd->sc.data[SC_REFLECTSHIELD]->val1);
    //sd->subele[ELE_GHOST]   //sd->bonus.long_attack_def_rate   //sd->bonus.long_attack_atk_rate
    
    
    sprintf(xrace,"Race: %s", mrace[sd->battle_status.race]);
    sprintf(xelement, "Element: %s (Lv. %u)",melement[sd->battle_status.def_ele],sd->battle_status.ele_lv);
    sprintf(xsize, "Size: %s", msize[sd->battle_status.size]);
    sprintf(rweaponelement, "Weapon Element (R): %s", mrweaponelement[sd->battle_status.rhw.ele]);
    sprintf(lweaponelement, "Weapon Element (L): %s", mlweaponelement[sd->battle_status.lhw.ele]);
    sprintf(output, msg_txt(sd,53), sd->status.name); // '%s' stats:

    clif_displaymessage(fd, output);
    
    for (i = 0; output_table.format != NULL; i++) {
        sprintf(output, output_table.format, output_table.value);
        clif_displaymessage(fd, output);
    }

    return 0;
  }


I'm working on an output table for @stats that includes reading from skill data, and I can pull the skill data just fine, but it causes a map crash when the skill is not active (the code below):

output_table[22].value = sd->bonus.short_weapon_damage_return + (sd->sc.data[SC_REFLECTSHIELD]->val1);

Does anyone know the principle / coding pattern that needs to be used in output tables so that the game will do an "if this is present, do this" check? I tried using if, but the code compiler didn't seem to like it. Thanks!

Edited by Humble_Bee
Link to comment
Share on other sites

  • 0

  • Group:  Members
  • Topic Count:  34
  • Topics Per Day:  0.01
  • Content Count:  215
  • Reputation:   45
  • Joined:  05/03/13
  • Last Seen:  

Hello,

Happy to have helped unlcok your situation ^^.

If I understand correctly, you want to check if sd->sc.data[SC_REFLECTSHIELD] exists before getting its value, I'd chance your line by:

output_table[22].value = sd->bonus.short_weapon_damage_return + sd->sc.data[SC_REFLECTSHIELD]?(sd->sc.data[SC_REFLECTSHIELD]->val1:0);

Link to comment
Share on other sites

  • 0

  • Group:  Members
  • Topic Count:  54
  • Topics Per Day:  0.03
  • Content Count:  112
  • Reputation:   9
  • Joined:  09/22/19
  • Last Seen:  

11 hours ago, Kreustoo said:

Hello,

Happy to have helped unlcok your situation ^^.

If I understand correctly, you want to check if sd->sc.data[SC_REFLECTSHIELD] exists before getting its value, I'd chance your line by:

output_table[22].value = sd->bonus.short_weapon_damage_return + sd->sc.data[SC_REFLECTSHIELD]?(sd->sc.data[SC_REFLECTSHIELD]->val1:0);

Your code didn't get read by the compiler. The ( ) stopped it. Though even though the below code was read by the compiler successfully, the mapserver still crashed when the power wasn't active, which is weird because the check should check if the move is there or not, and it gives a value to add if it isn't there:

 

Spoiler

output_table[22].value = sd->bonus.short_weapon_damage_return + sd->sc.data[SC_REFLECTSHIELD]?sd->sc.data[SC_REFLECTSHIELD]->val1:0;

I wonder what is causing the mapserver to mess up when this code gives a value properly when the power is active, but doesn't work when a power isn't active. I'll have to do more research into C++ code and the game code.

Link to comment
Share on other sites

  • 0

  • Group:  Members
  • Topic Count:  34
  • Topics Per Day:  0.01
  • Content Count:  215
  • Reputation:   45
  • Joined:  05/03/13
  • Last Seen:  

Sorry I messed the () things writting it too fast, you had to remove the ) yeah (or I wanted to put () around the test).

Quote

 but doesn't work when a power isn't active

What do you mean, what happens when the sc is not set?

Link to comment
Share on other sites

  • 0

  • Group:  Members
  • Topic Count:  54
  • Topics Per Day:  0.03
  • Content Count:  112
  • Reputation:   9
  • Joined:  09/22/19
  • Last Seen:  

On 6/14/2020 at 3:09 AM, Kreustoo said:

Sorry I messed the () things writting it too fast, you had to remove the ) yeah (or I wanted to put () around the test).

What do you mean, what happens when the sc is not set?

When a player does not have the SC active and this code runs, the mapserver crashes, even with the code we just tried where the game is supposed to check if there is the SC active and if not give it a value of 0. When the player DOES have the SC active, the code generates the appropriate value.

Link to comment
Share on other sites

  • 0

  • Group:  Members
  • Topic Count:  34
  • Topics Per Day:  0.01
  • Content Count:  215
  • Reputation:   45
  • Joined:  05/03/13
  • Last Seen:  

Try with that:

output_table[22].value = sd->bonus.short_weapon_damage_return + (sd->sc?(sd->sc.data[SC_REFLECTSHIELD]?(sd->sc.data[SC_REFLECTSHIELD]->val1:0):0);

Testing if sc is valid before accessing it, then the same for the SC itself.

Link to comment
Share on other sites

  • 0

  • Group:  Members
  • Topic Count:  54
  • Topics Per Day:  0.03
  • Content Count:  112
  • Reputation:   9
  • Joined:  09/22/19
  • Last Seen:  

On 6/16/2020 at 1:31 AM, Kreustoo said:

Try with that:


output_table[22].value = sd->bonus.short_weapon_damage_return + (sd->sc?(sd->sc.data[SC_REFLECTSHIELD]?(sd->sc.data[SC_REFLECTSHIELD]->val1:0):0);

Testing if sc is valid before accessing it, then the same for the SC itself.

You were close, and it helped me find the answer. This is huge, because a setup like this will work on finding data for most moves in most areas. I can probably use the following setup to find heal values and other data values like ranged damage buffs to add in to @stats. The trick was for it to look for sc.data (below):

 

Spoiler

output_table[22].value = sd->bonus.short_weapon_damage_return + (sd->sc.data?(sd->sc.data[SC_REFLECTSHIELD]?sd->sc.data[SC_REFLECTSHIELD]->val1:0):0);

All I have to do now is add in what val1 is multiplied by (val1*3+10) and shield reflect will be accurately accounted for when I pull stats when it is on. Obviously, if I do this for other areas, like heal rates, it would probably help to do the output value as a variable (and have the calc far below it in its own section), or at least put more space between each section, because adding a million moves for each stat's calc section would take up a lot of space.

Thanks again!

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...