Jump to content

Tero

Members
  • Posts

    58
  • Joined

  • Last visited

  • Days Won

    16

Posts posted by Tero

  1. Having altered the playable characters into a near-unrecognizable state, I next set my sights on the Homunculi, which I actually kind of don't recommend as the Homunculi are janky.

     

    For starters, I made an update to my previously release Homunculus storage function.  Now, Homunculi go into named Embryos when you rest them, and you can call them back out with a dialog box.  Having a bunch of Homunculi has never been easier!

    EmbyroMod2.png.bc5b9a3af502482e6f09d5510b0cfc22.png

     

    If you want this function on your server I provide the steps to add it here:

     

    However, that got me thinking.  It's a little weird that there's 2 clones of each homunculus that are exactly the same except for looks.  Wouldn't it be nice if they were different?  They do have unique skill trees in the homun-skill-tree file, so I made some new skills for them.

     

    It turns out making new Homunculus skills sucks.  Although you can adjust the MAX_HOM_SKILL in the code, the client has a predefined list of skills that can be homunculus skills and you can't change this.  This means that to add new Homunculus skills, you have to replace existing ones, which is lame.  Oh well.  I cannibalized Eleanor for these new moves, since my server doesn't have Homunculus S and none of her skills were of any use to the other Homunculi anyway.  As such, now all of the alternate Homunculi have a new alternate base skill.  I also gave each Homunculus a sixth skill, which we'll get to in a moment, and I gave the alternate homunculi new names.  All the rest of their skills are the same as the base versions.

     

    Lif and Raf:

    - Raf's new base skill is Healing Wind.  This places a healing zone on the ground, similar to Sanctuary, though it doesn't affect monsters in any way and is a lot weaker (though it does scale with level and such).  Compared to Touch of Heal (which on my server doesn't need a potion to use and Lif will target either herself or the master depending on who has lower health), it has less healing power, but it has the added bonus of also being able to heal your party members, which Touch of Heal can't.

    HomChanges1.png.bf15e5fe18d7268a04f6cde5eac5cd1a.png

    - Lif's new 6th skill is Holy Pole, which was one of Bayeri's abilities.

    - Raf's new 6th skill is Volcanic Ash, which was one of Dieter's abilities.  I think Raf seems more like a troublemaker compared to Lif.

     

    Amistr and Gist:

    - Gist's new base skill is Taunt.  This is an AOE provoke around himself.  On my server, Provoke has the extra effect that it prevents monsters from changing targets in some situations, so you can use this to draw attention away from yourself.  It does have the unfortunate side effect of possibly drawing a lot of attention to Gist though.

    HomChanges2.png.eb91a92c2cdcaeab2ab657fdeb404d6c.png

    - Amistr's new 6th skill is Lava Slide, from Dieter.

    - Gist's new 6th skill is Magma Flow, also from Dieter.  I think this makes sense since it's a counter, which synergizes with the taunt move.

     

    Filir and Prit:

    - Prit's new skill is Daybreak.  This is very similar to Filir's Moonlight.  It has less power and only hits once, but in exchange it has knockback.  This is decent as a "get off me" move if you want to use ranged attacks.

    HomChanges3.png.749b4c5dab8c9c53cada7d6e4a2a0800.png

    - SBR44 is basically a totally new skill.  It's now called Last Resort and uses the user's HP to do a powerful attack, similar to Final Strike.  It doesn't directly lower intimacy, but the homunculus is very likely to die afterwards (it leaves it with 1 hp), which now does lose intimacy (I always thought it was weird that it didn't).

    - Filir's new 6th skill is Xeno Slasher, from Eira.  It has good power and can leave enemies bleeding, and it also gives Filir a ranged attack, but Filir's magic attack probably won't be too high.

    - Prit's new 6th skill is Pyroclastic, from Dieter.  This skill is slightly changed in that it loses the Hammer Fall chance, but instead grants slight HP Regen, which I think makes sense because Prit is probably supposed to be a Phoenix.

     

    Vanilmirth and Slograth:

    - Slograth's base skill is still Caprice, but it chooses different skills.  Vanilmirth has the 4 bolt spells, while Slograth has Soul Strike, Dark Strike, Blood Sucker, and Holy Light.  Blood Sucker is interesting because he can heal himself with it, but generally this element selection tends to be less reliable.

    HomChanges4.png.0457bf7e0bf66a111225d5cb921187e9.png

    - Self Destruct no longer takes all your intimacy, but it does cost you a fair bit on top of the usual penalty for the homunculus dying.

    - Vanilmirth's new 6th skill is Granitic Armor, from Dieter.  I think the fact that this hurts you at the end fits with Vanilmirth's chaotic nature.

    - Slograth's new 6th skill is Poison Mist.  This is a rare poison-element spell, fitting Slograth's use of the non-conventional elements.

     

    One last annoyance is that the game wouldn't display the skills in the right order in the homunculus skill tree.  It turns out the homunculus skills are always sent in their skill_id order.  I really didn't want to reorder them all, so I altered the clif method to send them in the same order as the skill tree.  Thankfully, the client preserves the order they receive the skills in and doesn't auto-sort them.  Phew!  For once the client came through for me.

    • Upvote 2
    • Love 1
  2. Are you using a weapon type that that class cannot normally equip?  Each job has a base aspd for each weapon type, which will be 0 for weapons they can't normally use.  You need to modify the values in job-db1 if you're doing this.

    Also, make sure that your max_aspd in player.conf is not 0.

  3. 44 minutes ago, WhiteEagle said:

    At first, holy awesome work and thank you very much for sharing.
    I tried to test it, but I got some errors after compiling. Do I miss something?!
    image.png.86aa3aa2ec51ec860c3843a3ac995ff8.png

    Looks like they've changed a couple small things in the code compared to the version I have, I remember why I posted it the way I did the first time now.  These kinds of errors typically occur when a method signature has changed, so you just need to swap the affected code with whatever they have in the base version.

     

    To fix the first error, in hom_vamporize, find this:

    if (battle_config.hom_setting&HOMSET_RESET_REUSESKILL_VAPORIZED)
    		memset(hd->blockskill, 0, sizeof(hd->blockskill));

     

    and change it to this:

    if (battle_config.hom_setting&HOMSET_RESET_REUSESKILL_VAPORIZED) {
    		hd->blockskill.clear();
    		hd->blockskill.shrink_to_fit();
    	}

     

    For the second, find this in hom_call:

    if (battle_config.hom_setting&HOMSET_COPY_SPEED)
    			status_calc_bl(&hd->bl, SCB_SPEED);

    and change it to this:

    if (battle_config.hom_setting&HOMSET_COPY_SPEED)
    			status_calc_bl(&hd->bl, { SCB_SPEED });

     

    By the way, my version of hom_call is also missing this at the end, as it predates the update where this was done:

    #ifdef RENEWAL
    	sc_start(&sd->bl, &sd->bl, SC_HOMUN_TIME, 100, 1, skill_get_time(AM_CALLHOMUN, 1));
    #endif

     

    And similarly this is in hom_vaporize:

    #ifdef RENEWAL
    	status_change_end(&sd->bl, SC_HOMUN_TIME);
    #endif

     

    You can add this back in if you want (these are responsible for the Homunculi lasting only a certain amount of time).  I don't know if this plays nicely with this mod, though.

    • Upvote 2
    • Love 1
    • MVP 1
  4. If you've gotten annoyed with the limitation of not being able to see what homunculus is inside the Embryo, I've coded a significantly more complicated version of this change that displays a pet incubator-like dialog and lets you pick the embryo you want to hatch.  This is much more complex from a coding perspective though, so you should make sure you're confident in making changes to the codebase.

    EmbyroMod2.png.a8912cd1fa29ed53a7643fd2aa8a37a2.png

    Any embryos made with the old version of the mod will still work, but you'll have to hatch and rest them to convert them to their named versions.  This will also require you to distribute a new version of iteminfo.lub.

     

    First, you need to add a new method to clif.hpp:

    void clif_sendembryo(struct map_session_data* sd);

     

    Next, you need to add the code for this method to clif.cpp:

    /// Presents a list of embyros that can be revived
    /// 01a6 <packet len>.W { <index>.W }*
    void clif_sendembryo(struct map_session_data* sd)
    {
    	int i, n = 0, fd;
    
    	nullpo_retv(sd);
    
    	fd = sd->fd;
    
    	WFIFOHEAD(fd, MAX_INVENTORY * 2 + 4);
    	WFIFOW(fd, 0) = 0x1a6;
    	for (i = 0, n = 0; i < MAX_INVENTORY; i++) {
    		if (sd->inventory.u.items_inventory[i].nameid <= 0 || sd->inventory_data[i] == NULL ||
    			(sd->inventory_data[i]->nameid != 7142 && !(sd->inventory_data[i]->nameid >= 9901 && sd->inventory_data[i]->nameid <= 9909)) ||
    			sd->inventory.u.items_inventory[i].amount <= 0)
    			continue;
    		WFIFOW(fd, n * 2 + 4) = i + 2;
    		n++;
    	}
    	WFIFOW(fd, 2) = 4 + n * 2;
    	WFIFOSET(fd, WFIFOW(fd, 2));
    
    	sd->menuskill_id = AM_CALLHOMUN;
    	sd->menuskill_val = -1;
    }

     

    There's also a change needed in clif.cpp:

     

    Find the method clif_parse_SelectEgg and replace it with this:

    /// Answer to pet incubator egg selection dialog (CZ_SELECT_PETEGG).
    /// 01a7 <index>.W
    void clif_parse_SelectEgg(int fd, struct map_session_data* sd) {
    	if (sd->menuskill_val != -1)
    		return;
    
    	if (sd->menuskill_id == SA_TAMINGMONSTER) {
    		pet_select_egg(sd, RFIFOW(fd, packet_db[RFIFOW(fd, 0)].pos[0]) - 2);
    		clif_menuskill_clear(sd);
    	}
    
    	if (sd->menuskill_id == AM_CALLHOMUN) {		
    		hom_call(sd, RFIFOW(fd, packet_db[RFIFOW(fd, 0)].pos[0]) - 2);
    		if (sd->pd) clif_send_petstatus(sd); // the client wipes the pet status upon answering this dialog, so it has to be resent.
    		clif_menuskill_clear(sd);
    	}
    }

     

    Now we need to change homunculus.hpp.

    Find the definition for hom_call and change it to this:

    bool hom_call(struct map_session_data *sd, short hom_index);

     

    Now in homunculus.cpp:

    Replace the hom_call method with this:

    /**
     * Make a player spawn a homonculus (call)
     * @param sd
     * @param hom_index
     * @return False:failure, True:sucess
     */
    bool hom_call(struct map_session_data* sd, short hom_index)
    {
    	struct homun_data* hd;
    	struct item ed;
    	int n;
    
    	if (hom_index < 0 || hom_index >= MAX_INVENTORY)
    		return 0; //Forged packet!	
    
    	// find the embryo
    	if (!sd->status.hom_id) { //Create or revive a homun.
    
    		if (sd->inventory.u.items_inventory[hom_index].nameid == 7142 || sd->inventory.u.items_inventory[hom_index].nameid >= 9901 && sd->inventory.u.items_inventory[hom_index].nameid <= 9909)
    			n = hom_index;
    		else
    		{ 
    			ShowError("wrong embryo item inventory %d\n", hom_index);
    			return false;
    		}
    
    		ed = sd->inventory.u.items_inventory[n];
    
    		if (ed.card[1] != 0) {
    			// is it ours?
    			if (sd->status.char_id == MakeDWord(ed.card[2], ed.card[3])) {
    				// revive the homun
    
    				// delete the embryo
    				pc_delitem(sd, n, 1, 0, 0, LOG_TYPE_CONSUME);
    
    				sd->status.hom_id = ed.card[1];
    				// proceed with rest of function
    			}
    			else {
    				// Cannot revive someone else's homunculus
    				return false;
    			}			
    		}
    		else {
    			// create a new homun
    
    			// delete the embryo
    			pc_delitem(sd, n, 1, 0, 0, LOG_TYPE_CONSUME);
    			return hom_create_request(sd, HM_CLASS_BASE + rnd_value(0, 7));
    		}
    	}
    
    	// If homunc not yet loaded, load it
    	if (!sd->hd)
    		return intif_homunculus_requestload(sd->status.account_id, sd->status.hom_id);
    
    	hd = sd->hd;
    
    	if (!hd->homunculus.vaporize)
    		return false; //Can't use this if homun wasn't vaporized.
    
    	if (hd->homunculus.vaporize == HOM_ST_MORPH)
    		return false; // Can't call homunculus (morph state).
    
    	hom_init_timers(hd);
    	hd->homunculus.vaporize = HOM_ST_ACTIVE;
    	if (hd->bl.prev == NULL)
    	{	//Spawn him
    		hd->bl.x = sd->bl.x;
    		hd->bl.y = sd->bl.y;
    		hd->bl.m = sd->bl.m;
    		if(map_addblock(&hd->bl))
    			return false;
    		clif_spawn(&hd->bl);
    		clif_send_homdata(sd,SP_ACK,0);
    		clif_hominfo(sd,hd,1);
    		clif_hominfo(sd,hd,0); // send this x2. dunno why, but kRO does that [blackhole89]
    		clif_homskillinfoblock(sd);
    		if (battle_config.hom_setting&HOMSET_COPY_SPEED)
    			status_calc_bl(&hd->bl, SCB_SPEED);
    		hom_save(hd);
    	} else
    		//Warp him to master.
    		unit_warp(&hd->bl,sd->bl.m, sd->bl.x, sd->bl.y,CLR_OUTSIGHT);
    	return true;
    }

     

    Also replace the hom_vaporize method with this:

    /**
    * Vaporize a character's homunculus
    * @param sd
    * @param flag 1: then HP needs to be 80% or above. 2: then set to morph state.
    */
    int hom_vaporize(struct map_session_data *sd, int flag)
    {
    	struct homun_data *hd;
    	int itemflag;
    	struct item tmp_item;
    
    	nullpo_ret(sd);
    
    	hd = sd->hd;
    	if (!hd || hd->homunculus.vaporize)
    		return 0;
    
    	if (status_isdead(&hd->bl))
    		return 0; //Can't vaporize a dead homun.
    
    	if (flag == HOM_ST_REST && get_percentage(hd->battle_status.hp, hd->battle_status.max_hp) < 80)
    		return 0;
    
    	hd->regen.state.block = 3; //Block regen while vaporized.
    	//Delete timers when vaporized.
    	hom_hungry_timer_delete(hd);
    	//hd->homunculus.vaporize = flag ? flag : HOM_ST_REST;
    	if (battle_config.hom_setting&HOMSET_RESET_REUSESKILL_VAPORIZED)
    		memset(hd->blockskill, 0, sizeof(hd->blockskill));
    	clif_hominfo(sd, sd->hd, 0);
    	hom_save(hd);
    
    	if (hd->homunculus.intimacy > 0) {	
    
    		memset(&tmp_item, 0, sizeof(tmp_item));
    
    		switch (hom_class2mapid(hd->homunculus.class_)) {
    		case MAPID_LIF:
    		case MAPID_LIF_E:
    			tmp_item.nameid = 9901;
    			break;
    		case MAPID_AMISTR:
    		case MAPID_AMISTR_E:
    			tmp_item.nameid = 9902;
    			break;
    		case MAPID_FILIR:
    		case MAPID_FILIR_E:
    			tmp_item.nameid = 9903;
    			break;
    		case MAPID_VANILMIRTH:
    		case MAPID_VANILMIRTH_E:
    			tmp_item.nameid = 9904;
    			break;
    		case MAPID_EIRA:
    			tmp_item.nameid = 9905;
    			break;
    		case MAPID_BAYERI:
    			tmp_item.nameid = 9906;
    			break;
    		case MAPID_SERA:
    			tmp_item.nameid = 9907;
    			break;
    		case MAPID_DIETER:
    			tmp_item.nameid = 9908;
    			break;
    		case MAPID_ELANOR:
    			tmp_item.nameid = 9909;
    			break;
    		}
    
    		tmp_item.amount = 1;
    		tmp_item.identify = 1;
    		tmp_item.card[0] = CARD0_CREATE;
    		tmp_item.card[1] = hd->homunculus.hom_id;
    		tmp_item.card[2] = GetWord(sd->status.char_id, 0); // CharId
    		tmp_item.card[3] = GetWord(sd->status.char_id, 1);
    
    		if ((itemflag = pc_additem(sd, &tmp_item, tmp_item.amount, LOG_TYPE_PRODUCE))) {
    			clif_additem(sd, 0, 0, itemflag);
    			if (battle_config.skill_drop_items_full) {
    				map_addflooritem(&tmp_item, tmp_item.amount, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0, 0);
    			}
    		}
    
    		unit_remove_map(&hd->bl, CLR_OUTSIGHT);
    		sd->status.hom_id = 0;
    		unit_free(&hd->bl, CLR_OUTSIGHT);
    		sd->hd = 0;
    		return 1;
    	}
    
    	return unit_remove_map(&hd->bl, CLR_OUTSIGHT);
    }

     

    Getting there, we now need to make a couple changes to skill.cpp:

    As with the first version of this process, comment out this line:  (If you already implemented the first version this will be done already)

    if (sd->status.hom_id) //Don't delete items when hom is already out.

     

    Now find this code block:

    case AM_CALLHOMUN:	//[orn]
    		if (sd && !hom_call(sd))
    			clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
    		break;

     

    And replace it with this:

    case AM_CALLHOMUN:
    		if (sd && !sd->status.hom_id) {
    			clif_sendembryo(sd);
    			clif_skill_nodamage(src, bl, skill_id, skill_lv, 1);
    		}
    		else if (sd && !hom_call(sd, 0)) {
    			clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
    		}
    		break;

     

    Now, find this line in script.cpp:

    hom_call(sd); // Respawn homunculus.

     

    and replace it with this:

    hom_call(sd, 0); // Respawn homunculus.

     

    Phew!  Done with code changes!  Now we just need to add the new embryos into the item-db (for a fun challenge, see if you can determine what their item ids are from the code before we proceed further).

     

    If you have the old, text based item-db, you need to add this:

    9901,Lif_Embryo,Lif Embryo,3,10,,10,,,,,,,,,,,,,{},{},{}
    9902,Amistr_Embryo,Amistr Embryo,3,10,,10,,,,,,,,,,,,,{},{},{}
    9903,Filir_Embryo,Filir Embryo,3,10,,10,,,,,,,,,,,,,{},{},{}
    9904,Vanilmirth_Embryo,Vanilmirth Embryo,3,10,,10,,,,,,,,,,,,,{},{},{}
    9905,Eira_Embryo,Eira Embryo,3,10,,10,,,,,,,,,,,,,{},{},{}
    9906,Bayeri_Embryo,Bayeri Embryo,3,10,,10,,,,,,,,,,,,,{},{},{}
    9907,Sera_Embryo,Sera Embryo,3,10,,10,,,,,,,,,,,,,{},{},{}
    9908,Dieter_Embryo,Dieter Embryo,3,10,,10,,,,,,,,,,,,,{},{},{}
    9909,Eleanor_Embryo,Eleanor Embryo,3,10,,10,,,,,,,,,,,,,{},{},{}

     

    If you have the new, yaml-based item-db, you need to add this to item-db-etc.yml

      - Id: 9901
        AegisName: Lif_Embryo
        Name: Lif Embryo
        Type: Etc
        Buy: 10
        Weight: 10
      - Id: 9902
        AegisName: Amistr_Embryo
        Name: Amistr Embryo
        Type: Etc
        Buy: 10
        Weight: 10
      - Id: 9903
        AegisName: Filir_Embryo
        Name: Filir Embryo
        Type: Etc
        Buy: 10
        Weight: 10
      - Id: 9904
        AegisName: Vanilmirth_Embryo
        Name: Vanilmirth Embryo
        Type: Etc
        Buy: 10
        Weight: 10
      - Id: 9905
        AegisName: Eira_Embryo
        Name: Eira Embryo
        Type: Etc
        Buy: 10
        Weight: 10
      - Id: 9906
        AegisName: Bayeri_Embryo
        Name: Bayeri Embryo
        Type: Etc
        Buy: 10
        Weight: 10
      - Id: 9907
        AegisName: Sera_Embryo
        Name: Sera Embryo
        Type: Etc
        Buy: 10
        Weight: 10
      - Id: 9908
        AegisName: Dieter_Embryo
        Name: Dieter Embryo
        Type: Etc
        Buy: 10
        Weight: 10
      - Id: 9909
        AegisName: Eleanor_Embryo
        Name: Eleanor Embryo
        Type: Etc
        Buy: 10
        Weight: 10

     

    Finally, we just need to add the following to iteminfo.lub:

    	[9901] = {
    		unidentifiedDisplayName = "Lif Embryo",
    		unidentifiedResourceName = "¿¥ºê¸®¿À",
    		unidentifiedDescriptionName = { "..." },
    		identifiedDisplayName = "Lif Embryo",
    		identifiedResourceName = "¿¥ºê¸®¿À",
    		identifiedDescriptionName = {
    			"An embryo containing a Lif.",
    			"^FFFFFF_^000000",
    			"Weight:^009900 1^000000"
    		},
    		slotCount = 0,
    		ClassNum = 0
    	},
    	[9902] = {
    		unidentifiedDisplayName = "Amistr Embryo",
    		unidentifiedResourceName = "¿¥ºê¸®¿À",
    		unidentifiedDescriptionName = { "..." },
    		identifiedDisplayName = "Amistr Embryo",
    		identifiedResourceName = "¿¥ºê¸®¿À",
    		identifiedDescriptionName = {
    			"An embryo containing an Amistr.",
    			"^FFFFFF_^000000",
    			"Weight:^009900 1^000000"
    		},
    		slotCount = 0,
    		ClassNum = 0
    	},
    	[9903] = {
    		unidentifiedDisplayName = "Filir Embryo",
    		unidentifiedResourceName = "¿¥ºê¸®¿À",
    		unidentifiedDescriptionName = { "..." },
    		identifiedDisplayName = "Filir Embryo",
    		identifiedResourceName = "¿¥ºê¸®¿À",
    		identifiedDescriptionName = {
    			"An embryo containing a Filir.",
    			"^FFFFFF_^000000",
    			"Weight:^009900 1^000000"
    		},
    		slotCount = 0,
    		ClassNum = 0
    	},
    	[9904] = {
    		unidentifiedDisplayName = "Vanilmirth Embryo",
    		unidentifiedResourceName = "¿¥ºê¸®¿À",
    		unidentifiedDescriptionName = { "..." },
    		identifiedDisplayName = "Vanilmirth Embryo",
    		identifiedResourceName = "¿¥ºê¸®¿À",
    		identifiedDescriptionName = {
    			"An embryo containing a Vanilmirth.",
    			"^FFFFFF_^000000",
    			"Weight:^009900 1^000000"
    		},
    		slotCount = 0,
    		ClassNum = 0
    	},
    	[9905] = {
    		unidentifiedDisplayName = "Eira Embryo",
    		unidentifiedResourceName = "¿¥ºê¸®¿À",
    		unidentifiedDescriptionName = { "..." },
    		identifiedDisplayName = "Eira Embryo",
    		identifiedResourceName = "¿¥ºê¸®¿À",
    		identifiedDescriptionName = {
    			"An embryo containing an Eira.",
    			"^FFFFFF_^000000",
    			"Weight:^009900 1^000000"
    		},
    		slotCount = 0,
    		ClassNum = 0
    	},
    	[9906] = {
    		unidentifiedDisplayName = "Bayeri Embryo",
    		unidentifiedResourceName = "¿¥ºê¸®¿À",
    		unidentifiedDescriptionName = { "..." },
    		identifiedDisplayName = "Bayeri Embryo",
    		identifiedResourceName = "¿¥ºê¸®¿À",
    		identifiedDescriptionName = {
    			"An embryo containing a Bayeri.",
    			"^FFFFFF_^000000",
    			"Weight:^009900 1^000000"
    		},
    		slotCount = 0,
    		ClassNum = 0
    	},
    	[9907] = {
    		unidentifiedDisplayName = "Sera Embryo",
    		unidentifiedResourceName = "¿¥ºê¸®¿À",
    		unidentifiedDescriptionName = { "..." },
    		identifiedDisplayName = "Sera Embryo",
    		identifiedResourceName = "¿¥ºê¸®¿À",
    		identifiedDescriptionName = {
    			"An embryo containing a Sera.",
    			"^FFFFFF_^000000",
    			"Weight:^009900 1^000000"
    		},
    		slotCount = 0,
    		ClassNum = 0
    	},
    	[9908] = {
    		unidentifiedDisplayName = "Dieter Embryo",
    		unidentifiedResourceName = "¿¥ºê¸®¿À",
    		unidentifiedDescriptionName = { "..." },
    		identifiedDisplayName = "Dieter Embryo",
    		identifiedResourceName = "¿¥ºê¸®¿À",
    		identifiedDescriptionName = {
    			"An embryo containing a Dieter.",
    			"^FFFFFF_^000000",
    			"Weight:^009900 1^000000"
    		},
    		slotCount = 0,
    		ClassNum = 0
    	},
    	[9909] = {
    		unidentifiedDisplayName = "Eleanor Embryo",
    		unidentifiedResourceName = "¿¥ºê¸®¿À",
    		unidentifiedDescriptionName = { "..." },
    		identifiedDisplayName = "Eleanor Embryo",
    		identifiedResourceName = "¿¥ºê¸®¿À",
    		identifiedDescriptionName = {
    			"An embryo containing an Eleanor.",
    			"^FFFFFF_^000000",
    			"Weight:^009900 1^000000"
    		},
    		slotCount = 0,
    		ClassNum = 0
    	},

     

    And that should be everything!  Now just recompile the codebase and restart the server and you should have the new homunculus behaviour.  Hopefully I didn't miss anything in the steps.

    • Upvote 1
    • MVP 2
  5. I've been fiddling around with skills a bit more, having finally somewhat figured out how to get custom animations working.  This is related to the file "skilleffectinfo.lub".  Initially, I thought you could only use certain effects here, but it turns out you can add more effects by editing effectid.lub.  Between the two, you can kinda add custom skill animations, but it's very janky.  Target animations always work, but animations for the caster refuse to play for most skills for no reason that I've been able to determine.  It could be related to the type of skill or some kind of hardcoding in the client file, but I've generally had to use workarounds involving the clif_skill_nodamage function for these sorts of animations.

     

    Anyway, I figured it might be a good time to give a summary of some of the skill changes I've made to the various classes.  Some of these have been mentioned in previous posts, but many are new.  I've also included a little bit of an explanation behind my thought process at the bottom of each entry.

     

    Lord Knight:

    - Bowling Bash now works.  I completely recoded the skill so it now does what it's supposed to do, it knocks back a target and if it hits other targets they get knocked back too.  It does more damage if at least one other target is hit.

    - Spear Stab is now a completely new ability called Pin Down, which has cast time but inflicts the ankle snare effect on enemies.  This is because the original Spear Stab is almost the same as Bowling Bash.

    - Brandish Spear no longer has knockback, which improves its DPS since you can now spam it.

    - Knight has two new skills in "Calmness" and "Fast Metabolism".  The former eliminates the Flee Penalty from being hit by many targets at once, which is good for Flee-based Knights.  The latter increases the amount of healing received from healing items, similar to Increase HP Recovery, though it also affects SP items.

    - Concentration now slightly reduces cast time

    - Aura Blade is now a party skill that can also affect teammates, similar to Doram's buffs.  It also now applies its damage to "fake" multihits (those that have a hit count in the negatives).

    - Has a completely new skill in "Blade Beam", a sword-exclusive skill that has cast time and shoots a projectile with splash damage that can cause Fear.  This is actually a heavily reworked version of RK_WINDCUTTER.

    SkillChanges1.png.a7165d290378b485f479efc9781458e9.png

     

    Lord Knight is a strange class in that it's good but its skill tree has a lot of issues.  Almost all of the class's power is concentrated in Spiral Pierce, even though it has a million other active skills that never see use.  The in-game descriptions of the class imply that it's supposed to be a tank, though it isn't really, it's basically just a bulky DPS, so when adding a few new skills I tried to give the class some tanking utility.  I also wanted Sword-based LK to be more viable, since everyone always runs spear.

     

    Paladin:

    - Grand Cross's physical damage portion is slightly stronger, the physical and magical sides are about equal now (this also increases the recoil damage, however).

    - Pressure is its Renewal version, which deals strong magic damage instead of just dealing fixed damage, making it a drastically better skill.

    - Providence is significantly changed and is now exclusive to Paladin.  It now gives other characters the effect of Faith and Endure, increasing Max HP and Holy Resist.  It also now works on other Paladins, though you can't cast it on yourself.  This was mainly changed because there was actually too much Demon Resist in the game, it was possible to get >90% resist to Demons, functionally trivializing some bosses.

    - Paladin now gets Pinpoint Attack (from Royal Guard).  This skill no longer does an automatic critical and is mainly useful for its status effects.

    - Gospel now functions like a song, you can move and attack while using it.  It no longer strips your buffs when you cast it, though the positive effects still don't affect the caster.  It also makes a bigger cross at level 5 and above.

    SkillChanges2.png.180c87ba206974fbafb96ff34d0ea116.png

     

    In the old days, Paladin was a strong contender for the title of "most underwhelming transcendent class", with basically all of its transcendent skills being useless.  This changed instantly with the change to Pressure, in fact I had to reduce its power a couple times, because when given a source of strong damage output Paladin instantly becomes a "master of all" who has no weaknesses.  I feel like the fact that Paladin has low DPS against enemies who aren't weak to Holy is a key part of the class, so I tried to avoid giving it any significant damage buffs, and I also didn't want to give it anything that significantly improved its tankiness either.  Spear Paladin has always felt quite weak to me, so I think the addition of Pinpoint attack helps a lot there, and the new Providence skill is an interesting buff for some fragile characters.  It's also fun to actually be able to use Gospel.

     

    Assassin Cross:

    - Assassin has four completely new skills.  The first three are "Numbing Poison", "Impairing Poison", and "Sapping Poison".  These are passives that add stat debuffs to Poison status (for AGI, DEX, and STR, respectively), turning it into kind of an anti-Blessing status. 

    - The fourth new skill is "Status Mastery", which increases the chance to inflict status conditions.  This is now a prerequisite for Meteor Attack, which no longer requires Soul Breaker.

    - Venom Dust makes a larger cross at high levels.

    - Venom Splasher is its modern version, which has more power and doesn't require the target to have less than a certain percentage of its HP to be used.

    - Righthand Mastery and Lefthand Mastery now both have 10 levels.  At Level 10 for Lefthand Mastery, the damage penalty for your left hand weapon is eliminated (previously the maximum damage you could get was 70%).

    - Assassin Cross can now learn Phantom Menace (from Guillotine Cross).  This is a very situational ability that hits hidden characters with 100% hit rate.  This mainly exists to deal with Stalkers, as it can hit people using Chase Walk.

    - Assassin Cross has a new ability in Poison Resist.  This reduces the damage you take from Poison Element and reduces the chance to be Poisoned, but you lose 2% of your maximum HP per level of it that you take.  This skill has some use but is mainly intended as a "penalty" skill to gatekeep EDP.

    - Create Deadly Poison requires 5 levels of Poison Resist.  If you want to drink the poison bottle for an ASPD boost, it has to be maxed at level 10, costing you 20% of your maximum HP.

    - EDP is also a 10 level skill that has slightly less power at level 10 than it used to have at level 5.  It's still extremely powerful, but it now makes you into a glass cannon, which I think makes sense.  Note my abysmally low max HP at level 71.

    SkillChanges3.png.fc274a9b0a100d7f8c4709fcd303b645.png

    At least you can freely walk through Venom Dust now without ever being poisoned once this skill is maxed!

    SkillChanges4.png.eb003b6c9200c86cdf318924c2d33f93.png

     

    Assassin is probably the most flawed class in the game.  Pre-Rebirth Assassin has almost no skills that anyone cares about, in particular all of their poison skills are always ignored, but Assassin Cross is almost unquestionably the most powerful class in the game.  It gets three absurdly strong new abilities in EDP, Soul Breaker, and Meteor Assault, all of which are best-in-class abilities of their respective types.  Even then, Sin Cross still typically has a ton of points left over since they don't care about the rest of their abilities.  One of the first things I wanted to do was make Poison more useful, since it's generally one of the wimpiest Status conditions but like half their skills revolve around it.  I also think the ability to inflict status conditions more accurately also allows for a number of interesting status-based builds.  I also use these new skills to make the super strong Sin Cross abilities more expensive to get your hands on, so you now typically have to pick and choose between them a little more.  EDP Sin is also now a total glass cannon, which I think makes sense given how powerful it is.

     

    Stalker:

    - Chase Walk now consumes SP faster

    - Rogue has a new active skill in Rupture.  This is a very strong attack that can only be used against enemies that are bleeding.  Obviously, this synergizes well with Gouge from Thief for auto-attacker Rogues.

    - Stalker has a new ability in "Shadow Master".  This is a passive that reduces damage taken from and increases damage dealt with Shadow Element.  Rogue does not innately have any skills that do Shadow Damage, but there are lots of ways to get one (use a Shadow-element weapon, use Cursed Water, copy a Shadow skill using Intimidate, etc).

    - Stalker also now gets Shadow Form (from Shadow Chaser).  This is an active skill that redirects damage from the Stalker to a target for a certain number of hits.  In the base game, this skill can only be used on players, but I recoded it so you can use it on enemies as well (though MVPs are immune to it).  This is one of the only abilities in the game that has a cooldown before you can use it again, to prevent it from being spammed over and over.

    SkillChanges5.png.32aeb649731dbfb38ba6628236664adf.png

     

    Stalker is an interesting class with a lot of PVP applications and I mainly wanted to enhance that with these changes.  Shadow Master is kind of interesting for mindgames in that it gives you more power at the expense of predictability.  You won't be able to do anything to anyone using Bathory armor, but what if your Intimidate skill is Holy Cross or Grand Cross?  Shadow Form is also the ultimate counter to Asura, allowing you to delete anyone who dares try to use it on you, but a clever attacker will try to bait it out first, since once it has been used you can safely Asura during the cooldown.

     

    Whitesmith:

    - Hammer Fall now has 10 levels and has a larger area at high levels than it used to.

    - Skin tempering also now has 10 levels, granting 10% neutral resist when maxed.

    - Blacksmith has a new ability in "Weapon Enchant", which adds bonus elemental damage to your (or an ally's) weapon.  This is the same effect that Magnum break applies, but for a longer duration.  The level of the skill determines the element of the bonus damage, between Fire, Water, Wind, Earth, and Shadow.  It costs a Red Gemstone to use.

    SkillChanges6.png.61948d05c635ff6bdbbab633aa3bb687.png

    - Whitesmith gets another ability based on this, "Release Enchant", which uses this enchantment to do a Pulse Strike-like attack using the element of the enchantment, though the buff is removed when using this.  Yes, you can indeed use this with Magnum Break, if you have the Marine Sphere card.  It costs a lot of SP though.

    - Whitesmith also gains access to Cart Cannon (from Geneticist).  You have to craft the cannonballs yourself using a mini-furnace rather than them being buyable, so there's a new passive for "Cannonball Craft" as well.

    SkillChanges7.png.239168a69cf2ba6d5b944d5fc700e2c6.png

     

    It's no secret that I've long found Whitesmith to be kind of an underwhelming class.  I like the idea of it being kind of an offensive support-focused tank, but so much of its skill tree is dedicated to utility skills that it feels kind of underwhelming to use in combat.  I think having the new buffs and Cart Cannon helps a lot with this.  I had been looking at Cart Cannon for a long time, but it didn't really make sense for Creator, I think it functions far better as a Whitesmith skill.  Cannonballs are a bit expensive to get in large numbers (the elemental cannonballs require Flame Hearts and the like), so the main use for them is probably for wiping out boss mobs, which they do pretty well since the damage doesn't divide among the targets.

     

    Creator:

    - As mentioned in another topic, resting a Homunculus puts it back into its Embryo, allowing you to raise multiple Homunculi.

    - Each of the Homunculi gets a new skill when evolved.  Lif gets Eraser Cutter, Amistr gets Stahl Horn, Filir gets Needle of Paralyze, and Vanilmirth gets Steinwand.  However, you have to be a Creator to evolve Homunculi (only the Creator can use the Sage Stone).

    - Bomb and Acid Terror now have 10 levels.  Acid Demonstration requires a higher level of these skills to learn.

    - Alchemist has one new skill in Precision, which is a passive skill that increases hit.  At level 5 and 10 it increases the range of skills like Potion Pitcher and Acid Terror by 1.

    - Creator now has access to four new skills, Crazy Vines, Mandragora Howling, Explosive Spore, and Blood Sucker, all from Geneticist.  You can craft the items needed to use these skills using the pharmacy skill and a new book.

    SkillChanges8.png.b3e1b1d876fc60961f5c4a16257f23f5.png

    - Creator also gets Duple Light (from Arch Bishop), which is renamed to Alchemical Weapon and needs a special item to use, which you also create using a new book.

    Not too much to say about Creator.  It's already a pretty solid class.  Precision and Alchemical Weapon are mainly there to add a bit more value to the generally ignored Axe Mastery, which serves as the root of this skill path, taking all of these skills can make Creator into a relatively solid auto-attacker now.  I also wanted Cultivation to actually do something useful, so it's now the root of the new plant skills tree, which also gives more options besides Acid Demonstration (though that skill is still extremely strong).  The biggest change is being able to store the homunculi, which makes them far nicer to use (I eventually got fed up and implemented this after failing like 10 straight times to get a Vanilimirth).

     

    Sniper:

    - Hunter gains access to a new skill, Fear Breeze (From Ranger).  It's now a 10-level skill, that has slightly more power than it originally did at level 5.  This skill (and all other skills that cause multi-hits, like Double Attack) is now able to critical hit (I actually never knew this wasn't the case until I tested it).  This makes the Archer's Bullseye skill a lot more useful.

    SkillChanges9.png.987164ea4fe5aa49b1f739488ed52ddf.png

    - Hunter's skill tree is significantly refactored so the trap skills make more sense in terms of their prerequisites now (each now only relies on the one above it).

    - Sniper gains access to 3 new traps, Cluster Bomb, Burning Trap, and Icebound Trap (all from Ranger).  These now just consume regular traps rather than special alloy traps.

    SkillChanges10.png.15dd78383b682c8c766c4301a5a6de0e.png

     

    Sniper is another class that is generally very powerful, but also had a lot of skills no one ever used.  Fear Breeze is an interesting skill, but it's so underpowered for Ranger that it needed buffs to even be viable as a regular Hunter skill, but now I think it's an interesting part of a trapper or auto-blitz beat build.  I also wanted traps to feel more viable, and also for there to be more sources of some of the new status effects like Burning and Crystalize.  An interesting note is that Ankle Snare is now harder to get, so you'll have to invest more points into traps if you want that (which you almost certainly still do).

     

    Clown / Gypsy:

    - Bard and Dancer can now normal attack while singing / dancing.

    - Bard and Dancer songs / dances now affect the user without needing Soul Link, though they drain significantly more SP.

    - Most Bard and Dancer songs are better.  Apple of Idun heals more HP.  Fortune's Kiss now raises LUK.  Assassin Cross of Sunset now stacks with everything.

    - Bard and Dancer have a new active skill called "Up Tempo".  This is basically an Instrument / Whip version of Two Hand Quicken.

    - Clown and Gypsy have a new passive skill in "Battle Rhythm", which grants Perfect Dodge while singing / dancing.

    - Arrow Vulcan has slightly more power, but Dex no longer reduces its cast time.

    - Clown and Gypsy have a new skill in Sonic Force / Sonic Lash, a melee-range active skill that is different between the two classes.  Sonic Force has a knockback effect, while Sonic Lash hits 3 times and can inflict Bleeding.  For both characters, this skill gains significant bonus damage from Strength.  This can also be used while singing / dancing.

    SkillChanges11.png.633c7c44169858768a175f2a13d4c101.png

    - Clown and Gypsy also get the lost skill "Ragnarok".  This skill is basically just continuous Meteor Storm, it drops a meteor within the skill's range every few seconds while the song is active.  Unlike the original version, it doesn't hit allies.  This was an interesting exercise in learning how to program timer skills.

    SkillChanges18.png.8fdbebd02a76ab6c43f032ab2d334a3a.png

     

    The main thing I wanted for Clown and Gypsy was for singing and dancing to feel more relevant, as many people totally ignore this to focus purely on burst damage through Arrow Vulcan.  I also wanted to make their normal attack feel more relevant, to emphasize the fact that their new class-exclusive weapons are capable of melee attacks, considering they're mostly used in a near interchangeable way with bows.

     

    High Priest:

    - High Priest has 5 new skills, Coluceo Heal, Cantocandidus, Clementia, Lauda Agnus, and Lauda Ramus, (all from Arch Bishop).

    - These skills all rely on different Priest buffs to learn.  Sanctuary, Magnificat, Suffragium, Kyrie, and Gloria, respectively.

    - Redemptio is deleted from existence (there's simply too much weirdness involving this skill and exp penalties and the like).

    SkillChanges12.png.59afabc3f3fd18da963ddc3b7c14a691.png

     

    High Priest is obviously a very good class, but it often feels like you don't really have a lot of options for build diversity.  Having these new buffs rely on some of the lesser used buffs creates a lot more variety in terms of different builds for this class.

     

     

    Champion:

    - Monk has a completely new skill in "Status Barrier", which provides a one-time block against bad status.

    SkillChanges13.png.5eb25001f93d6b726593d3d2b533df10.png

    - Zen's cast time is no longer affected by Dex.

    - Champion gets three new skills in Crescent Elbow, Ride The Lightning and Howling of Lion (all from Sura).  Ride the Lightning is an almost completely new skill.  It now teleports to the target, similar to Snap, has a chance to inflict Stun, and also grants Combo status, allowing Chain Combo to be used immediately afterwards, followed by the rest of the chain if you have enough spirit spheres.  This is probably the coolest skill ever.

    SkillChanges14.png.791da6abd73676aa904ba1487316e428.png

     

    Champion is a pretty good class with a decent number of options.  I like the new Status Barrier skill as a way for the class to give a little more PVE support, considering it does branch from a support class.  Ride the Lightning is there to give a bit more power to combo-based Champion, and honestly I just think it's super cool.  Howling of Lion is mostly there to prevent the newly buffed Bard and Dancer skills from being too strong, and Crescent Elbow is basically just something that's interesting and different.

     

    High Wizard:

    - Napalm Vulcan is now a 10 level skill, but at max level it does more hits and does more damage than it used to.

    - Gravitation is a mix of its old and new versions.  It has the new proper damage from the new formula, but it also applies the reduced Attack Speed debuff from the old version.

    - High Wizard has a totally new skill in Ancient Curse.  This is an Undead Element spell that can inflict the Curse status.  Unfortunately, a ton of enemies also have this spell.

    SkillChanges15.png.dd21060d7b0c51d360aa20730797abc1.png

     

    High Wizard is another one of those classes that originally only had one relevant skill, in Amplify Magic Power.  It's a very good skill, undoubtedly, but it still felt a bit dull.  With Napalm Vulcan now being a proper nuke (albeit, not against Neutral armor) and Gravitation being a pretty relevant debuff, it now feels pretty good.  Ancient Curse was mainly just added because I wanted more sources of Undead damage in the game, currently only like 2 enemy-only spells hit that element.  On my server, Undead always hits Neutral armor for 100% damage (unlike dark, which is resisted at higher levels), so it's a very reliable element even if it isn't super strong.  

     

     

    Professor:

    - Memorize now affects the whole party.

    - Autospell can cast more spells, like Storm Gust and Lord of Vermillion (you need equipment or to be a Super Novice to take advantage of this, though).

    - Sage has a totally new spell in Poison Splash (as shown before)

    - Professor has two new spells in Arrullo and Kyomu (from Sorcerer and Kagerou, respectively).  These are renamed to Sleep Mist and Disable.

    SkillChanges16.png.47a16baac0f88fecc2017828c78d5fe0.png

     

    Professor was another one of those classes that always felt underwhelming in the past, with the main appeal simply being Double Bolt.  I discussed previously about the changes to autospell, which make the class feel a lot better, but I figured it would also probably need a little bit of help against magic reflect, which it is otherwise completely helpless against (Wizard at least has ground target spells it can use, the only one Professor has is Heaven's Drive).  Arrullo is mostly just there because I wanted something that could inflict Deep Sleep.

     

    Whew, this was long.  I've already talked a lot about the other classes previously, but I guess I can quickly touch on one new skill for Soul Linker, which is called Eskon.  It's a rebirth-only skill that deals damage based on the number of debuffs on a target, which it also removes after it hits.  It can hit very hard if a target is very significantly debuffed, and many of the other Es- skills are debuffs, so it presents kind of an alternate combo route if you want to use those skills instead.

     

    Also, you get to blow people up.  Poor, poor Lunatic.

    SkillChanges17.png.c30078e3fcc3ba4d59a161afd3359450.png

     

    • Upvote 4
  6. This is such a minor tweak that I don't even really think it's worth creating a topic for, but my testers reported that this makes the game feel significantly smoother.

     

    This change attempts to address a desync issue when attacking.  When clicking on a monster that is hostile and is also moving towards you, sometimes your character will fail to begin attacking because the client thinks it is within range to attack, but the character is actually too far away to attack on the server side.  It's especially common with monsters that move fast.  With this tweak, this situation should no longer happen.

     

    The change is in unit.cpp:

     

    Find this comment:

    // Player tries to attack but target is too far, notify client

     

    Add this line immediately afterwards:

    clif_fixpos(src);  // synchronize the player's position with the client

     

    Don't change anything else.  The finished code block should look like this.

    if(sd && !check_distance_client_bl(src,target,range)) {
    		// Player tries to attack but target is too far, notify client
    		clif_fixpos(src);  // synchronize the player's position with the client
    		clif_movetoattack(sd,target);		
    		return 1;	

     

    Then just recompile the code and test it out.  Everyone I had test it said it felt instantly noticeable.  This does increase the number of packets being sent so this may cause a very minor increase to network traffic, but based on the number of packets that are typically sent back and forth I don't think the effect is very significant.

    • Love 7
    • MVP 2
    • Like 4
  7. So, if you believed I was done editing the game you probably shouldn't have.

     

    A while back, I downloaded the latest Korean GRF, which I periodically backport content from.  I'd had my eye on a couple of the enemies from Ep19 for a while, but I never really had a place for them to go.  There simply weren't any more useful maps to steal from Renewal, and the maps from Episode 19 are in a different format that my version of the game can't read.

     

    I was fiddling around with the Episode 19 maps to see if I could figure out how to get them to load, and I noticed the error just complains about the rsw file.  So I tried subbing out the rsw for the new maps with one from an old map, and this does allow the maps to load, albeit in an extremely glitchy way.  It turns out the problem is linked to the size of the map specified in the rsw, so I was able to get it to work by creating a new map in Browedit with the same dimensions, saving it, substituting the gat and gnd files for the ones from Episode 19, reopening it in Browedit, and saving it again.  This produces a viable Episode 19 map that can be loaded in the old client.

     

    So now we have a new dungeon based on Episode 19, Nightmare Canyon:

    Modding29.png.e96834dd4787ed1ffbb6f10bd1e2d96e.png

    This area uses 1@jorchs and 1@jorlab and is located near Rachel.  The monsters here have endgame-level power and a number of interesting cards, for example one adds a speed down effect to Provoke.

    Modding30.png.704bcac0f827e59629ed397c695be4e1.png

    I did a fair amount of fiddling around with the map editor to get this working and learned how to do a few new things, like changing the water colour (this is under windows -> water -> type).  I think this purple water really helps enhance the atmosphere of this location.  These areas beside the final walkway were actually not filled with water originally, I had to edit the stage geometry to create these pools.

     

    I also created a second new dungeon, this time a past version of Juperos.  This allows you to visit the town of Verus.  Incidentally, this required me to add some of the Juperos characters to the npc folder.  These characters initially make noise, so I had to edit their sprites with act editor to remove the sound effects.

    Modding31.png.3b013f76f30e9fce4c0a3260dacb6159.png

     

    You can proceed through Verus to reach the past version of Juperos core, which uses 1@mcd.  This stage has many geometry edits to allow you to get through the whole thing (it has many walls, which I assume use NPCs to warp you around int he base game)

    Modding32.png.949d608c491b1ff0a7742ccd16f34211.png

    You can fight the Limacinas here, which I think are neat enemies.  They were incredibly hard to get working, though.  Backporting enemy sprites from the new version of the game is easy, you just have to add them to jobname.lua and npcidentity.lua.  However, Limacina is a shooter.  It has a separate sprite file for its bullet, but for the life of me I couldn't figure out how to specify the name of their bullet file.  It turns out that this is because you can't - the monster bullet sprites are hardcoded inside the client file.  The only way to add a new bullet is to replace an existing one, and there aren't many.

    About the only shooters that aren't used in the base game are the Photon Cannon enemies.  There's 4 of them, which means I can give shots to 4 enemies by stealing their enemy ids and renaming the bullets of the enemies to the name of the photon cannon bullets.  So I had to make Limacina monster ID 1664, and its bullet is named canon_bullet.spr.  This was an absolute pain in the neck, but it paid off.  Limacina can shoot!

    Modding33.png.9959b7b4bea7aadd97b28ce182a60bcd.png

     

    As for the Photon Cannons, they're still in the game, but they no longer shoot.  In fact, they don't attack at all.  They instead simply cast spells.  Monsters can use spells without having the "can attack" flag set, if those spells are set to be cast during idle state and on a random target.

    Modding34.png.79fef4158117b01410faddcbe5d8241a.png

     

    The boss of this area is Charleston 3.  I had considered using this boss before, but I felt it didn't fit with any of the existing areas, but it works well here.  It has a number of fun drops, but my favourite is this.

    Modding35.png.99c820cdd471d65b67bb129378eadec4.png

    This might be my new favourite weapon.  It has this script:

    bonus bSplashRange,1; bonus4 bAutoSpellOnSkill,"GS_DUST","NC_FLAMELAUNCHER",1 + (getskilllv("GS_DUST")>=5) + (getskilllv("GS_DUST")==10),10000; bonus2 bSkillUseSPrate,"GS_DUST",100;

     

    There was a problem initially, though.  When NC_Flamelauncher is used, it's suppose to show a cool flame animation, but it doesn't appear when using the above.  After a ton of debugging, I discovered that this attack actually has a 2 stage animation - the animation of the flames is actually shown during the attack's casting animation, and then the animation of the target being burned occurs after the casting animation.  In the script above, the casting animation never plays, so there's no flames.  I fixed this by adding the following code to skill_castend_damage_id

    if (skill_id == NC_FLAMELAUNCHER && sd && sd->state.autocast) clif_skillcasting(src, src->id, bl->id, bl->x, bl->y, skill_id, skill_get_ele(skill_id, skill_lv), 1);

    Basically, this causes the game to show the cast animation for one frame whenever you use Flame Launcher, even if it wouldn't otherwise be shown.  And it works:

    Modding36.png.603d4d814e283f91ef359c2bad5a66e9.png

    It's hard to capture how sick this looks in a still image, but it was well worth the effort to get it working.

     

    Finally, all this fiddling around with the map editor finally led me to solve something that had been a problem for a long time.  When you create maps with Browedit, they don't automatically update the lightmaps, which leaves you with either the shadows the map started with or no shadows at all.  You can create lights to cast shadows, but they create overly dark shadows that turn anything inside pure black.  You can see this above when I posted a picture of the new Lutie map.  After a bunch of tweaking, I figured out how to fix this.  You have to go to Tools->Lightmap->Export, which will export the lightmap as a BMP.  You can then edit the bitmap with paint, by altering the colour from black to gray.  Then re-import the lightmap, and this is the result:

    Modding37.png.23001eb812d763ccec076f4d2fdc6fab.png

    Finally correct lightmaps!  You can't tell this is a custom map anymore.

     

    I feel like I've solved almost all the mysteries of how to edit stuff in the game now, it now feels like there's very little I don't know how to edit, save for stuff that's locked to the client exe file.  Kind of crazy when I think of how much I struggled with things at the beginning.

    • Upvote 1
    • MVP 2
  8. Been working on a ton of small things that don't really make for an interesting post.  Lots of little polish things, like fixing minimaps where exits have changed, fixing item descriptions, fixing status icon descriptions, altering the card prefixes to make sense with the new / changed cards, etc.  Important, but not flashy.

     

    I've also been trying to look at EXP curves and smooth out various issues.  Something I noticed was that without fail, every character always wants to go to Culvert 1 after job change.  This is probably because Thief Bugs and Thief Bug Eggs give somewhat disproportionately high exp for how easy they are, so I've toned this back a fair bit.  You can push on to Culvert 2 for better exp (but at more risk), or you can consider other areas like the areas south or east of Prontera at this level.

     

    Similarly, pretty much every character always wants to go to Lutie when they get to around level 35-40.  This one I'm kind of okay with (there are some other viable alternatives here, Clock Tower 2, Orc Dungeon, Brasilis, Amatsu Dungeon 1, etc).  Instead, I chose to slightly nerf Lutie in a slightly different way: it's now harder to get there.  Rather than talking to Santa Claus at Aldebaran and getting warped there, Lutie is instead now on the main map, north of Yuno.  There's also now a second Lutie Field map, which occurs before the existing one.  It's actually just an altered version of the existing map with a new enemy in the Snow Tail, which is a weaker version of Nine Tail.  This plays the previously unused Track 56, which is a nice peaceful song for a nightime snow map.

    Modding26.png.3f691787e9d29e785adf7ae51580486b.png

     

    I also made some tweaks to Dewata, which I noticed was a place you would basically never bother with, it's now a decent level 70ish levelling area.  I added the previously unused Basilisk enemy to this map, which I think fits well here.

    Modding27.png.31a0657b700be9dfa14d17714d49a52e.png

     

    Finally, the later floors of Malangdo dungeon have these new Fire fish enemies, which give roughly Niflheim-level exp, being a decent alternative for level 75+.

    Modding28.png.d143a20cf1804768b5ab26454ba06a41.png

     

    With these changes I think the PVE content feels pretty good and there aren't really any major deadzones or spots where there's only one viable place to level.

     

    Beyond this, one of the biggest issues with playing on my server is that so much is changed that it's hard to create builds.  The existing at commands in the game can help a little, but it really helps to be able to view the content in the game using a webpage, so I put together a very simple dictionary of the cards, pets, and card sets in the game, which I've attached to this post in the event that you're curious what my rebalance of the cards looks like.  I also took the opportunity to do another pass of the card balance while I was putting it together.

     

    While this is a massive document to go through (my server contains exactly 700 cards, purely by chance), I think there's some interesting things to talk about with regards to game balance when it comes to the cards.

     

    For starters, my biggest pet peeve when it comes to the cards are when there are multiple cards that have almost the same effect but one is purely better than the other.  An example in the base game would be Wormtail and Zerom, which are both accessory cards that increase DEX.  Wormtail gives DEX +2, and Zerom gives DEX +3, so Zerom is just purely superior in every situation.  On my server, Wormtail instead gives DEX +2, STR +1, INT +1.  I think this is still generally worse, as most builds that want to use a DEX accessory card want as much as they can get and don't care too much about INT or STR, but for certain builds that use all of these stats (like autocast Sage for example) you might consider it.

     

    Another thing I really wanted to avoid are situations where there's literally only one card you would ever consider for a specific slot.  A good example would be in PVP.  There is literally only one card you would ever consider for your shield card and that's Thara Frog, which cuts damage taken from Demi-Human by 30%.  There is pretty much no way this can exist in the game and not be the best PVP card, so this was a rare example of a card that I actually nerfed fairly substantially, on my server it only reduces demi-human damage by 20%, to make room for some other shields to be relevant, though it's probably still the all-around best option.  Another example would be the weapon cards for Mages.  In base, the only weapon any mage ever uses is a 4-slot Rod with 4 Drops cards, because there are almost no cards that do anything for mages.  This is now drastically changed as almost all cards that affect damage that used to be physical-only also affect magic, so mages can now run Hydra cards for example (though Hydra is also somewhat nerfed).  This makes mages significantly more powerful, but there are more ways to defend against magic as well.

     

    When it comes to the relative power of the cards, I generally chose a few baseline cards for each category to use as a guideline for the general power of that category, typically the most commonly used ones.  For example, for weapon cards, the benchmark was the "do 20% more damage to enemies of a specific race / element" cards.  These are almost undeniably the most powerful weapon cards in the base game (save for MVP cards), but rather than severely nerfing them to bring them in line with everything else, I generally tried to buff the other cards to be more relevant.  An interesting wrinkle when it comes to buffs is you often have to buff slightly more than feels sensible in order to make things balanced.  My first idea is usually something along the lines of "this seems fine now but I probably still wouldn't use it", but in order to make it an interesting option it has to be powerful enough that you actually want to go out and get it.  This was particularly an issue for the cards in the past, as they have to be quite powerful to make up for how difficult it is to get there.

     

    By far the hardest thing to balance were the card sets, particularly the ones for each class.  In the base game, these sets are simply irrelevant and no one ever uses them.  They involve a lot of lousy cards that you'd never want to use and the bonuses are generally not worth what you're giving up.  Here, with the cards being buffed so they're actually usable, some of the card sets actually became much too powerful and had to be nerfed somewhat.  There's an extremely fine line between the card sets clearly being the best option for their class and being worthless,  In general, I don't think you want the sets to be too good because I feel like they're kind of fundamentally uninteresting, since coming up with your own card build is one of the most interesting things about the game, but some of them do give some interesting effects, like Rogues gaining the ability to use some traps.

     

    The balance of the pets is probably nonsense.  This is the one area where I mainly focused on flavour and what I thought was cool moreso than balance.  Some pets that have a really strong skill have a somewhat weaker loyalty bonus, but there's no question that a lot of them are kinda bonkers.  Oh well.  Pets are fun.

     

     

    There's a good chance this will end up being my last post about the server, because to be honest, there's not actually that much more to be done with it.  It's definitely been incredibly fun to tinker around with, though.  I hope this topic can inspire others to see what interesting things they can do with this game.  It's actually kinda bonkers how much control you have with this game compared to pretty much any other game that allows modding.

    pets.html sets.html cards.html

    • Love 1
    • MVP 1
  9. Being doing some behind the scenes stuff lately, most of which is hard to show off.

     

    For starters, I've been fiddling with autocast.  I've mentioned before that I always felt Professor felt mediocre and part of this is because autocast kind of sucks.  Whenever you trigger an autocast, it cancels your attack and you just pose, similar to casting the spell normally.  For Professor, this makes autocast kind of pointless since you can just cast the spell normally and attack with free cast and you get a similar effect, except you call the spell at the maximum level.  I've always felt that they way it should work is that you should keep attacking and the spell should just go off, so autocast is just like bonus DPS on top of your regular attacking.

     

    This is actually extremely hard to change, because the posing actually takes place client-side, and it does not respect any of the fields sent in the packet like amotion.  There is a flag that is sent to skill_attack that can suppress the casting animation, but it doesn't work for multi-hit or NPC skills (ie, almost every spell that can be autocast) and it has its own share of problems.

     

    My first change to try to change this was to shift the "src" of the attack to the target.  For mobs, this works perfectly, because mobs don't have casting animations.  We can now auto-attack and throw bolts without stopping!

    Modding23.png.5ebc0991d4ee6871cc1e936c006b7ed3.png

     

    The problem is PVP.  If you use this approach for PVP, the person being hit by the bolts does the casting animation instead!  This is obviously not what we want.  There isn't a great solution to this.  What I've done is to change the damage type to splash when used against a player (this is also how the animation flag works).  However, this has several issues.  When casting a multi-hit spell, it only hits once (for bolts, all the bolts come down at once).  It also deals the damage instantly, rather than after the animation.  This is not ideal, but I don't think there's any other way without changing the client.

     

    Notice the 501 damage from the bolts already happened a bit ago even though they haven't hit yet.

    Modding24.png.ae3e24cbb4e8c49c1754d4a60303ab5f.png

     

    Speaking of, I've been working on PVP.  I wrote a pretty simple script to add some PVP arenas, which I've added to this post if anyone wants it.  It does require you to set the mapflags on these maps (pvp_n_1-5, pvp_n_2-5, and pvp_n_3-5), all of them need to have the nightmare flag removed and the nopenalty flag added, and the first arena needs noparty, and the last needs noexp and noloot.

     

    The first two arenas are pretty straightforward, the first is FFA and the second is Team-Based.  The third arena is fun though, as it also spawns some enemies!  It can get pretty chaotic, but you might be able to use the Monsters to your advantage.  You can also just use this area to test out your builds without any risk, since you don't lose exp if you die here (though you don't get exp or drops either).

    Modding25.png.446a6cde777cd261d60b9eab62aaf612.png

     

    Finally, I also added a pity system for cards.  Whenever a card fails to drop from a monster, the rate very slightly increases until the card drops, at which time it resets.  This increase is server-wide and it doesn't persist if the server is shut down, but I think it makes card hunting feel a lot better.  It doesn't make a huge amount of difference most of the time, but it makes it very unlikely to go super dry on getting a card.  The chance of taking like 4x the expected amount of kills to get a card is now effectively nonexistent.

     

    Programming-wise this is actually pretty simple.  I might maybe eventually make a topic about it if people want it.

    pvp.txt

    • Upvote 1
    • Love 1
  10. Been on a little bit of a break after all the work I did on RO recently, but I've been filling in a bit of content here and there.

     

    For starters, I finally got marriage working.  The custom marriage script that came with my distribution had a few bugs.  I'm not sure if they are fixed in the latest version, but I've included the fixed version in this post.   Here's the happy couple.  (Not pictured their previous 6 divorces while I debugged the script)

    Wedding.png.cdea370725f939ae68d4c1c5c3231ca6.png

    In order for this to work, the wedding rings need to be marked as married partner tradeable, which they weren't initially in my distribution (this is bit flag 511 in item-trade.txt).  Also, for some reason, the Tuxedo was marked as an etc item, I restored it to being an equippable item as it was before.

    I've also been adding some new stuff here and there.  For starters, there's now a new dungeon in Jawaii called the Tunnel of Love.  It's accessed via this NPC in Jawaii.

    TunnelOfLove1.png.3833132f74d998bd060230a1194a2163.png

    This place is pretty unique.  For starters, he won't even let you in if you don't have your wedding ring equipped, and if you take it off in the dungeon you get warped out (this is achieved via an unequip script on the wedding ring, which only activates on this particular map).  The map itself is a reskinned version of Beach Cave North, but it plays track 172, which I think fits well with it.

    TunnelOfLove2.png.c2d53f74b89da1798d5a88fa17b638d5.png

    There are a couple new enemies here and a new boss, but it also has a lot of pairs of enemies like Poporing and Marin, and Bongun and Munak.  The boss is a fairly unique one called The Lovers, which consists of two boss-like entities who have comparable power.  The female is the "main boss", if you defeat her they both die, and the male enemy is the summon, but she will only summon him on spawn and never resummons him if he dies.  As long as he's alive, he tries to heal her and cast buffs on her, so you kind of want to target him first, but she starts using NPC_POWERUP once he goes down (this uses the same check on number of living slaves that bosses typically use to respawn their summons).  They drop a couple different things, but the real prize is the Lovers' Ring, a slotted accessory that gives an incredible +2 to all stats, making it easily the best accessory in the game.  The catch is that it only works if you're also equipping your wedding ring in the other slot, which significantly limits its power.  Actually, pretty much everything unique you can get in here is connected to the wedding ring in some way.  I mainly wanted a way to make wearing the wedding ring kinda viable.  Obviously, under normal circumstances you just keep it in your inventory and only swap to it when you want to use the wedding skills, but I think this gives you some fun options if you'd prefer to keep it equipped.  This also means that for characters who are single, the fact that they can't come to this dungeon isn't a big deal.

     

    I also added a boss based on Red Scar from Ragnarok 2 to the Cave Dungeon in the past.

    Modding22.png.759b1a6d72c921fafa2ebc7d31c4e231.png

    This area bares some resemblance to where you fight him in RO2 and RO2 takes place in the past compared to RO1, so I thought it was a fun little touch.  He's quite an easy boss, not much more powerful than GTB, which makes sense because he was one of RO2's earliest bosses and this area is one of the first you can access in the past.  I also don't know if I ever talked about the Humanoid Chimera pet.  She's the hardest pet to get in the entire game (she requires killing T_W_O, who is close to Satan Morroc in power), but her pet skill is that she can give you Soul Link.  This actually uses a completely new skill called "SL_OMNI" which calls all of the other soul link spells depending on the target's class.

     

    You might be wondering how I created these new bosses.  Actually, it was very easy.  You can probably tell that they're using the sprites of existing enemies, namely Succubus, Incubus, and Desert Wolf.  RO has a file in the System subfolder under the client folder (this is also where iteminfo.lub) is located that the game uses to dynamically apply certain sprite effects to various enemies.  They use this to create quite a number of the enemies in the game.

     

    The file is monster_size_effect_sak_new.lub.  It's quite easy to understand and modify, the entries in the list are just the Monster IDs, then there's a list of effects to apply to them.  For Red Scar, his effects look like this.

        [2546] = {
            MonsterSize = 1.5,
            MonsterEff = { EFFECT.EF_GREEN99_3, EFFECT.EF_GREEN99_5, EFFECT.EF_GREEN99_6, EFFECT.EF_REDLIGHTBODY }
        },

    So what this does is it takes Desert Wolf's sprite, makes it 1.5x the size, then applies 4 effects to it.  The first 3 create the "boss aura", while the last colours him red.  And presto!  It's a vaguely new enemy sprite!

     

    In terms of things that weren't so simple, there's also this place.

    EndlessSands.png.028290ec87daf2a1ec86c2ae21fc0e8a.png

    This is the Endless Sands dungeon, which is found in the past.  Unlike other things I added, this is a totally new map that I made from scratch.  It's not fancy or anything, it's mostly just some bumpy terrain with some cacti and a sand texture, but I like it.  This dungeon is also a maze, where each screen has multiple exits but only one leads forward.  The Pixy Porings also appear here, and they have pretty good stuff, though they're pretty strong for porings.

     

    Should you make it to the exit, you can reach Valhalla!  It's actually just the Lasagna field maps, but I think it looks kind of heavenly.

    Valhalla.png.00aca633909ad576201246076b8b54f5.png

    This is the most dangerous area in the entire game.  There's a ton of new enemies and gear here, but the enemies have comparable power to Odin's Tower and since this is in the past all enemies deal double damage and take only half.  Defeating the Wish Maiden (who actually uses a different sprite that's from a newer version of the game) will not be easy.  You're probably going to want at least a couple boss cards before you come here.

     

    I feel like I'm probably mostly done with PVE content now, the next big thing I'll have to figure out is all the PVP stuff.  The amount of stuff to fiddle with never ends.

    marriage.txt

    • Upvote 2
  11. A quick update.  Under latest Rathena, the way statuses are referenced has been changed.  So if you're trying to apply the following code tweak.

     

    On 10/31/2022 at 8:29 PM, Tero said:

    In status.cpp, there are some Doram-specific buffs that affect Matk.  These are only applied when in renewal mode, so these buffs have no effect under PRE-RE without a code change.

    To make these work, you need to add the following to the method "status_calc_matk" in status.cpp.  

    	if (sc->data[SC_CATNIPPOWDER])
    		matk -= matk * sc->data[SC_CATNIPPOWDER]->val2 / 100;
    	if (sc->data[SC_CHATTERING])
    		matk += sc->data[SC_CHATTERING]->val2;
    	if (sc->data[SC_DORAM_MATK])
    		matk += sc->data[SC_DORAM_MATK]->val1;

    They go right before the line:

    return (unsigned short)cap_value(matk,0,USHRT_MAX);

     

    You now need to use the following code instead.

    	if (sc->getSCE(SC_CATNIPPOWDER))
    		matk -= matk * sc->getSCE(SC_CATNIPPOWDER)->val2 / 100;
    	if (sc->getSCE(SC_CHATTERING))
    		matk += sc->getSCE(SC_CHATTERING)->val2;
    	if (sc->getSCE(SC_DORAM_MATK))
    		matk += sc->getSCE(SC_DORAM_MATK)->val1;

     

    I think the rest of it is still fine, but it's quite possible that some of these issues might have been fixed by now.

  12. It was brought to my attention that some users encounter an error when trying to use the new Summoner palettes.  It looks like for newer client versions, the summoner palettes are stored in a new location, which I've also added to the GRF file (by duplicating the palettes, but palette files are super small).  Hopefully this should now work for people using the newer client as well.

     

    I've also now updated the GRF to include the palettes for the Summoner's mount as well.

  13. I've been sick for the last week, which is lame, but it means I basically had nothing to do but work on RO, so I can actually show off my secret project a little earlier than expected.  It's a massive new expansion to the game that adds about 65 new maps.

     

    It all begins with this NPC in Morroc:

    ThePast1.png.8b67ffc451192b81cee10555743253d1.png

    He tells you about Satan Morroc, which is kind of important because fighting him is quite different on my server.  

     

    Next, you have to go ALL the way to the end of the New World to find Satan Morroc and kill him (or rather, be alive and on the map when he dies).  Moro_Vol is where Dicastes would normally be.

    ThePast2.png.1ba680460e8155fd71097c0b85b43106.png

     

    We then return to the old man to learn of a secret mission.  It turns out the old man is actually a very aged version of Thanatos, who sealed Morroc orriginally.  Unfortunately, Satan Morroc will revive endlessly, so if we want to get rid of him for good, we would have to travel back in time to the past and kill Morroc the wizard, before he ever became Satan Morroc.

    ThePast3.png.d94c7a856203a01de9a8eb91ddc56919.png

    As part of this mission, we have to be reborn again.  Assuming you're already max base / job level, we are converted back into a novice (albeit, a very special novice), and we're whisked off to the past.

    ThePast4.png.fa713b448503a182ec064e943e1207d3.png

    If this place looks different, it's because we're actually in the world from the Alpha!

    ThePast5.png.e8c7c1413e417b2e57effb57ce79a4bc.png

    There's a lot to know about the past maps.  For starters, you're stuck here for a while.  You can't return to the present until base level 80 (you're warned about this ahead of time), not even Warp Portal, Guild Recall, or the Marriage skills will get you out.  The Past maps have a special map flag, and if you try to warp between two maps that don't have the same setting for that flag, it doesn't let you.

     

    Secondly, the monsters here are much tougher.  All monsters in the past do double damage and take only half.  This is also handled via a mapflag.

    A Poring does 28 damage?!  Better get Vit!

    ThePast6.png.d1e304235ce084c496a9f4a70cc98a99.png

     

    However, it's not all bad, you're stronger too.  As a second transcendent character, which are called Time Travelers, you have the standard increased HP and SP totals (which go beyond even what Transcendent characters get), but you also get some new bonuses.  Your second job can gain 10 more levels (this is why jobs with low skill point totals needed more skills), which also means more job bonuses.  Everyone also gets one new skill (which you learn for free upon becoming a Time Traveller) called Time Slip, which gives you 2 seconds of total invincibility and can break out of control effects.  However, it has a 5 minute cooldown.  Perfect for a quick escape when a Lunatic hits you for over half your HP in one hit!  This must be revenge for all the Lunatics I murdered in the present.

    ThePast7.png.3482d896f8d17d567e40c0e095232a14.png

     

    There's all kinds of new stuff in the past.  There's about 15 new bosses and a ton of new enemies.  Most of the dungeons are from the alpha, but a few are areas I didn't use previously, like Orc's Memory, which becomes the past version of Orc Dungeon.

     

    You can visit Glast Heim before it got destroyed, which I think is cool.

    ThePast8.png.6ab19e865dff0d897689438687e98d4f.png

    This area uses the elemental knight enemies, which apparently are from Puzzle and Dragons.  I actually created the Wind Knight by heavily editing the Stone Knight, as there wasn't a Wind Knight initially.

     

    You can visit the first ever Kafra, back when it was just a lowly inn (it's located roughly near where Aldebaran would be on the map, which I think is a fun little touch as Kafra headquarters is there).

    ThePast9.png.704bbff5b88731014a9e0cc9d5a98d9b.png

     

    You can visit the future site of Gonryun and talk to the kid who turns people into Soul Linkers (on my server, he's in Gonryun).  He can trade you some headgears.

    ThePast10.png.65b8f242c867f5f2e1718e660b029ade.png

     

    You can head to the desert town that will eventually be called Morroc and hear the original, undestroyed version of the Morroc town theme!  So nostalgic!

    ThePast11.png.b91ac5c80ae50e3b5affca521b30743e.png

     

    And of course, you can fight your way through Morroc's fortress to reach Temple of the Demon God and defeat Morroc once and for all.  He's actually a 2-stage battle, where you fight his younger form first before fighting Despair God Morroc.

    ThePast12.png.2886f51db85f125aced3eff8cb8c80d1.png

     

    Some of the new enemies drop cards that you can use to gain access to some of the third-class skills (generally the weaker, non-class defining ones), like this one that lets you use Axe Boomerang.

    Thank the gods!  An attack skill that doesn't cost money to use!

    ThePast13.png.193735cf6d90959015b045ce16999c44.png

     

    Of course, there's all kinds of cool new equipment too.  One of my favourites is a scythe called the Soul Eater that lets you cast Soul Breaker.

    Casting Soul Breaker with a Scythe is actually the sickest thing ever.

    ThePast14.png.1d5a4b13fc55defb686aa6cc1ee60f56.png

     

    There's way too much to possibly go over.  While nowhere near the size of the present map, the past maps probably add around 15% more content to the game.  Plus, it's just super cool to be able to run around the areas from the Alpha.  I've had this idea cooking up in my head ever since I saw the game's original intro video, which showcased the alpha maps.  Combined with the fact that I had been considering adding Despair God Morroc into the game, it just made too much sense to do it this way.

     

    Programming-wise, this was not a particularly complicated change, it was just a ton of map editing, scripting, and database entries.  None of the past maps came with warps, of course, so I had to make all of those, as well as all of the NPCs, and all of the stats for the new enemies, none of whom existed in any database.

     

    You might be wondering why I decided to add another rebirth instead of just adding in the third jobs.  While that certainly would have been possible, I feel like there's just no way to balance the third jobs within PRE-RE.  Pretty much the entire reason Renewal exists is to drastically revamp the game so that third classes can exist, otherwise they'd just one-shot everything in PRE-RE and have way too much health and stats for anything to be a threat to them.  The brilliance of transcendence is that it adds a lot more playtime for a fairly small increase in total power.  Plus, if I did keep you at a high level, the past maps would have to contain purely endgame-level enemies.  This way, they can have the regular enemies, closer to what they might have had originally, but it still provides a challenge.  Plus, not all of the classes have another job available, like Summoner for example.

     

    You might also be wondering why everything in the past does double damage.  This is mainly so that it's still challenging.  When you rebirth the first time, the game becomes easier, because you have better stats and equipment but the enemies don't become any harder until you venture into the hardest dungeons, like Odin's Temple and Thanatos Tower, which you probably won't visit before you rebirth.  I've done a ton of tweaking of the transcendent exp curves to try to stop transcendent characters from feeling trivial to level, but it's still definitely a little on the easy side.  Playing in the past is interesting because it's actually harder than playing the game the first time, you really have to use all the tools at your disposal to avoid becoming Lunatic chow.  If you never made good equipment for first-job characters, now's the time to do so.

     

    Of course, I'm sure there's still a ton of bugs to fix and balancing to do, but this will probably be the last major thing I add to the game (granted, I've said that before).  There does eventually come a point where the game just has enough stuff.  Now I should actually probably spend some time playing it instead of just scripting stuff all the time.

    • Upvote 1
  14. I put up a guide on how to make a custom pet in another part of the forum which goes over everything about making them in a lot of detail.

    The short version is that you need to modify petinfo.lub, which is stored inside the datainfo folder (you can just search for it with GRF editor).  Of course, you need to add the new illustration to the GRF file as well.  If you want to make the pets talk, that's also in the GRF file, in pettalktable.xml.  The thread explains more about how to modify these.

     

    As for the images, I'd love to say there's an easy way to get these, but there's not really.  I just search for the pet I want to make on Google, and if there's a good piece of fanart, I use that, if not, I meticulously edit the card art.  In some cases I even have to redraw parts of the art that are cut off, for example in the picture above the card art actually cuts off Pere's fingers on one hand so I had to draw them, luckily the resolution is low so you can't tell.  Of course, if you're not a crazy person you could just use one of their sprites or something, which I did for a couple monsters whose card art wasn't suitable.

    • Upvote 1
    • Love 1
  15. On 11/7/2022 at 9:04 AM, Scamper said:

    So far everything works fine except Catnip Meteor. If I use it the Map Server crashes.... 

    Haha, you're right!  I just tried it and it crashed my server too!  Good thing no one else was playing a magic cat!  Easily fixed though.

    The problem is we forgot to update skill_unit_db.

    If you have skill_unit_db.txt, paste the following into it:

    5027,0x106,   ,  1:1:2:2:3, 0,  -1,enemy, 0x2010 // SU_CN_POWDERING
    5028,0x86,    ,  0, 3, 500,enemy, 0x10 // SU_CN_METEOR
    5042,0x86,    ,  0, 3, 500,enemy, 0x10 // SU_CN_METEOR2
    5048,0x107,   ,  2:2:3:3:4, 0, -1, enemy, 0x2010 // SU_NYANGGRASS

     

    No more crash!

    CN_Meteor.png.b1543eea1cd6e33a6584240c5a446ea0.png

     

    If your rathena is the latest version, the content of skill_unit_db has been incorporated into skill_db.yaml, so I don't think you should experience this crash.  If you somehow still do, make sure the Unit settings inside skill-db.yaml got copied properly.

     

    I also discovered one more problem.  Currently, if your cat is level 99, it will still show the exp bar, and cat does not get an aura, either.  This is because some of the settings in ExternalSettings_kr.lub are wrong.  We edited this in the first step, but it turns out we have a couple more changes to make.

     

    At the top, there is a "MaxLevelTable".  Find the "BaseLevelDoram", and put this:

    BaseLevelDoram = 99,

     

    Might want to update BaseLevelHomun to 99 too, though this is unrelated to cats.

     

    Now the EXP bar disappears at level 99, and Doram can get an aura.  However, currently it's not the same aura as everyone else.  If you want it to be, find the "MaxLevelAuraTable" section below, and replace it with the following:

    MaxLevelAuraTable = {
    	Default150LvAura = LEVELAURA.EF_LEVEL99,
    	Default150LvAura_sub = LEVELAURA.EF_LEVEL99_ORB1,
    	Default160LvAura = LEVELAURA.EF_LEVEL99,
    	Default160LvAura_sub = LEVELAURA.EF_LEVEL99_ORB1,
    	Default185LvAura = LEVELAURA.EF_LEVEL99,
    	Default185LvAura_sub = LEVELAURA.EF_LEVEL99_ORB1,
    	HomunMaxLvAura = LEVELAURA.EF_LEVEL99,
    	HomunMaxLvAura_sub = LEVELAURA.EF_LEVEL99_ORB1
    }

    And Presto!  Aura Cat!

    AuraCat.png.50396b9311e79a17a5d8abafdf703446.png

  16. To no one's real surprise, it didn't take long after I learned how to make new skills for me to go mad with power.

     

    Something that's always bothered me is that some classes barely have more skills to take than they have skill points.  The two worst offenders are Thief and Archer, who have 51 and 50 total points of skills respectively.  If you max your first job, you get 49 job points, which leaves you with only 2 / 1 skill levels not to take.  This is pretty dumb and effectively gives you no freedom in how you build these classes.  So these were the first ones to address.

     

    For Thief, they now have two new skills, Gouge and Reprieve, both of which are passives.

    NewSkiils1.png.2faccae1c39210bd35df4c9e7df9311c.png

    Gouge is a 10-level skill that gives you a chance to inflict Bleeding when regular attacking with a dagger-class weapon, or when using Back Stab.  When it came to thief, I feel like the idea behind the class is to use a lot of auto-attacks, so I wanted a new offensive skill that fit with that playstyle.  I don't think I'd usually take this on Sin, but I guess it could be useful to double dagger Sin.

    Reprieve is a 5-level skill that allows you to get a little bit of HP recovery while Hidden / Cloaked / Chase Walking.  The recovery isn't much, and the requirement to take Hiding level 10 is steep, but it can add up over time, particularly with Cloaking.  I think this skill is pretty good, but you'll have to give up one of the other skills to get it.

     

    Speaking of Bleeding, it's a bit annoying to attack with because by default, there's no indicator when a target has been successfully hit by it.  Maybe my client is just out of date, but I added one anyway.  Now, when you bleed a target, they do this.

    NewSkiils2.png.79673687334914578be9fafb5c9004ec.png

     

    If you want this functionality in your server, it's quite easy to add.  Just find this in skill.cpp

    		case SC_BLEEDING:
    		case SC_BURNING:
    			tick_time = status_get_sc_interval(type);
    			val4 = tick - tick_time; // Remaining time
    			break;

    Remove the "case SC_Bleeding" line, then insert this below:

    		case SC_BLEEDING:
    			tick_time = status_get_sc_interval(type);
    			val4 = tick - tick_time; // Remaining time
    			clif_emotion(bl, ET_HUK);
    			break;

    I also added something similar for Crystalize as well, as that also didn't have any kind of visual display.

     

    Moving on to Archer, it also has two new skills.

    NewSkiils3.png.d3a3f1c89bf6c6187f16a11ad9277884.png

    Bullseye is a 10-level skill that increases your crit rate and damage.  This is an awesome skill, on a class that would almost never use it.  I guess if you're building for some kind of high-aspd auto-Blitz Beat build you could take it, but generally I just liked the idea behind it.

    Organization is a 5-level skill that increases the amount you can carry before you're considered to be overweight by 5% per level.  On the other hand, this is a skill I really want on a low-STR character like Archer.

     

    These skills bring Thief and Archer up to having 66 and 65 skill levels available.  Much better!  Now, the lowest is actually Merchant at 61.  So I also gave Merchant one new skill in Lucky Pennies, which adds a small chance to find a bit of Zeny after killing an enemy, similar to the Cramp card.  It probably won't offset the money you're burning on Mammo, but at least it's something.  Super Novice can also learn all 5 of these skills.

     

    But of course I wasn't done there.  Hunter also has much the same problem as Archer where it just doesn't have enough skills to take,  Technically it has 82, but the vast majority of these are irrelevant trap skills that no one ever uses.  So I made a couple tweaks.  For starters, Blitz Beat now has 10 levels.  I've done this with a few skills, and it's generally the case that at level 10, the skill is a little better than it used to be at level 5, but of course you have to spend 5 more points on it.  In Blitz Beat's case, at level 10, it now hits 6 times (it used to hit 5 times at level 5), and the chance of auto-blitz beat improves.  You'll want to max it, too, because Falcon Assault now relies on Blitz Beat's level for its damage calculation (Falcon Assault is essentially a max-level Blitz Beat that does bonus damage and ignores your defense).  I'm incredibly wary of buffing Falcon Assault because it was a gamebreaker in the past, but there are more cards that can defend against it now (the "MISC" defense type defends against Falcon attacks).

     

    Hunter also gets a totally new attacking skill in Tranquilizer.  This is an active skill that fires an arrow and has a chance to inflict Sleep.  It's not too powerful and requires a fair bit of SP, but I imagine this could be useful in PVP.

    NewSkills4.png.54bdf02a0639e412c7f95649db4dedf6.png

    It requires you to know the Sandman Trap, so that at least gives you a little incentive to take the trap skills.

     

    Gypsy and Minstrel also have a new passive skill that gives them a buff to their perfect dodge while dancing, and Throw Arrow / Melody Strike are also more powerful while Dancing.  Generally, I want Dancing to feel a bit more useful, particularly when soloing, as these classes tend to just build for Arrow Vulcan and not much else.

     

    However, the granddaddy of all changes was to the Star Gladiator class, which is almost a completely different character now.

    NewSkills5.png.a229449629465ac57d543edfd13ac165.png

    The biggest issue with Star Gladiator is that my server has rebirth for all classes, and Star Gladiator gets SJ_Document as a rebirth skill.  SJ_Document allows you to reset your target maps and mobs nearly for free (on my server it requires a 2-carat diamond to use), which is cool but causes a bunch of problems.  See, the thing with Star Gladiator is that the skills for the Sun, Moon, and Stars are all almost identical.  This kind of makes sense initially, as the idea is that the fact that you basically get 3 copies of those skills gives you redundancy, since those choices are permanent.  However, once they become impermanent, there's now no real reason to bother having 3 copies.  You can just focus on one of the three, and reset whenever you want to target something else.  As such, I pretty much completely redesigned all of the skills so that the Sun, Moon, and Star skills are all different from each other.

    The Comfort Skills are the only ones that were originally appreciably different from each other, so they are untouched.

    For the Warmth Skills, Warmth of the Sun is now a self-target heal, and Warmth of the Stars is now self-target Assumptio (Warmth of the Moon remains as the barrier effect).

    NewSkills6.png.cad5357172cf548f0ace680633800100.png

    For the anger skills, the Sun remains untouched in increasing your damage.  Moon now increases your damage resistance, and Stars gives you extra critical chance.

    For the blessing skills, Sun remains untouched as extra exp.  Moon gives you extra drop rate (albeit, not much extra as drop rate is very centralizing), and Stars gives you bad status resistance.

    Finally, Star Gladiator also has a bunch of new skills.  Taekwon Mastery is a passive that increases the chance to activate Taekwon Kicks.  You also need it to take SG_DEVIL.  Vision of the Sun, Moon, and Stars is a transcendent passive that counteracts SG_DEVIL, and if levelled to max, you gain permanent intravision (which lets you see hidden targets).  Memory of the Sun, Moon, and Stars lets you warp to the map you set as your special map from anywhere (if used on the map itself, it acts like teleport level 1).  Wrath of the Sun, Moon, and Stars is a strong debuff to attack speed and defense that you can use on any of your target mobs, and it's one of the only debuffs in the game that does work on bosses.  Finally, there are 3 powerful new Magic attacks, Power of the Sun, Moon, and Stars.  These are strong, uninterruptable spells, but they can only be used on the appropriate Map, or against the appropriate Target (ie, you can use Power of the Moon against any enemy on the Moon map, or against the Target of the Moon, on any map).  Besides being strong, these also inflict status effects, Burning for Sun, Crystallize for Moon, and Paralyze for Star.  Of course, the caveat is that this requires you to take at least some Int if you want them to do any real damage.

    NewSkills7.png.03a4771bff3667b67bdf0d4a11a8471e.png

    (Why is it always poor lunatics getting obliterated by powerful attacks?)

     

    At any rate, I think this class is vastly more interesting now.

     

    The last rework is to Blacksmith.  Skill-wise, Blacksmith isn't very changed, other than that Hammer Fall can now go to level 10.  The bigger issue with Blacksmith is forging, specifically, the fact that there's no reason to ever bother with it.  The weapons the Blacksmith can forge have no slots (and cannot have slots, the game stores the forging information in the card slots), and the bonuses given from forging are small, so they're pretty much always outclassed by stuff you can find easily.  The latter issue is somewhat easily solved, I simply increased the power of the materials the Blacksmith can add to weapons.  Star Crumb now also gives a little bit of crit bonus, and if the Blacksmith is a ranker Blacksmith, their weapons also give a small Aspd bonus.  This is enough to make the top-end weapons they can forge at least somewhat viable.

    But what about the others?  Blacksmiths can forge a ton of different weapons, but even with the buffs, these are all totally worthless.  Ragnarok makes weaker weapons viable by giving them higher numbers of slots, but since all Blacksmith weapons are unslotted, the strongest ones are obviously the best.  So I came up with an inventive solution for this.

     

    Weapons forged by Blacksmiths now have unique, card-like bonuses, which differ by weapon.  It achieves this by having the Blacksmith forge the previously unused double underscore version of weapons (such as knife__), which now have bonus scripts attached to them.  For example, a knife forged by a blacksmith now gives 5 Agi and 5 Dex.

    NewSkills8.png.cd96fc4ebec74deeeae1f02eb6b9e6ea.png

    (I know what you're thinking, but this isn't instantly the best weapon to hold while making potions or whatever.  Lunatic cards give 2 luk, so with a 4 slot weapon you can get 8 luk.  It's a decent option until something better is available, though).

    Meanwhile, a Trident gives +50% bonus damage to Fish enemies.  This would be good to use with Wind element!

    NewSkills9.png.1a4c3de6b4a7ef2b54385e9171b7b751.png

    They're all different, save for the top end weapons, which have no bonuses, since they're already the most powerful.  I don't think any of the weapons you can forge have "best in class" power, but they're now things that could definitely be useful before the very best equipment is available.  It's at least much more interesting to fool around with now.

     

    Wow, this was long.  Much of this is relevant to my super secret project which I'm still working on, but that's still a long way from being finished.

    Modding21.png.b5da6ab5633635f4b4d9757d8489dc75.png

    I don't think we're in Kansas anymore, Toto...

    • Upvote 2
  17. A small update this time, but something I'm quite pleased with.

     

    Meet Pere!  Players of Renewal might recognize Pere from Jitterbug of Nightmare, which I recently implemented on my server.  (Which, as mentioned above, is PRE-RE, I've been porting all of Renewal's content to it).

    Pere1.png.ea996710610f08f05134c18f49f30b83.png

    Pere is quite special.  Besides being super cute, she can also serve as your ensemble partner!

    Pere2.png.57ff313584615ee5da19159f4a536737.png

    There are two Peres that you can get as pets, one dances and one plays the guitar, and whichever one you are, you need the other one.

    Someone on my server has been complaining since day 1 about the necessity of being joined at the hip with a Bard and I think this is a good compromise that preserves the intent of the ensemble skills while also making them a little more accessible.

     

    If you want to add this functionality to your server, it's actually pretty easy from a coding perspective.  You just have to find the method "skill_check_condition_castbegin" in skill.cpp, then find this code:

    	else if(inf2[INF2_ISENSEMBLE]) {
    	    if (skill_check_pc_partner(sd, skill_id, &skill_lv, 1, 0) < 1 && !(sc && sc->data[SC_KVASIR_SONATA])) {
    		    clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
    		    return false;
    	    }
    	}

    And replace it with this:

    	else if(inf2[INF2_ISENSEMBLE]) {
    		// check to see if we have the ensemble pet
    		bool ensemblepet = false;
    		if (sd && sd->pd) {
    			if ((sd->status.class_ == JOB_BARD || sd->status.class_ == JOB_CLOWN) && sd->pd->pet.class_ == 3069 && sd->pd->pet.intimate > PET_INTIMATE_LOYAL) {
    				ensemblepet = true;
    			}
    			if ((sd->status.class_ == JOB_DANCER || sd->status.class_ == JOB_GYPSY) && sd->pd->pet.class_ == 3070 && sd->pd->pet.intimate > PET_INTIMATE_LOYAL) {
    				ensemblepet = true;
    			}
    		}
    		if (!ensemblepet && skill_check_pc_partner(sd, skill_id, &skill_lv, 1, 0) < 1 && !(sc && sc->data[SC_KVASIR_SONATA])) {
    		    clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
    		    return false;
    	    }
    	}

    Of course, you also have to pull everything from Jitterbug of Nightmare into PRE-RE, then implement the Peres as custom pets, but at least the coding part is simple!  (alternatively, you could just use a different pet, like maybe a Rocker or something, you can just change the id number it looks for in the pet.class_ part).

    • Upvote 2
  18. You have to recompile the server using visual studio after making changes to the source code.  If you have visual studio already, just open up rathena.sln and select to "Build Solution", otherwise you might have to download it (it's free).  Make sure to install the files to compile C++.  I'm pretty sure there's guides on it somewhere.

    • Upvote 1
  19. I don't think you should need to remove sections 2 and 3, but it looks like it should work.  You recompiled your server and restarted after making the change and it still doesn't work?

     

    Just tested it myself, with the change I suggested in the first post, it works, I can now steal repeatedly from the same enemy.

  20. This is the line that blocks the steal attempt

    if(md->state.steal_flag == UCHAR_MAX || ( md->sc.opt1 && md->sc.opt1 != OPT1_BURNING && md->sc.opt1 != OPT1_CRYSTALIZE ) ) //already stolen from / status change check
            return 0;

    In particular, md->state.steal_flag is set to UCHAR_MAX after a successful steal.  You could simply remove that part of the line to allow stealing from that monster again and again.

     

    if(( md->sc.opt1 && md->sc.opt1 != OPT1_BURNING && md->sc.opt1 != OPT1_CRYSTALIZE ) ) //already stolen from / status change check
            return 0;

    Or you can just remove that code entirely if you don't want anything to block stealing attempts.

     

    Also, leave the configuration for steal_max_tries at 0, that disables it.

  21. I've been fiddling a lot with skills lately.

     

    For starters, I've been playing Sage.  Sage has always felt like a bit of an underwhelming class to me.  A big part of this is that it gets very few new damage spells.  So I made a new one.

    Modding16.png.e38c9a015b5cb7bd8c315d1b07e3bfbe.png

    Poison Splash is basically just Poison-element Fire Ball, it does AOE Magic Poison damage and can also inflict the Poison status.  On my server, Poison does extra damage against Neutral (I think this makes sense, since Assassins use it and the main targets that are Neutral are players), so this spell is quite useful against Ridewords and the like.  I also think it works well for Sage since Sage is intended to be a PVP-focused Mage and this is a pretty decent PVP spell.  That said, you have to watch out because a number of enemies can cast this spell against you!

     

    I also buffed Professor's Memorize skill, which I've renamed to Lecture.  Like the Summoner Buffs, it now also applies this buff to all party members on the screen.  I think this makes thematic sense with the class being called "Professor" but doing no actual teaching previously.  It was also a move which, in my opinion, didn't have a ton of utility for Professor, as they tend to either use fast-casting spells or autocast, but has a ton of potentially interesting utility for other characters and enhances the "Support Sage" playstyle.

    Modding17.png.c4cdee80168d8c327b6f2ca6838595e2.png

     

    Beyond this, something I think is super cool is that I've added some cards that allow you to cast previously enemy-only skills.  For example, here my Paladin has the Dark Priest Card, which allows you to cast Soul Strike of Darkness.

    Modding18.png.1fd324683b645087624b49a6adf28a31.png

    It even has a proper description in the skill window and everything.

    Modding19.png.6a729d7e72207ef5af29bc5f72bf7f7a.png

    This was surprisingly painless to pull off.  You need to add entries for the enemy spells (in this case NPC_DARKSTRIKE) to skilldescript.lub and skillinfolist.lub (these are in the GRF file under skillinfoz), and add entries for the spell in skill-cast-db and skill-require-db and that's about it, then just have the card script look something like "skill "NPC_DARKSTRIKE", 5;" and you're good to go.

    I have cards like this for Grand Darkness, Darkness Jupitel, Blood Drain, and Energy Drain, but none of them are easy to get your hands on.  Still, it's cool to have more options for dealing Darkness damage.

     

    I also almost completely reworked Endless Tower.  For starters, I moved it.  It was originally accessed via Alberta, like far too much of the game (like 8 different towns are accessed through there), so it's now where Misty Forest Labyrinth used to be at Bifrost Field 1.  The condition where you have to wait a week between attempts is also now gone, you can now play it as much as you like, but creating the instance costs 500k Zeny.

    The difficulty of the tower has also been rebalanced.  Previously, it was kind of ludicrous, forcing you to fight many of the hardest bosses in the game, like Ifrit and Beelzebub.  You now generally fight the low to mid tier bosses, with a number of bosses who didn't previously appear in the tower, like Gopinich, Boitata, and Stormy Knight making an appearance.

     

    I also tweaked the enemies that spawn on pretty much every floor.  There's generally less of them, and they're themed based on various locations in the game.  For example, can you identify the map that this floor is based on?

    Modding20.png.62a930c046286a1101dffd57e8e03d38.png

    I also gave Endless Tower a huge music buff, in that it now plays the previously unused track 168 (well, this is used for Lasanga dungeon in Renewal, but that map isn't in Pre-Re), which I think fits perfectly with this dungeon.  If you ever want to edit which songs play where, this is very easily done by editing mp3nametable.txt, which is in root folder of one of your GRF files.  (I also restored Track 67, which currently doesn't play anywhere, it now plays on the maps north of Yuno).

     

    There are also kafras and shops within Endless Tower (though the Kafras only allow you to use the storage. no saving), to somewhat mitigate how absurdly many items you tend to get here.  Additionally, when you clear floors 25, 50, 75, and 99, the warp in the first room is replaced with a new warp that takes you to the appropriate floor (the concept of the Ashes is removed).  Overall, I think this makes this dungeon a lot more fun.

    • Upvote 2
    • MVP 1
  22. My cat is finally rebirthed!  I can't believe nothing broke!  He even got the correct number of status points and everything.  I'm the king of scripting.

     

    Back to Toy Factory for me.

    Modding11.png.9e2cd22c2c10d0aeac56fb4b099d9e43.png

     

    Now I can learn the cat's (originally) post level-100 skills.

    Modding12.png.94340d6d0ca8704cc7947df6b7f23544.png

     

    Besides all the new content, my server also has a boatload of skill tweaks (this is part of why I don't just share my code directly, there's hundreds of changes most people probably won't want).  For example, the first skill in each of the cat skill trees can now level to 10 instead of 5, to give you more options in terms of how you spend your points pre-rebirth.

    Modding13.png.cd41921c78e33d39904df397e62b1e3a.png

    The initial skills for Summoner are also buffed, particularly the nearly-useless Bite and Scratch.  These are both worthless 200% damage skills initially, that you would literally never use once you have anything else.  I tweaked it so that they now have 100 + <your base level> * 10 % attack, (only *5 for scratch).  Bite also has a chance to Stun and does more damage to weakened targets, making them very viable at high levels, with the caveat that Bite is a melee skill with cast time, so unless you have uninterruptable cast, a ton of flee, or tons of cast speed reduction you're going to get hit out of it a lot.  At any rate, I think this is interesting because this now means you could go healer cat and have a fairly viable form of offense that requires no further skill point investment, though obviously the loss of the range from Picky Peck is an issue.

     

    Soul Attack is also now a 5-level skill which functions similarly to a mastery skill, and enables long range attack at maximum level.  This is a fairly substantial nerf, but mastery skills on my server work like they do in the newest version of the game, where they increase your atk rather than final damage, so they're not worthless.

    Modding14.png.d1afb55c7e7ed9aa77c83348a2e83bef.png

     

    Summoner also has, initially, probably the single most broken skill in the game in Silvervine Root Twist.  This is a ranged skill with instant cast that completely freezes the enemy's movement with 100% success rate for 10+ seconds.  I shouldn't need to tell you how ludicrously busted this is on a character that has powerful ranged attacks.  The second you learn this skill, you are essentially completely invincible to almost all normal mobs.  I was able to waltz into area 30+ levels above me with no issues by just grabbing anyone who looked at me funny.  I have no clue who looked at this skill and thought this was fine.  Obviously this had to be adjusted.

     

    On my server, Silvervine Root Twist has a 1.5 second cast time and about 1/4 the duration (4 sec at max level).  It's still a ludicrously good skill which I think almost any build wants to take, but it no longer completely explodes the game balance.

    Modding15.png.2e2fabee27bb68f581f7201615318aed.png

    Stop hitting me!  I'm supposed to be invincible!  (Not pictured: my untimely death)

     

    On the flip side, Scar of Tarou is greatly buffed, in that the damage over time effect is greater and can work on bosses (albeit at only 25% of the power) if you have Spirit of Life.  With the aid of a powerful tank, Scar of Tarou can handle almost all your DPS needs, so that could be another interesting option for support cat.  The only issue is that its power scales with STR instead of DEX, as it does in the base game, so if you have no STR it will be weak.

     

    Speaking of, I've even tweaked the way the stats work slightly.  For example, every time you get 10 VIT, you now get a point of DEF.  I always thought it worked this way initially, but apparently it never did.  Well, now that I have absolute power, I can make it work however I want.  Actually, every stat gives you some kind of bonus for every 10 points now.

     

    The sky's the limit in terms of what you can do with this game.  I've tried to generally stick to (my interpretation of) the general balancing of the game prior to the battlegrounds update, since I wanted to make the game what I think it might have become if Renewal had never existed, but you could take it in pretty much any direction you want.  This game really is a modder's dream come true.

    • Upvote 2
  23. Additionally, while most headgear items are available as costumes, a few aren't.  Should you find a headgear item you want that isn't available, it's easy to add it yourself.  The code looks through item IDs 19433 to 20499 for costumes, so add your new items to gaps within this range to put them into the game.

     

    Let's take this example of the Monk Hat.  It doesn't have a costume entry, so let's create one.

     

    If using item-db.txt:

    First, find another entry to use as a template.  Let's use this one here for the Costume Angel Wing.  Note that it's important to choose a headgear that uses the same slots as the item you want to create, or use SDE to update the slots for the item afterwards.

    19529,C_Angelic_Chain,Costume Angel Wing,4,0,,0,,0,,0,0xFFFFFFFF,63,2,1024,,1,0,38,{},{},{}

    The costumes are all very similar, so we don't have to do much.  The main thing we need to change is the View ID, which determines which sprite will be shown when wearing the costume.  This is the last entry before the 3 sets of brackets.  The Angel Wing has a view ID of 38.

     

    Now, we need to find the original entry for the Monk Hat.  Here it is:

    2251,Holy_Bonnet,Monk Hat,4,30000,,100,,5,,0,0x00008110,7,2,256,,0,1,35,{ bonus bMdef,3; },{},{}

    All we care about is the view ID, which is again before the 3 brackets.  Its view ID is 35.

     

    Now, we just copy paste the Costume Angel Wing line, while making changes to the first number (the id), as well as the following two fields (the item's name) and changing the view ID, like so:

    19434,C_Monk_Hat,Costume Monk Hat,4,0,,0,,0,,0,0xFFFFFFFF,63,2,1024,,0,0,35,{},{},{}

     

    Now we just paste that into the item-db and the Costume Monk Hat exists. 

     

    If using item-db.yml

    The steps are the same if using the yaml version of the item-db, the formatting is just a little different.  Again, let's find the Costume Angel wing to use as a template.

      - Id: 19529
        AegisName: C_Angelic_Chain
        Name: Costume Angel Wing
        Type: Armor
        Locations:
          Costume_Head_Top: true
        ArmorLevel: 1
        EquipLevelMin: 1
        View: 38
        Script: |
          bonus bUnbreakableHelm;
          bonus bVit,1;
          bonus bAgi,1;

    I note that apparently by default, this item had stats.  I personally removed the stats from all costume items on my server, which is as easy as removing the "script" portion of this definition.

    Now, let's swap out the values for the Monk Hat, as above.

      - Id: 19434
        AegisName: C_Monk_Hat
        Name: Costume Monk Hat
        Type: Armor
        Locations:
          Costume_Head_Top: true
        ArmorLevel: 1
        EquipLevelMin: 1
        View: 35

    Paste this into item-db.yml and we're good to go.

     

    Updating the Description file:

    We're not quite done yet.  While we can now trade for this item, it'll show up as "Unknown Item" due to the fact that it doesn't exist in iteminfo.lua.  This is present in the System subfolder inside your client folder.

     

    There are entries for every item in the game.  To start, let's copy the one for the non-costume Monk Hat.  This is what my file has.

    [2251] = {
    		unidentifiedDisplayName = "Hat",
    		unidentifiedResourceName = "ĸ",
    		unidentifiedDescriptionName = { "Unknown Item, can be identified by using a ^6666CCMagnifier^000000." },
    		identifiedDisplayName = "Monk Hat",
    		identifiedResourceName = "¼ºÁ÷ÀÚÀǸðÀÚ",
    		identifiedDescriptionName = {
    			"A ceremonial hat worn by monks that contains a sacred force which offers protection from evil.",
    			"Mdef +3",
    			"Class:^6666CC Headgear^000000",
    			"Defense:^0000FF 5^000000",
    			"Position:^6666CC Upper^000000",
    			"Weight:^009900 10^000000",
    			"Jobs:^6666CC Acolyte^000000"
    		},
    		slotCount = 0,
    		ClassNum = 35
    	},

    Now we just make a few small changes, by pulling some related values from another costume entry, to get something like this.

    [19434] = {
    		unidentifiedDisplayName = "Hat",
    		unidentifiedResourceName = "ĸ",
    		unidentifiedDescriptionName = { "Unknown Item, can be identified by using a ^6666CCMagnifier^000000." },
    		identifiedDisplayName = "Costume Monk Hat",
    		identifiedResourceName = "¼ºÁ÷ÀÚÀǸðÀÚ",
    		identifiedDescriptionName = {
    			"A ceremonial hat worn by monks that contains a sacred force which offers protection from evil.",
    			"Class:^6666CC Costume^000000",
    			"Position:^6666CC Upper^000000",
    			"Weight:^009900 10^000000",
    			"Jobs:^6666CC All^000000"
    		},
    		slotCount = 0,
    		ClassNum = 65

    And we're done.  The Monk Hat is now a fully functional costume item.  You can use the same steps to add any other missing costume items that you come across.

    CostumeMonkHat.png.75fe5436b0763a7da6ecc26ed820dd54.png

  24. This is not tested under renewal.  I think it should still work, but test it with a GM character first.

     

    The default implementation of Homunculi is kind of obnoxious.  When you create one, you get one of the homunculi at random, and in order to get another one, you have to completely delete them from existence.  Wouldn't it be nice if you could keep the other homunculi to use later?  Well, now you can!

     

    EmbyroMod.png.e55978e9e9d6e87afd4d0252a4dfeba1.png

     

    What it does:

    - When you use rest, the Homunculus returns to its Embyro.

    - You can use Call Homunculus to call it back out, just as it was when you rested it.

    - You can store the Homunculus for later use, allowing you to raise a different Homunculus, which is not normally possible.

    - Only you can call the Homunculus back out.  If another alchemist tries to call it, it doesn't let them.

    - You can still delete the Homunculi as normal to remove them from existence completely.

     

    How it works from a technical perspective:

    - When you rest the homunculus, it is technically "removed" from you, similar to deleting it, but it returns an embyro with the Homunculus id set to its card[1] slot.

    - When you call out a Homunculus from an Embyro, if the embyro has a value in its card[1] slot, it restores that Homunculus instead of creating a new one.

     

    Some minor limitations:

    - It's not possible to distinguish embryos from each other, and call homunculus will always try to call the first one it finds in your inventory.  You'll need to store the ones you don't want to raise right now, and it may take some trial and error to hatch the right one if you have a bunch.

    - The name display of the embryo doesn't work with the client I have (it seems like the client will only display the name if the card[1] slot is 0, which it's not if a homunculus is in there).  This makes it hard to tell who owns a homunculus embyro.

     

    How to implement:

    Make the following code changes:

     

    In homunculus.cpp:

    Find the method "hom_vaporize":

    First, add the following variable declarations to the top, under the existing ones:

    	int itemflag;
    	struct item tmp_item;

    Next, comment out the following line:

    hd->homunculus.vaporize = flag ? flag : HOM_ST_REST;

    Then, insert the following at the end of the method, just before the return statement.

    if (hd->homunculus.intimacy > 0) {	
    
    		memset(&tmp_item, 0, sizeof(tmp_item));
    		tmp_item.nameid = 7142;
    		tmp_item.amount = 1;
    		tmp_item.identify = 1;
    		tmp_item.card[0] = CARD0_CREATE;
    		tmp_item.card[1] = hd->homunculus.hom_id;
    		tmp_item.card[2] = GetWord(sd->status.char_id, 0); // CharId
    		tmp_item.card[3] = GetWord(sd->status.char_id, 1);
    
    		if ((itemflag = pc_additem(sd, &tmp_item, tmp_item.amount, LOG_TYPE_PRODUCE))) {
    			clif_additem(sd, 0, 0, itemflag);
    			if (battle_config.skill_drop_items_full) {
    				map_addflooritem(&tmp_item, tmp_item.amount, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0, 0);
    			}
    		}
    
    		unit_remove_map(&hd->bl, CLR_OUTSIGHT);
    		sd->status.hom_id = 0;
    		unit_free(&hd->bl, CLR_OUTSIGHT);
    		sd->hd = 0;
    		return 1;
    	}

     

    Next, find the method "hom_call":

    Find this code:

    if (!sd->status.hom_id) //Create a new homun.
    		return hom_create_request(sd, HM_CLASS_BASE + rnd_value(0, 7)) ;

    Replace it with this:

    	struct item ed;
    	int n;
    
    	// find the embryo
    	if (!sd->status.hom_id) { //Create or revive a homun.
    		if ((n = pc_search_inventory(sd, 7142)) >= 0) {
    			ed = sd->inventory.u.items_inventory[n];
    		}
    		else {
    			return false; // no embryo
    		}
    
    		if (ed.card[1] != 0) {
    			// is it ours?
    			if (sd->status.char_id == MakeDWord(ed.card[2], ed.card[3])) {
    				// revive the homun
    
    				// delete the embryo
    				pc_delitem(sd, n, 1, 0, 0, LOG_TYPE_CONSUME);
    
    				sd->status.hom_id = ed.card[1];
    				// proceed with rest of function
    			}
    			else {
    				// Cannot revive someone else's homunculus
    				return false;
    			}			
    		}
    		else {
    			// create a new homun
    
    			// delete the embryo
    			pc_delitem(sd, n, 1, 0, 0, LOG_TYPE_CONSUME);
    			return hom_create_request(sd, HM_CLASS_BASE + rnd_value(0, 7));
    		}
    	}

     

    Almost done, just one small change to make in skill.cpp.

     

    Find this line:

    	if (sd->status.hom_id) //Don't delete items when hom is already out.

    And comment it out (we never want this method to delete the embyros, since the call method now handles it).

     

    Now just recompile your server and you should have the new homunculus behaviour.

    • Upvote 1
    • Love 1
    • MVP 1
    • Like 1
×
×
  • Create New...