Jump to content

Danilov3s

Members
  • Posts

    9
  • Joined

  • Last visited

Posts posted by Danilov3s

  1. I have started the work on this but didn't have any time nor interest to finish but I could get a proof of concept working. The concept is somewhat basic but I took a different approach than the officials, where they create a clone from your character and open the stall using that clone. I used the existing system for auctions and hooked an external web app to list the auctions. That external app would be able to buy the items, notifying the running server and then the server would send mails to both the seller and the buyer with their items.

    The external app talk via REST to a NodeJS/Express server which connects to rAthena via TCP streams and exchange raw packets. It seems a bit complicated, but once you get the hang of how packets work you'll be fine.

    On the rAthena side I've hooked some methods and packets to open/close auctions and to send mails.

     

    Node/Express server can be found here https://github.com/Danil0v3s/react.cp

    rAthena modifications can be found here https://github.com/Danil0v3s/broriginal/pull/11

    And the external app I've created to use as a launcher using Electron.JS can be found here https://github.com/Danil0v3s/broriginal-launcher

     

    None of these wouldn't be possible without the help from Norminator, Nitrous, Zell and many others. If you have any questions regarding any of these, I'll keep an eye on this thread. And please, bear in mind that I haven't created any of these to be used by anyone else but me, so you won't find any comments or anything explaining anything and some solutions are completely hammered just to work

  2. Recently I heard of the new "offline vending" in official servers

    Spoiler

     

    And I've been wondering how to achieve that, either it be on a "as close as possible" basis where I  have the vending to work with inventory items and then on succesfully creating the vending the items would be removed from player's inventory and he could manage it from the server website (to cancel/change price/etc). Once cancelled or sold get the stuff back by RodEx, like in the video.

    From what I can see in the video, it looks like they create a fake cart for the player and then add the player's items to that cart and display the normal vending screen with a limited number of 4 items, since that's the max items you can send via RodEx. After proceeding with the vending, it allows you to aim and then creates a copy of your player with a vending (lol ?)

    Any directions on how to accomplish this would be much appreciated. So far I can create a vending using an atcommand I've created by cloning the contents of 

    void clif_openvendingreq(struct map_session_data* sd, int num)

    and setting a state variable to bypass the vending control which checks if the vending was opened by using the skill

    • Upvote 1
    • Like 1
  3. 14 hours ago, Humble_Bee said:

    Try looking for this in status.cpp:

     

      Hide contents

    if(sd->matk_rate < 0)
            sd->matk_rate = 0;

    And try adding right below it:
     

      Hide contents

    if(sd->matk_rate > yourdesiredmaxvalue)
            sd->matk_rate = yourdesiredmaxvalue;

    Doing something like this for regen had worked for me in making a cap. If that doesn't work, I'll probably offer a few other things to try, but I'm relatively new to messing with code as well.

    Thank you for your suggestion, but I got it working already...

    I've changed the data types from both min and max to unsigned int, and changed every place that modify these values to cast it to int instead of short, and changed the caps from SHRT_MAX to USHRT_MAX. Also did some improvements in some formulas, like instead of using matk_max = matx_max + something, just matk_max += something; And last I changed the piece of code that calls clif to do a check whether the initial matk is 0 and reduce the max matk by 1.

     

     

    80029830_549048075946703_4567140683512545280_n.png

    80307890_2913796508644014_1521707930880049152_n.png

    80469536_555482131968484_4104355870014439424_n.png

  4. Hey all! Greetings,

    Recently I've been trying to avoid the MATK infamous overflow when it reaches the maximum, but no success at all.

    I tried protecting the values from getting bigger than SHRT_MAX (32727) but still nothing changed

    I tried poking aroud in the status.cpp, and found that when it executes this piece of code at line 5239
     

    if (bl->type&BL_PC && sd->matk_rate != 100) {
                status->matk_max = status->matk_max * sd->matk_rate/100;
                status->matk_min = status->matk_min * sd->matk_rate/100;
    }

    And the matk_max is greater than 30097, the result is 87 (I'm not 100% sure about these values, but they're approximated)

    I've also tried changing the matk_min and matk_max to int, but I'm not sure if I did it right..

    This is what I mean by "overflow" (the values just go negative)

    Spoiler

    lRRhP1j.png

    Thank you!

  5. On 8/15/2019 at 5:39 AM, Bringer said:
    
    diff --git a/conf/battle/battle.conf b/conf/battle/battle.conf
    index 593d4e92f4..30251a4834 100644
    --- a/conf/battle/battle.conf
    +++ b/conf/battle/battle.conf
    @@ -158,3 +158,9 @@ warg_can_falcon: no
     // Should the target be able of dodging damage by snapping away to the edge of the screen?
     // Official behavior is "no"
     snap_dodge: no
    +
    +// ****************************************
    +// Reserved Costume ID's
    +// ****************************************
    +// Reserved Char ID for costume converted items.
    +reserved_costume_id: 999998
    \ No newline at end of file
    diff --git a/doc/script_commands.txt b/doc/script_commands.txt
    index 70113c4145..d769b4364d 100644
    --- a/doc/script_commands.txt
    +++ b/doc/script_commands.txt
    @@ -9633,6 +9633,25 @@ solution rather than sending the map and the monster_id.
     
     ---------------------------------------
     
    +*costume <equipment position>;
    +
    +Converts equipment in <equipment position> to costume version that has no stats.
    +
    +Applicable positions are:
    + EQI_HEAD_TOP - Top Headgear
    + EQI_HEAD_MID - Middle Headgear
    + EQI_HEAD_LOW - Lower Headgear
    + EQI_GARMENT - Garment
    + 
    +---------------------------------------
    +
    +*getcostumeitem <item id>;
    +*getcostumeitem <"item name">;
    +
    +Spawn a costume version of an <item id> or <"item name"> in attached player's inventory.
    +
    +---------------------------------------
    +
     *hateffect(<Hat Effect ID>,<State>);
     
     This will set a Hat Effect onto the player. The state field allows you to
    diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp
    index 43d6ad4d7d..e2897a48b5 100644
    --- a/src/map/atcommand.cpp
    +++ b/src/map/atcommand.cpp
    @@ -1218,7 +1218,7 @@ ACMD_FUNC(heal)
     ACMD_FUNC(item)
     {
     	char item_name[100];
    -	int number = 0, bound = BOUND_NONE;
    +	int number = 0, bound = BOUND_NONE, costume = 0;
     	char flag = 0;
     	struct item item_tmp;
     	struct item_data *item_data[10];
    @@ -1267,6 +1267,27 @@ ACMD_FUNC(item)
     
     	for(j--; j>=0; j--){ //produce items in list
     		unsigned short item_id = item_data[j]->nameid;
    +		if (!strcmpi(command + 1, "costumeitem"))
    +		{
    +			if (!battle_config.reserved_costume_id)
    +			{
    +				clif_displaymessage(fd, "Costume convertion is disable. Set a value for reserved_cosutme_id on your battle.conf file.");
    +				return -1;
    +			}
    +			if (!(item_data[j]->equip&EQP_HEAD_LOW) &&
    +				!(item_data[j]->equip&EQP_HEAD_MID) &&
    +				!(item_data[j]->equip&EQP_HEAD_TOP) &&
    +				!(item_data[j]->equip&EQP_COSTUME_HEAD_LOW) &&
    +				!(item_data[j]->equip&EQP_COSTUME_HEAD_MID) &&
    +				!(item_data[j]->equip&EQP_COSTUME_HEAD_TOP) &&
    +				!(item_data[j]->equip&EQP_GARMENT) &&
    +				!(item_data[j]->equip&EQP_COSTUME_GARMENT))
    +			{
    +				clif_displaymessage(fd, "You cannot costume this item. Costume only work for headgears.");
    +				return -1;
    +			}
    +			costume = 1;
    +		}
     		//Check if it's stackable.
     		if (!itemdb_isstackable2(item_data[j]))
     			get_count = 1;
    @@ -1277,6 +1298,11 @@ ACMD_FUNC(item)
     				memset(&item_tmp, 0, sizeof(item_tmp));
     				item_tmp.nameid = item_id;
     				item_tmp.identify = 1;
    +				if (costume == 1) { // Costume item
    +					item_tmp.card[0] = CARD0_CREATE;
    +					item_tmp.card[2] = GetWord(battle_config.reserved_costume_id, 0);
    +					item_tmp.card[3] = GetWord(battle_config.reserved_costume_id, 1);
    +				}
     				item_tmp.bound = bound;
     				if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND)))
     					clif_additem(sd, 0, 0, flag);
    @@ -10282,6 +10308,7 @@ void atcommand_basecommands(void) {
     		ACMD_DEF(clonestat),
     		ACMD_DEF(bodystyle),
     		ACMD_DEF(adopt),
    +		ACMD_DEF2("costumeitem", item),
     		ACMD_DEF(agitstart3),
     		ACMD_DEF(agitend3),
     	};
    diff --git a/src/map/battle.cpp b/src/map/battle.cpp
    index 839cfb5620..d28c5f0182 100644
    --- a/src/map/battle.cpp
    +++ b/src/map/battle.cpp
    @@ -8482,6 +8482,7 @@ static const struct _battle_data {
     	{ "exp_cost_inspiration",               &battle_config.exp_cost_inspiration,            1,      0,      100,            },
     	{ "mvp_exp_reward_message",             &battle_config.mvp_exp_reward_message,          0,      0,      1,              },
     	{ "can_damage_skill",                   &battle_config.can_damage_skill,                1,      0,      BL_ALL,         },
    +	{ "reserved_costume_id",				&battle_config.reserved_costume_id,				999998,	0,		INT_MAX,		},
     	{ "atcommand_levelup_events",			&battle_config.atcommand_levelup_events,		0,		0,		1,				},
     	{ "block_account_in_same_party",		&battle_config.block_account_in_same_party,		1,		0,		1,				},
     	{ "tarotcard_equal_chance",             &battle_config.tarotcard_equal_chance,          0,      0,      1,              },
    diff --git a/src/map/battle.hpp b/src/map/battle.hpp
    index ad13f69d53..b8f36aaf00 100644
    --- a/src/map/battle.hpp
    +++ b/src/map/battle.hpp
    @@ -618,6 +618,7 @@ struct Battle_Config
     	int exp_cost_inspiration;
     	int mvp_exp_reward_message;
     	int can_damage_skill; //Which BL types can damage traps
    +	int reserved_costume_id;
     	int atcommand_levelup_events;
     	int block_account_in_same_party;
     	int tarotcard_equal_chance; //Official or equal chance for each card
    diff --git a/src/map/map.cpp b/src/map/map.cpp
    index 8b70459939..3b06cd032c 100644
    --- a/src/map/map.cpp
    +++ b/src/map/map.cpp
    @@ -1865,6 +1865,12 @@ void map_reqnickdb(struct map_session_data * sd, int charid)
     
     	nullpo_retv(sd);
     
    +	if (battle_config.reserved_costume_id && battle_config.reserved_costume_id == charid)
    +	{
    +		clif_solved_charname(sd->fd, charid, "Costume");
    +		return;
    +	}
    +
     	tsd = map_charid2sd(charid);
     	if( tsd )
     	{
    diff --git a/src/map/pc.cpp b/src/map/pc.cpp
    index c0126b1597..015381e857 100755
    --- a/src/map/pc.cpp
    +++ b/src/map/pc.cpp
    @@ -746,6 +746,7 @@ int pc_equippoint_sub(struct map_session_data *sd,struct item_data* id){
     				return EQP_SHADOW_ARMS;
     		}
     	}
    +
     	return ep;
     }
     
    @@ -757,7 +758,18 @@ int pc_equippoint_sub(struct map_session_data *sd,struct item_data* id){
     int pc_equippoint(struct map_session_data *sd,int n){
     	nullpo_ret(sd);
     
    -	return pc_equippoint_sub(sd,sd->inventory_data[n]);
    +	int ep = pc_equippoint_sub(sd, sd->inventory_data[n]);
    +
    +	if (battle_config.reserved_costume_id &&
    +		sd->inventory.u.items_inventory[n].card[0] == CARD0_CREATE &&
    +		MakeDWord(sd->inventory.u.items_inventory[n].card[2], sd->inventory.u.items_inventory[n].card[3]) == battle_config.reserved_costume_id)
    +	{ // Costume Item - Converted
    +		if (ep&EQP_HEAD_TOP) { ep &= ~EQP_HEAD_TOP; ep |= EQP_COSTUME_HEAD_TOP; }
    +		if (ep&EQP_HEAD_LOW) { ep &= ~EQP_HEAD_LOW; ep |= EQP_COSTUME_HEAD_LOW; }
    +		if (ep&EQP_HEAD_MID) { ep &= ~EQP_HEAD_MID; ep |= EQP_COSTUME_HEAD_MID; }
    +		if (ep&EQP_GARMENT) { ep &= ~EQP_GARMENT; ep |= EQP_COSTUME_GARMENT; }
    +	}
    +	return ep;
     }
     
     /**
    diff --git a/src/map/script.cpp b/src/map/script.cpp
    index 0b2386c32d..70127734b0 100644
    --- a/src/map/script.cpp
    +++ b/src/map/script.cpp
    @@ -22601,6 +22601,114 @@ BUILDIN_FUNC(getexp2) {
     	return SCRIPT_CMD_SUCCESS;
     }
     
    +/*==========================================
    +* Costume Items
    +*------------------------------------------*/
    +BUILDIN_FUNC(costume)
    +{
    +	int i = -1, num, ep;
    +	TBL_PC *sd;
    +
    +	num = script_getnum(st, 2); // Equip Slot
    +
    +	if (!script_rid2sd(sd))
    +		return SCRIPT_CMD_FAILURE;
    +
    +	if (equip_index_check(num))
    +		i = pc_checkequip(sd, equip_bitmask[num]);
    +	if (i < 0)
    +		return SCRIPT_CMD_FAILURE;
    +
    +	ep = sd->inventory.u.items_inventory[i].equip;
    +	if (!(ep&EQP_HEAD_LOW) && !(ep&EQP_HEAD_MID) && !(ep&EQP_HEAD_TOP) && !(ep&EQP_GARMENT)) {
    +		ShowError("buildin_costume: Attempted to convert non-cosmetic item to costume.");
    +		return SCRIPT_CMD_FAILURE;
    +	}
    +	log_pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->inventory.u.items_inventory[i]);
    +	pc_unequipitem(sd, i, 2);
    +	clif_delitem(sd, i, 1, 3);
    +	// --------------------------------------------------------------------
    +	sd->inventory.u.items_inventory[i].refine = 0;
    +	sd->inventory.u.items_inventory[i].attribute = 0;
    +	sd->inventory.u.items_inventory[i].card[0] = CARD0_CREATE;
    +	sd->inventory.u.items_inventory[i].card[1] = 0;
    +	sd->inventory.u.items_inventory[i].card[2] = GetWord(battle_config.reserved_costume_id, 0);
    +	sd->inventory.u.items_inventory[i].card[3] = GetWord(battle_config.reserved_costume_id, 1);
    +
    +	if (ep&EQP_HEAD_TOP) { ep &= ~EQP_HEAD_TOP; ep |= EQP_COSTUME_HEAD_TOP; }
    +	if (ep&EQP_HEAD_LOW) { ep &= ~EQP_HEAD_LOW; ep |= EQP_COSTUME_HEAD_LOW; }
    +	if (ep&EQP_HEAD_MID) { ep &= ~EQP_HEAD_MID; ep |= EQP_COSTUME_HEAD_MID; }
    +	if (ep&EQP_GARMENT) { ep &= EQP_GARMENT; ep |= EQP_COSTUME_GARMENT; }
    +	// --------------------------------------------------------------------
    +	log_pick_pc(sd, LOG_TYPE_SCRIPT, 1, &sd->inventory.u.items_inventory[i]);
    +
    +	clif_additem(sd, i, 1, 0);
    +	pc_equipitem(sd, i, ep);
    +	clif_misceffect(&sd->bl, 3);
    +
    +	return SCRIPT_CMD_SUCCESS;
    +}
    +
    +/*===============================
    + * getcostumeitem <item id>;
    + * getcostumeitem <"item name">;
    + *===============================*/
    +BUILDIN_FUNC(getcostumeitem)
    +{
    +	unsigned short nameid;
    +	struct item item_tmp;
    +	TBL_PC *sd;
    +	struct script_data *data;
    +
    +	if (!script_rid2sd(sd))
    +	{	// No player attached.
    +		script_pushint(st, 0);
    +		return SCRIPT_CMD_SUCCESS;
    +	}
    +
    +	data = script_getdata(st, 2);
    +	get_val(st, data);
    +	if (data_isstring(data)) {
    +		int ep;
    +		const char *name = conv_str(st, data);
    +		struct item_data *item_data = itemdb_searchname(name);
    +		if (item_data == NULL)
    +		{	//Failed
    +			script_pushint(st, 0);
    +			return SCRIPT_CMD_SUCCESS;
    +		}
    +		ep = item_data->equip;
    +		if (!(ep&EQP_HEAD_LOW) && !(ep&EQP_HEAD_MID) && !(ep&EQP_HEAD_TOP) && !(ep&EQP_GARMENT)){
    +			ShowError("buildin_getcostumeitem: Attempted to convert non-cosmetic item to costume.");
    +			return SCRIPT_CMD_FAILURE;
    +		}
    +		nameid = item_data->nameid;
    +	}
    +	else
    +		nameid = conv_num(st, data);
    +
    +	if (!itemdb_exists(nameid))
    +	{	// Item does not exist.
    +		script_pushint(st, 0);
    +		return SCRIPT_CMD_SUCCESS;
    +	}
    +
    +	memset(&item_tmp, 0, sizeof(item_tmp));
    +	item_tmp.nameid = nameid;
    +	item_tmp.amount = 1;
    +	item_tmp.identify = 1;
    +	item_tmp.card[0] = CARD0_CREATE;
    +	item_tmp.card[2] = GetWord(battle_config.reserved_costume_id, 0);
    +	item_tmp.card[3] = GetWord(battle_config.reserved_costume_id, 1);
    +	if (pc_additem(sd, &item_tmp, 1, LOG_TYPE_SCRIPT)) {
    +		script_pushint(st, 0);
    +		return SCRIPT_CMD_SUCCESS;	//Failed to add item, we will not drop if they don't fit
    +	}
    +
    +	script_pushint(st, 1);
    +	return SCRIPT_CMD_SUCCESS;
    +}
    +
     /**
     * Force stat recalculation of sd
     * recalculatestat;
    @@ -24343,6 +24451,8 @@ struct script_function buildin_func[] = {
     	BUILDIN_DEF(getguildalliance,"ii"),
     	BUILDIN_DEF(adopt,"vv"),
     	BUILDIN_DEF(getexp2,"ii?"),
    +	BUILDIN_DEF(costume, "i"),
    +	BUILDIN_DEF(getcostumeitem, "v"),
     	BUILDIN_DEF(recalculatestat,""),
     	BUILDIN_DEF(hateffect,"ii"),
     	BUILDIN_DEF(getrandomoptinfo, "i"),
    diff --git a/src/map/status.cpp b/src/map/status.cpp
    index af4c3afb00..a296f7b89e 100644
    --- a/src/map/status.cpp
    +++ b/src/map/status.cpp
    @@ -3492,6 +3492,8 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
     			continue;
     		if (!sd->inventory_data[index])
     			continue;
    +		if (sd->inventory.u.items_inventory[current_equip_item_index].card[0] == CARD0_CREATE && MakeDWord(sd->inventory.u.items_inventory[current_equip_item_index].card[2], sd->inventory.u.items_inventory[current_equip_item_index].card[3]) == battle_config.reserved_costume_id)
    +			continue;
     
     		base_status->def += sd->inventory_data[index]->def;
     

    try this

    Dude, this saved me! Is this code yours? I'd like to thank the owner if not. Thank you, again!

  6. Hi! I was using the 2014.10.22bRagexe together with a data from brAthena and was able to connect normally. After upgrading the client to 2018-06-21aRagexeRE I'm not able to connect anymore, I've updated the data to RoenglishRE together with its System folder and kRO dlls and stuff. The server version is the most recent from rAthena git. This is my client folder with everything inside, including my data and patched client

    Everything opens normally but after typing any password I just get the message "Disconnected from server" and there's nothing on the login-server logs, which got me thinking it could be somewhat related to the clientinfo.xml, so I've diffed (using NEMO) the option to select a custom clientinfo.xml and put the sclientinfo.xml. I'm not able to select Always Call SelectKoreaClientInfo() which checking the nemo wiki, I can see that my client won't support it. So I have nowhere to go now...

    I'm using this sclientinfo.xml

    <?xml version="1.0" encoding="euc-kr" ?>
    <clientinfo>
    	<desc>Ragnarok Client Information</desc>
    	<servicetype>korea</servicetype>
    	<servertype>primary</servertype>
    	<connection>
    		<display>Local</display>
          		<address>127.0.0.1</address>
          		<port>6900</port>
          		<version>55</version>
          		<langtype>1</langtype>
    		<registrationweb>www.ragnarok.com</registrationweb>
    		<loading>
    			<image>loading00.jpg</image>
    			<image>loading01.jpg</image>
    			<image>loading02.jpg</image>
    			<image>loading03.jpg</image>
    			<image>loading04.jpg</image>
    			<image>loading05.jpg</image>
    			<image>loading06.jpg</image>
    		</loading>
       	</connection>
    </clientinfo>

    I might be wrong but does the absence of a <aid> makes no difference unless I specify on NEMO to ignore GM clothes?

    PS: I can see the sclientinfo.xml file is being read by the client because if I change the <servertype> to Sakray or the <langtype> to anything but 0/1 the client won't open with a bunch of errors.

    Thanks!

×
×
  • Create New...