Jump to content

Humble_Bee

Members
  • Posts

    112
  • Joined

  • Last visited

Posts posted by Humble_Bee

  1. So I added a couple autobonuses to some cards where they would trigger a buff (like a heal) and do a special effect so players would know that something happened. My problem is that the effects listed in rAthena->rathena->doc->effect_list are not turning off. I still have fireworks popping like ten minutes later. Does anyone know how to put a timer on these or how to get them to stop when a buff ends or an item is unequipped? Thanks if you've figured this out already!

  2. On 7/11/2020 at 11:43 PM, Sergardo said:

    how to remove pnuema on landprotector?

    im using latest trunk rathena

    thx

    According to this code in skill.cpp, pnuema already doesn't work on land protector (iRO wiki says the same thing):
     

    	switch (skill_id) {
    		case AL_PNEUMA: //Pneuma doesn't work even if just one cell overlaps with Land Protector
    			if(g_skill_id == SA_LANDPROTECTOR)
    				break;

    If you want it to disappear on land protector, perhaps try one or more of these:
    Adding it to the return null list here in skill.cpp (look for the first part of the code, I've added it to the bottom):
     

    	case WM_SEVERE_RAINSTORM:
    	case SO_WATER_INSIGNIA:
    	case SO_FIRE_INSIGNIA:
    	case SO_WIND_INSIGNIA:
    	case SO_EARTH_INSIGNIA:
    	case AL_PNEUMA:
    		if( map_getcell(src->m, x, y, CELL_CHKLANDPROTECTOR) )
    			return NULL;

    Or look for first part of this code in skill.cpp and add pneuma right before the break like I've done:
     

    	switch (skill_id) {
    		case SA_LANDPROTECTOR:
    			if( unit->group->skill_id == SA_LANDPROTECTOR ) {//Check for offensive Land Protector to delete both. [Skotlex]
    				(*alive) = 0;
    				skill_delunit(unit);
    				return 1;
    			}
    			//It deletes everything except traps and barriers
    			if ((!(skill_get_inf2(unit->group->skill_id)&(INF2_TRAP)) && !(skill_get_inf3(unit->group->skill_id)&(INF3_NOLP))) || unit->group->skill_id == WZ_FIREPILLAR || unit->group->skill_id == GN_HELLS_PLANT) {
    				if (skill_get_unit_flag(unit->group->skill_id)&UF_RANGEDSINGLEUNIT) {
    					if (unit->val2&UF_RANGEDSINGLEUNIT)
    						skill_delunitgroup(unit->group);			
    				} else
    					skill_delunit(unit);
    				return 1;
    			}
    				if( unit->group->skill_id == AL_PNEUMA ) {
    				(*alive) = 0;
    				skill_delunit(unit);
    				return 1;}
    			break;


     

    • Upvote 1
    • Like 1
  3. On 7/11/2020 at 11:26 PM, Sergardo said:

    How to Remove gospel bonus + atk

    im using new rathena trunk 

    I'm using an older rAthena trunk, but not that old. I'm assuming they will be the same. Look for this code in skill.cpp:

    		case UNT_GOSPEL:
    			if (rnd() % 100 >= 50 + sg->skill_lv * 5 || ss == bl)
    				break;
    			if (battle_check_target(ss, bl, BCT_PARTY) > 0)
    			{ // Support Effect only on party, not guild
    				int heal;
    				int i = rnd() % 13; // Positive buff count
    				int time = skill_get_time2(sg->skill_id, sg->skill_lv); //Duration
    				switch (i)
    				{
    					case 0: // Heal 1000~9999 HP
    						heal = rnd() % 9000 + 1000;
    						clif_skill_nodamage(ss, bl, AL_HEAL, heal, 1);
    						status_heal(bl, heal, 0, 0);
    						break;
    					case 1: // End all negative status
    						status_change_clear_buffs(bl, SCCB_DEBUFFS | SCCB_REFRESH);
    						if (tsd) clif_gospel_info(tsd, 0x15);
    						break;
    					case 2: // Immunity to all status
    						sc_start(ss, bl, SC_SCRESIST, 100, 100, time);
    						if (tsd) clif_gospel_info(tsd, 0x16);
    						break;
    					case 3: // MaxHP +100%
    						sc_start(ss, bl, SC_INCMHPRATE, 100, 100, time);
    						if (tsd) clif_gospel_info(tsd, 0x17);
    						break;
    					case 4: // MaxSP +100%
    						sc_start(ss, bl, SC_INCMSPRATE, 100, 100, time);
    						if (tsd) clif_gospel_info(tsd, 0x18);
    						break;
    					case 5: // All stats +20
    						sc_start(ss, bl, SC_INCALLSTATUS, 100, 20, time);
    						if (tsd) clif_gospel_info(tsd, 0x19);
    						break;
    					case 6: // Level 10 Blessing
    						sc_start(ss, bl, SC_BLESSING, 100, 10, skill_get_time(AL_BLESSING, 10));
    						break;
    					case 7: // Level 10 Increase AGI
    						sc_start(ss, bl, SC_INCREASEAGI, 100, 10, skill_get_time(AL_INCAGI, 10));
    						break;
    					case 8: // Enchant weapon with Holy element
    						sc_start(ss, bl, SC_ASPERSIO, 100, 1, time);
    						if (tsd) clif_gospel_info(tsd, 0x1c);
    						break;
    					case 9: // Enchant armor with Holy element
    						sc_start(ss, bl, SC_BENEDICTIO, 100, 1, time);
    						if (tsd) clif_gospel_info(tsd, 0x1d);
    						break;
    					case 10: // DEF +25%
    						sc_start(ss, bl, SC_INCDEFRATE, 100, 25, 10000); //10 seconds
    						if (tsd) clif_gospel_info(tsd, 0x1e);
    						break;
    					case 11: // ATK +100%
    						sc_start(ss, bl, SC_INCATKRATE, 100, 100, time);
    						if (tsd) clif_gospel_info(tsd, 0x1f);
    						break;
    					case 12: // HIT/Flee +50
    						sc_start(ss, bl, SC_INCHIT, 100, 50, time);
    						sc_start(ss, bl, SC_INCFLEE, 100, 50, time);
    						if (tsd) clif_gospel_info(tsd, 0x20);
    						break;

    Below, I've changed just a piece of it, change your piece of code in the above section like this and I think it will work just fine:

     

    				//	case 11: // ATK +100%
    					//	sc_start(ss, bl, SC_INCATKRATE, 100, 100, time);
    					//	if (tsd) clif_gospel_info(tsd, 0x1f);
    					//	break;
    					case 11: // HIT/Flee +50
    						sc_start(ss, bl, SC_INCHIT, 100, 50, time);
    						sc_start(ss, bl, SC_INCFLEE, 100, 50, time);
    						if (tsd) clif_gospel_info(tsd, 0x20);
    						break;

    Notice that I changed case 12 to case 11. You will need to do this so that there is not an error in the code, because you told the computer to not see the +atk bonus, which was case 11 before.

  4. I haven't tested these, but here are four ideas that might give you something to play with: 

    		case [Your Power's Name with no brackets]:
    			status_zap(bl, status->hp/2, 0);
    			break;
    
    		case [Your Power's Name with no brackets]:
    			status->hp = status->max_hp/2;
    			break;
                
    		case [Your Power's Name with no brackets]:
    			int64 damage = status->hp - status->max_hp/2;
    			status_zap(bl, damage, 0);
    		        break;
    
    		case [Your Power's Name with no brackets]:
    			int64 damage = status->max_hp / 2;
    			if (damage >= status->hp){
    			clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
    			return false;}
    			else{			
    			status_zap(bl, damage, 0);};
    		        break;
    
    if status->hp doesn't work, you could try sd->battle_status.hp

     

  5. So I noticed that Magnum Break added elemental damage to standard attacks, almost making them dual-element. I want to do something similar where I reduce weapon damage for standard attacks for mobs by half, and then add that half back in in another element- Magnum Break style. I made some headway- I found where the code is that calculates elemental damage for mobs. I even coded it where the mobs can use dual-element attacks. My problem comes in in the damage calculations. When I wear armor that receives 100% damage in both elements, everything is fine. When I wear armor where one element receives 100% damage and the other element receives 50% resistance, it works fine. For example, I have Orc Zombies normally hitting me for 200 damage, even with the dual-attack (half nonelement, half undead). If I wear a poison element armor, my code correctly reduces the damage to 150 (100 nonelement stays the same, undead lowers by 50). My problem appears to come in when one element adds damage (150%) and the other reduces it (50%). The game might be taking the sign of the first element (+ or - / increase or decrease damage) and applying it to the other element as well- (150% and 50% should balance to 100%, but might be becoming 200%), though sometimes the numbers don't seem quite right. Anyone have any clues on this?

    My code (This is found in the "battle_calc_element_damage" section of battle.cpp):
     

    	//Elemental attribute fix
    	if(!(nk&NK_NO_ELEFIX)) {
    		//Non-pc physical melee attacks (mob, pet, homun) are "non elemental", they deal 100% to all target elements
    		//However the "non elemental" attacks still get reduced by "Neutral resistance"
    		//Also non-pc units have only a defending element, but can inflict elemental attacks using skills [exneval]
    		if(battle_config.attack_attr_none&src->type){
    			if(((!skill_id && !right_element) || (skill_id && (element == -1 || !right_element))) &&
    				(wd->flag&(BF_SHORT|BF_WEAPON)) == (BF_SHORT|BF_WEAPON))
                wd->damage = wd->damage/2;
                wd->damage += battle_attr_fix(src, target, wd->damage, sstatus->def_ele, tstatus->def_ele, tstatus->ele_lv);};


    Since that code isn't working and I've spent hours trying different things to get it to work, I've settled for doing a random roll where it swaps out nonelemental damage and defensive element damage half of the time each. It's not as enjoyable for me, but it will do until I figure out the actual answer:

     

    	//Elemental attribute fix
    	if(!(nk&NK_NO_ELEFIX)) {
    		//Non-pc physical melee attacks (mob, pet, homun) are "non elemental", they deal 100% to all target elements
    		//However the "non elemental" attacks still get reduced by "Neutral resistance"
    		//Also non-pc units have only a defending element, but can inflict elemental attacks using skills [exneval]
    		if(battle_config.attack_attr_none&src->type){
    			if(((!skill_id && !right_element) || (skill_id && (element == -1 || !right_element))) &&
    				(wd->flag&(BF_SHORT|BF_WEAPON)) == (BF_SHORT|BF_WEAPON)){
    			
    			if(rnd() % 100 < 50)
    		    wd->damage = battle_attr_fix(src, target, wd->damage, sstatus->def_ele, tstatus->def_ele, tstatus->ele_lv);
    			if(rnd() % 100 >= 50)
    			return;
    			
    			};
    			
    		   };

     

    Also, has anyone tested Magnum Break by changing it to Water element and seeing how it fares damage-wise against a Fire element mob? I'd be curious to see if Magnum Break would be buggy if it weren't a pure Fire attack. Thanks for any assistance!

  6. On 7/14/2020 at 4:11 AM, Kreustoo said:

    Yeah you're right my reasoning is just plain wrong :D.

    I remembered some other game theroycrafting transforming resist in bonus hp and tryed to do it again but it's just wrong.

    1) 2000+2000*0.75 -(500 * 4) = 1500 - 2k hp with 75% hp resist hit by 4* 500 damages, survive with 1500 HP
    2) 2000-(500-500*0.75)*4 = 1500 - 2k hp with 75% resist hit by 4*500 damages, survive with 1500 HP

    But 1500 HP on the first case is really less %max hp than in case 2 and you'll die really faster.
     

    That's a good question, did you try to see how calculator like maybe diablo 3 evaluate that?

    I haven't checked into other games at all yet. A person could make HP increase like resist increases, but then the closer someone got to 100% HP bonus, the closer to infinite HP they would have. ?  Probably wouldn't be good for game balance, ha. 

    One option might be to cap MaxHP bonus at 100% or 95%, and then have the bonus give a soft-defense boost after reaching 50% MaxHP bonus. The higher the MaxHP boost gets, the greater % boost to soft defense. At 100% MaxHP boost, a person would be immune to damage. Though this wouldn't be balanced, because each element has to reach 100% a piece in order to get immunity. I'm sure there is a way to balance it though.

  7. 21 hours ago, Tereco said:

    where can i edit it in src?

    It's not in SRC. It is in rAthena->rathena->db->re (or pre-re, depending on if you are using a renewal or pre-renewal server). The file is called attr_fix . I will say, you will probably want to make a copy of the file and save it before changing anything. Also, the balancing work almost requires a program like Microsoft Excel, or OpenOffice, or LibreOffice, as it is there that you can do formulas for sums to make sure everything adds up properly. Of course, if you wanted to make a game based on Shadow being really over-powered and all the other elements having to fight against it, that could add a whole new dynamic to your server.

    • Upvote 1
  8. To anyone familiar with Ragnarok, you know that in the original game, the elements aren't balanced. Holy is resistant to darn near everything, while Fire is largely only resistant to itself. Since I'm a big of game balance, I re-did my elemental table to make both defensive and offensive elements balanced. Of course, there are a million ways to do this, so this thread is for people to post their favorite versions of their balanced elemental mods chart. Here is lv. 1 of mine:

     

    // Columns - target's defense element           Element Lv. 1
    // Rows    - attacker's weapon element
    
    Neut	Watr	Erth	Fire	Wind	Pois	Holy	Shdw	Ghst	Und	
    105	105	90	105	105	105	125	105	75	80	Neutral
    95	75	100	125	85	105	90	100	100	125	Water
    95	125	75	85	125	125	90	90	80	110	Earth
    95	85	125	75	100	105	90	120	80	125	Fire
    95	125	85	100	75	105	90	90	110	125	Wind
    125	90	120	115	115	75	90	100	95	75	Poison
    95	90	90	95	95	125	75	125	85	125	Holy
    95	100	90	120	110	85	125	75	125	75	Shadow
    75	110	120	90	80	95	100	120	125	85	Ghost
    125	95	105	90	110	75	125	75	125	75	Undead

    Note: The biggest thing to remember is that this about balance, which means it will be unlikely that a person will get everything they want for every element.

    What I like about mine:

    Neutral has a weakness, and it gives more of a reason for undead element to be used as a weapon.

    Ghost players can actually get the full neutral resistance from Ghost armor on my server, instead of the hot mess that iRO did with Ghost armor.

    Undead gets neutral resistance, which makes them more realistically undead for me.

    The normal gameplay on my server will be more full of variety, especially when I make monster basic attacks 50% non-elemental 50% monster element, and once I change the monster spawn rates around so that there is more elemental mixing.

    What I don't like about mine:

    In order to get Undead and Earth with neutral resistance, it required giving other elements a small neutral weakness. Not as big of a deal at lv. 1, but becomes more of a bonus at the higher levels. I also wish Holy's neutral weakness wasn't so high, but since a lot of holy enemies will have heals, it will help against neutral using players.

    Shadow doesn't have any poison resistance, so it's not as traditionally thematic compared to other games. I'm not fond of Water having such a high Earth weakness, but it would have messed up my thematic choices on other elements to lower it. 

    When it comes to offense, people only need to use a neutral and a water weapon to have 100% coverage against everything. I don't like this feature, but there also aren't a ton of strengths between the two either, so it won't be that much of a boost. Given how happy I am with the rest of the balancing, I don't know that I would change this.

    - - - -

    Notes:

    On my server-

    Ghosts aren't inherently immune to neutral damage, but at lv. 4 they gain full immunity.

    Undead armor element won't affect healing, but I will likely make a racial bonus that will give increased elemental/defensive resistances in exchange for lowered healing.

    My lv. 2, lv. 3, and lv.4 elemental mods increase according to the lv. 1 bonuses, so a 10% bonus at lv. 1 turns into 20% bonus at lv. 2, and a 15% resist turns into a 30% resist at lv. 2 and a 45% resist at lv. 3.
    - - - -
    In order to have a balanced elemental table, both offense and defense must be balanced. It's easy to get stuck thinking about only defense, and this wouldn't be a problem if players had to use the same weapon element as they do their armor element, but if a shadow armor player can use any weapon type and one weapon is strong against half your elements and another weapon is strong against the other half, the player has an "easy win" button offensively.

    EDIT: I recently edited my table after noticing that poison seemed too strong against the first 5 elements combined. Boosted water resistance to help with this.

    EDIT2: My elements were messing up in game until I realized that the amount of lines between the charts must be the exact same as they are in the original file. In the original file you see something like:

    Spoiler

    1    // lv1 Attribute table
    //Neut Watr Erth Fire Wind Pois Holy Shdw Gho  Und

    In my updated elemental chart, I had spaced it out to be like:

    Spoiler

    1    // lv1 Attribute table
     

    //Neut Watr Erth Fire Wind Pois Holy Shdw Gho  Und

    The extra space between the two lines, even though there is nothing there, is apparently read as part of the array, and so can mess up the file.

  9. On 7/12/2020 at 11:43 AM, Kreustoo said:

    Hello,

    Let's say we have just 1000hp 0 def, and we gain +5 def and it actually remove 5% of the damage, you'll need 1000+5% (1050) damage to kill him, which is stricly the same as +5% MaxHP.

    But let's say now with have 1000hp and already 50%def, we need 1000 + 1000*50% = 1500 damage to get killed.
    - +5% def will result in 1000 +1000*55% = 1550 damage to get killed
    - +5% max HP will be 1050 + 1050*50% = 1575 damage to get killed

    In both case max hp gave the maximum "damage to get killed". Max hp is then stricly better? So MaxHP is really pure 5% defense while other stat depends of what the player has already?

    (Maybe there's some bonus having def that make it better that I forgot tho.)


     

    But damage isn't calculated by MaxHp. It's calculated by atk power.

    If I have 1000 HP and 75% HP boost, I have 1750 HP. If I get hit by an attack for 2000, I die.

    If I have 1000 HP and 75% resist boost, I have 1000 HP. If I get hit by an attack for 2000, damage reduces to 500, and I have 500 HP left over (half of it).


     

  10. (This is not a support thread, but a bit more of a lively debate.) So I'm working on standardizing my server a bit. I'm trying to come up with calculations that will make all my bonuses equal. For example, all cards either add the equivalent of a 5% damage boost or 5% survivability boost. With autocast skills, it's usually not too hard, because I can change their skill lv and chance to happen to balance out to about a 5% overall boost. With MaxHP, I've been questioning myself. Unlike a resistance boost to all classes that keeps working every time I get hit, hitpoints are gone after I get hit that many times. It's really just a one time buff that someone can use items or skills or etc to refresh. That said, would you say that a 5% MaxHP boost still adds 5% to a person's survivability? If you say no, how much of a MaxHP boost do you think would be equal to the same % boost in other areas?

  11. (Note: This issue was solved.)

    So I was able to trigger pets to perform when I autocast a skill by doing this in skill.cpp:

     

    Spoiler
    
        case NPC_EMOTION_ON:
        case NPC_EMOTION:
            //val[0] is the emotion to use.
            //NPC_EMOTION & NPC_EMOTION_ON can change a mob's mode 'permanently' [Skotlex]
            //val[1] 'sets' the mode
            //val[2] adds to the current mode
            //val[3] removes from the current mode
            //val[4] if set, asks to delete the previous mode change.
            if (sd) {struct pet_data *pd; pd = sd->pd; {clif_pet_performance(pd, 6);} }

     

    But it is having trouble when I'm not the target already. If I autocast an attack on an enemy (like fire bolt) and set NPC_EMOTION to autocast when fire bolt casts, NPC_EMOTION fails to cast (because fire bolt has it's target set on the enemy). If I autocast something like a heal on myself, NPC_EMOTION works consistently. I'm trying to figure out where the targeting is even coming into this calculation. Perhaps because I'm only using sd instead of pointing the sd to player characters?

    I also have trouble trying to set NPC_EMOTION as the first attack and having something else autocast off of NPC_EMOTION, because NPC_EMOTION sets my target to myself, which means fire bolt hits me. I have yet to test if this effect happens when trying to autocast fire bolt by causing it to trigger off a self-heal. That will probably be part of my next step.

    Can anyone point out where my error is that is causing the targeting issues?

    EDIT (SOLVED): I figured out my problems. AutoSpellOnSkill uses the target of the skill before it- so if you attach it to a self-target skill, it will also target the player (heal+fire bolt will cause fire bolt to hit you).  The second part of my problem with the targeting seems to have been linked to NPC_EMOTION being a self skill as well. I tried the code attached to NPC_RANGEATTACK and the code is working like I want it to. After adding Dimik's attack animation as its performance animation client-wise, my Dimik is now happily shooting while I autocast NPC_COMBOATTACK. Just got to figure out why it's also saying it's "I just got fed" quotes and turn that off, and this will be golden.

  12. 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!

  13. 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.

  14. 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.

  15. 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!

  16. 6 hours ago, iamjhigz said:

    @Humble_Bee Thanks for the effort ? You'll help many server owner didn't know how to fix this issue.
    does this remove all songs? like Assassin  Cross of Sunset?

    It should remove all songs that cause a buff, including Assassin Cross of Sunset and Apple of Idun's heal and the others. What I don't think it is does is stop damage songs from causing damage to your homun or other people's homun. Again, note, please test it out first before sending it live if possible, as that way you can see if it causes any bugs on your server. Mess around playing with a homun quite a bit with it, as my bard using a homun (which they normally don't) had some map server crashes, but they may be related to my bard using a homun or to other server issues I might have.

  17. 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!

  18. One of the things I enjoy is implementing custom pet scripts on pets, either current Ragnarok pets or ones that haven't been implemented officially but the sprites exist in-game already. Where would be the best place to start a thread where people can share their custom pet scripts so that everyone can enjoy the bonuses? (By scripts, I mean when a pet is loyal, cordial, etc, it gets such-and-such bonuses.)

  19. I like your all-in-one script. I'm just trying to figure out how to make it if someone picks a particular slot, they get a particular set of enchants- like slot 4 on a weapon gives a weapon element, slot 3 gives stat buffs, slot 2 gives skill bonus buffs or something. I know it could be simple as make Weapon$ an array with 4 options that each are item arrays, and then it would just be "if slot 4 was selected, use Weapon$ and it's value 4", but I haven't figured out how to do it yet. Otherwise, loving that I can already permanently buff any weapon with any element that I want. ?

    Edit: I'm getting a little closer. I copied the Weapon$ array line and made a second one while changing the enchants, and then did an "if / else" statement. When I used the script, the game passed over the first Weapon$ array, which means it's working. Now I just need to find out what variable is attached to each card slot and I should be golden. "If slot 1, use this Weapon$" … "Else If slot 2, use this Weapon$ instead".

  20. I believe this is the answer: Go to your skill.cpp file. Here you will make 2 changes.

    Change #1
    Look for this section of code:
     

    Spoiler

        if( skill_get_inf2(sg->skill_id)&(INF2_SONG_DANCE|INF2_ENSEMBLE_SKILL) && map_getcell(bl->m, bl->x, bl->y, CELL_CHKBASILICA) )
            return 0; //Songs don't work in Basilica

    Right below it, add:
     

    Spoiler

        if( skill_get_inf2(sg->skill_id)&(INF2_SONG_DANCE|INF2_ENSEMBLE_SKILL) && bl->type==BL_HOM )
            return 0; //Songs don't work on homunculus

    Change #2
    Look for this section of code:
     

    Spoiler

            case UNT_APPLEIDUN: { //Apple of Idun [Skotlex]
                    int heal;
    #ifdef RENEWAL
                    struct mob_data *md = BL_CAST(BL_MOB, bl);

                    if (md && md->mob_id == MOBID_EMPERIUM)
                        break;
    #endif

    Right below the #endif, add:

    Spoiler

                    if (bl->type == BL_HOM)
                        break;


    Note: Damage songs will still likely hit your homun, because I didn't mess with that. This just gets rid of the buffs and heals from songs. Also, I would try this on a test server before hitting live with it.

  21. If it's possible, I would love to see a bonus where the pet uses it's special animation (or attack animation) when a move is used. I have some pets that trigger autocast moves, like gargoyle triggering arrow repel. It would be quite fun for the pet to actually look like it's the one firing the arrow repel, even if it's not. Love the work you're doing. If you ever make a video tutorial on how to make new item bonuses, I also would love to see it. ?

  22. What I care about right now is that I'm adjusting some weapons' matk through bonus scripts- like causing books to give matk to magic using classes- and because the matk isn't listed under the base atk/matk, the heal is not reading it and adding it in. So I would say it's probably the flat heal? The +matk portion at the end of the heal formula.

×
×
  • Create New...