Jump to content

keitenai

Members
  • Content Count

    15
  • Joined

  • Last visited

  • Days Won

    1

Posts posted by keitenai


  1. I saw lots of players asking to have @autoloot id with more than one item to autoloot. There are many src code for this but none was available for 3ceam compatible.

     

    So here's @autloot item with 20slots made compatible for 3ceam

     

    V1 : 3CEAM_@ALOOTID_20SLOTS.patch

     

    Index: conf/atcommand_athena.conf
    ===================================================================
    --- conf/atcommand_athena.conf	(revision 6)
    +++ conf/atcommand_athena.conf	(working copy)
    @@ -157,10 +157,8 @@
     
     // Enables/disables autolooting from killed mobs.
     autoloot: 10,10
    +aloot: 10,10
     
    -// Enables/disables autolooting an item.
    -alootid: 10,10
    -
     // Allows you continue vending offline.
     autotrade: 10,10
     at: 10,10
    Index: src/map/atcommand.c
    ===================================================================
    --- src/map/atcommand.c	(revision 6)
    +++ src/map/atcommand.c	(working copy)
    @@ -6517,70 +6517,134 @@
     }
     
     /*==========================================
    - * @autoloot by Upa-Kun
    - * Turns on/off AutoLoot for a specific player
    + * @autoloot by Zephyrus
      *------------------------------------------*/
     ACMD_FUNC(autoloot)
     {
    -	int rate;
    -	double drate;
    -	nullpo_retr(-1, sd);
    -	// autoloot command without value
    -	if(!message || !*message)
    +	int p = 0;
    +	char subcmd[100], data[100];
    +	memset(subcmd, '\0', sizeof(subcmd));
    +	memset(data, '\0', sizeof(data));
    +
    +	if( !message || !*message )
    +	{ // Normal Autoloot usage
    +		if( sd->aloot.rate )
    +		{
    +			sd->aloot.rate = 0;
    +			clif_displaymessage(fd, "Autoloot per percentage of drop turned off.");
    +		}
    +		else
    +		{
    +			sd->aloot.rate = 10000;
    +			clif_displaymessage(fd, "Autoloot activated to receive all drops.");
    +		}
    +
    +		clif_displaymessage(fd, "To learn how to use the autoloot command use @autoloot help");
    +		return 0;
    +	}
    +
    +	if( (p = sscanf(message, "%99s %99[^\n]", subcmd, data)) < 1 )
     	{
    -		if (sd->state.autoloot)
    -			rate = 0;
    +		clif_displaymessage(fd, "To learn how to use the autoloot command use @aloot help");
    +		return -1;
    +	}
    +
    +	if( !strcmp(subcmd, "rate") )
    +	{ // Set autoloot rate value
    +		int rate;
    +		if( p < 2 )
    +		{
    +			clif_displaymessage(fd, "It's required to enter a percentage value of drop. Ex. @aloot rate 0.03");
    +			return -1;
    +		}
    +
    +		rate = (int)(atof(data) * 100);
    +		sd->aloot.rate = cap_value(rate, 0, 10000);
    +
    +		if( sd->aloot.rate )
    +		{
    +			snprintf(atcmd_output, sizeof(atcmd_output), "Autoloot activated for items of drop %0.02f%% or lower.",((double)sd->aloot.rate)/100.);
    +			clif_displaymessage(fd, atcmd_output);
    +		}
     		else
    -			rate = 10000;
    -	} else {
    -		drate = atof(message);
    -		rate = (int)(drate*100);
    +			clif_displaymessage(fd, "This item is already on your autoloot list.");
     	}
    -	if (rate < 0) rate = 0;
    -	if (rate > 10000) rate = 10000;
    +	else if( !strcmp(subcmd, "clear") )
    +	{
    +		memset(&sd->aloot, 0, sizeof(sd->aloot));
    +		clif_displaymessage(fd, "Percentage and items autoloot Information deleted.");
    +	}
    +	else if( !strcmp(subcmd, "info") )
    +	{
    +		int i, c = 0;
    +		struct item_data *it = NULL;
     
    -	sd->state.autoloot = rate;
    -	if (sd->state.autoloot) {
    -		snprintf(atcmd_output, sizeof atcmd_output, "Autolooting items with drop rates of %0.02f%% and below.",((double)sd->state.autoloot)/100.);
    +		snprintf(atcmd_output, sizeof(atcmd_output), "Autoloot activated for items of drop %0.02f%% or lower.",((double)sd->aloot.rate)/100.);
     		clif_displaymessage(fd, atcmd_output);
    -	}else
    -		clif_displaymessage(fd, "Autoloot is now off.");
    +		for( i = 0; i < MAX_AUTOLOOTID; i++ )
    +		{
    +			if( sd->aloot.nameid[i] == 0 || (it = itemdb_exists(sd->aloot.nameid[i])) == NULL )
    +				continue;
     
    -	return 0;
    -}
    +			snprintf(atcmd_output, sizeof(atcmd_output), "+ Autolooting of item : %s (%d).", it->jname, it->nameid);
    +			clif_displaymessage(fd, atcmd_output);
    +			c++;
    +		}
     
    -/*==========================================
    - * @alootid
    - *------------------------------------------*/
    -ACMD_FUNC(autolootitem)
    -{
    -	struct item_data *item_data = NULL;
    +		snprintf(atcmd_output, sizeof(atcmd_output), "You're using %d of %d spots for autoloot per item.", c, MAX_AUTOLOOTID);
    +		clif_displaymessage(fd, atcmd_output);
    +	}
    +	else if( !strcmp(subcmd, "item") )
    +	{
    +		int i, j;
    +		struct item_data *it = NULL;
     
    -	if (!message || !*message) {
    -		if (sd->state.autolootid) {
    -			sd->state.autolootid = 0;
    -			clif_displaymessage(fd, "Autolootitem has been turned OFF.");
    -		} else
    -			clif_displaymessage(fd, "Please, enter item name or it's ID (usage: @alootid <item_name_or_ID>).");
    +		if( p < 2 )
    +		{
    +			clif_displaymessage(fd, "Please enter the name or id of the item for autoloot. Ex. @aloot item Elunium");
    +			return -1;
    +		}
     
    -		return -1;
    -	}
    +		ARR_FIND(0, MAX_AUTOLOOTID, i, sd->aloot.nameid[i] == 0);
    +		if( i == MAX_AUTOLOOTID )
    +		{
    +			clif_displaymessage(fd, msg_txt(886));
    +			return -1;
    +		}
     
    -	if ((item_data = itemdb_exists(atoi(message))) == NULL)
    -		item_data = itemdb_searchname(message);
    +		if( (it = itemdb_exists(atoi(data))) == NULL )
    +			it = itemdb_searchname(data);
     
    -	if (!item_data) {
    -		// No items founds in the DB with Id or Name
    -		clif_displaymessage(fd, "Item not found.");
    +		if( !it )
    +		{
    +			clif_displaymessage(fd, "Please enter the name or id of the item for autoloot. Ex. @aloot item Elunium");
    +			return -1;
    +		}
    +
    +		ARR_FIND(0, MAX_AUTOLOOTID, j, sd->aloot.nameid[i] == it->nameid);
    +		if( j < MAX_AUTOLOOTID )
    +		{
    +			clif_displaymessage(fd, "This item is already on your autoloot list.");
    +			return -1;
    +		}
    +
    +		sd->aloot.nameid[i] = it->nameid;
    +		snprintf(atcmd_output, sizeof(atcmd_output), "+ Autolooting of item : %s (%d).", it->jname, it->nameid);
    +		clif_displaymessage(fd, atcmd_output);
    +	}
    +	else if( !strcmp(subcmd, "help") )
    +	{
    +		clif_displaymessage(fd, "@aloot rate <amount> : For autolooting items with percentage of drop <amount> and lower.");
    +		clif_displaymessage(fd, "@aloot item <id/name> : For autolooting the item. You can change it up to 20 times.");
    +		clif_displaymessage(fd, "@aloot info : To see autoloot's configuration list.");
    +		clif_displaymessage(fd, "@aloot clear : To erase autoloot's configuration & deactivate it.");
    +	}
    +	else
    +	{
    +		clif_displaymessage(fd, "To learn how to use the autoloot command use @aloot help");
     		return -1;
     	}
     
    -	sd->state.autolootid = item_data->nameid; // Autoloot Activated
    -
    -	sprintf(atcmd_output, "Autolooting item: '%s'/'%s' (%d)",
    -		item_data->name, item_data->jname, item_data->nameid);
    -	clif_displaymessage(fd, atcmd_output);
    -
     	return 0;
     }
     
    @@ -9406,7 +9470,7 @@
     	{ "disguiseall",       99,99,     atcommand_disguiseall },
     	{ "changelook",        60,60,     atcommand_changelook },
     	{ "autoloot",          10,10,     atcommand_autoloot },
    -	{ "alootid",           10,10,     atcommand_autolootitem },
    +	{ "aloot",             10,10,     atcommand_autoloot },
     	{ "mobinfo",            1,1,      atcommand_mobinfo },
     	{ "monsterinfo",        1,1,      atcommand_mobinfo },
     	{ "mi",                 1,1,      atcommand_mobinfo },
    Index: src/map/mob.c
    ===================================================================
    --- src/map/mob.c	(revision 7)
    +++ src/map/mob.c	(working copy)
    @@ -1730,9 +1730,10 @@
      * rate is the drop-rate of the item, required for autoloot.
      * flag : Killed only by homunculus?
      *------------------------------------------*/
    -static void mob_item_drop(struct mob_data *md, struct item_drop_list *dlist, struct item_drop *ditem, int loot, int drop_rate, unsigned short flag)
    +static void mob_item_drop(struct mob_data *md, struct item_drop_list *dlist, struct item_drop *ditem, int loot, int drop_rate, bool flag)
     {
     	TBL_PC* sd;
    +	int i = MAX_AUTOLOOTID;
     
     	if(log_config.enable_logs&0x10)
     	{	//Logs items, dropped by mobs [Lupus]
    @@ -1745,19 +1746,30 @@
     	sd = map_charid2sd(dlist->first_charid);
     	if( sd == NULL ) sd = map_charid2sd(dlist->second_charid);
     	if( sd == NULL ) sd = map_charid2sd(dlist->third_charid);
    +	
    +	// Display Drop
    +	if( sd && sd->state.displaydrop && drop_rate <= sd->state.displaydrop )
    +	{
    +		char message[128];
    +		sprintf(message, "Monster dropped %d %s (drop rate: %0.02f%%)", ditem->item_data.amount, itemdb_exists(ditem->item_data.nameid)->jname, (float)drop_rate / 100.);
    +		clif_disp_onlyself(sd, message, strlen(message));
    +	}
     
    +	if( sd )
    +		ARR_FIND(0, MAX_AUTOLOOTID, i, sd->aloot.nameid[i] == ditem->item_data.nameid);
    +
     	if( sd
    -		&& (drop_rate <= sd->state.autoloot || ditem->item_data.nameid == sd->state.autolootid)
    -		&& (battle_config.idle_no_autoloot == 0 || DIFF_TICK(last_tick, sd->idletime) < battle_config.idle_no_autoloot)
    -		&& (battle_config.homunculus_autoloot?1:!flag)
    +		&& ( drop_rate <= sd->aloot.rate || i < MAX_AUTOLOOTID )
    +		&& ( battle_config.idle_no_autoloot == 0 || DIFF_TICK(last_tick, sd->idletime) < battle_config.idle_no_autoloot )
    +		&& ( battle_config.homunculus_autoloot?1:!flag )
     #ifdef AUTOLOOT_DISTANCE
     		&& sd->bl.m == md->bl.m
     		&& check_distance_blxy(&sd->bl, dlist->x, dlist->y, AUTOLOOT_DISTANCE)
     #endif
    -	) {	//Autoloot.
    -		if (party_share_loot(party_search(sd->status.party_id),
    -			sd, &ditem->item_data, sd->status.char_id) == 0
    -		) {
    +	)
    +	{ // Autoloot.
    +		if( party_share_loot(party_search(sd->status.party_id), sd, &ditem->item_data, sd->status.char_id) == 0 )
    +		{
     			ers_free(item_drop_ers, ditem);
     			return;
     		}
    Index: src/map/pc.c
    ===================================================================
    --- src/map/pc.c	(revision 6)
    +++ src/map/pc.c	(working copy)
    @@ -1240,7 +1240,7 @@
     		sd->autobonus3[i].active = INVALID_TIMER;
     
     	if (battle_config.item_auto_get)
    -		sd->state.autoloot = 10000;
    +		sd->aloot.rate = 10000;
     
     	if (battle_config.disp_experience)
     		sd->state.showexp = 1;
    Index: src/map/pc.h
    ===================================================================
    --- src/map/pc.h	(revision 6)
    +++ src/map/pc.h	(working copy)
    @@ -22,9 +22,11 @@
     #define MAX_PC_SKILL_REQUIRE 5
     #define MAX_PC_FEELHATE 3
     
    +#define MAX_AUTOLOOTID 20
    +
     #define MAX_RUNE 20
    -#define MAX_RAGE 15
    -#define MAX_SPELLBOOK 7
    +#define MAX_RAGE 15
    +#define MAX_SPELLBOOK 7
     
     struct weapon_data {
     	int atkmods[3];
    @@ -141,8 +143,7 @@
     		unsigned buyingstore : 1;
     		unsigned lesseffect : 1;
     		unsigned vending : 1;
    -		unsigned short autoloot;
    -		unsigned short autolootid; // [Zephyrus]
    +		unsigned short displaydrop;
     		unsigned noks : 3; // [Zeph Kill Steal Protection]
     		bool changemap;
     		short pmap; // Previous map on Map Change
    @@ -167,6 +168,12 @@
     		unsigned no_knockback : 1;
     		unsigned bonus_coma : 1;
     	} special_state;
    +
    +	struct {
    +		unsigned short rate;
    +		int nameid[MAX_AUTOLOOTID];
    +	} aloot;
    +
     	int login_id1, login_id2;
     	unsigned short class_;	//This is the internal job ID used by the map server to simplify comparisons/queries/etc. [Skotlex]
     	int gmlevel;
    
    

  2. Here's MVP tomb stone patch that i made compatible with 3ceam

     
     
     
    Index: conf/battle/monster.conf
    ===================================================================
    --- conf/battle/monster.conf	(revision 792)
    +++ conf/battle/monster.conf	(working copy)
    @@ -206,6 +206,11 @@
     // NOTE: This affects who gains the Castle when the Emperium is broken. 
     mob_npc_event_type: 1
     
    +// Wheter or not to spawn the mvp tomb. (Default: no)
    +// This is a renewal feature.
    +// See http://irowiki.org/wiki/MVP#Gravestone
    +mvp_tomb_enabled: yes
    +
     // Time in milliseconds to actitave protection against Kill Steal
     // Set to 0 to disable it.
     // If this is activated and a player is using @noks, damage from others players (KS) not in the party
    Index: src/map/battle.c
    ===================================================================
    --- src/map/battle.c	(revision 792)
    +++ src/map/battle.c	(working copy)
    @@ -5914,6 +5914,7 @@
     	{ "mob_luk_status_def",                 &battle_config.mob_luk_sc_def,                  300,    1,      INT_MAX,        },
     	{ "pc_max_status_def",                  &battle_config.pc_max_sc_def,                   100,    0,      INT_MAX,        },
     	{ "mob_max_status_def",                 &battle_config.mob_max_sc_def,                  100,    0,      INT_MAX,        },
    +	{ "mvp_tomb_enabled",					&battle_config.mvp_tomb_enabled,				1,      0,      1				},
     	{ "sg_miracle_skill_ratio",             &battle_config.sg_miracle_skill_ratio,          1,      0,      10000,          },
     	{ "sg_angel_skill_ratio",               &battle_config.sg_angel_skill_ratio,            10,     0,      10000,          },
     	{ "autospell_stacking",                 &battle_config.autospell_stacking,              0,      0,      1,              },
    Index: src/map/battle.h
    ===================================================================
    --- src/map/battle.h	(revision 792)
    +++ src/map/battle.h	(working copy)
    @@ -416,6 +416,7 @@
     
     	int mob_npc_event_type; //Determines on who the npc_event is executed. [Skotlex]
     	int mob_clear_delay; // [Valaris]
    +	int mvp_tomb_enabled;
     
     	int character_size; // if riders have size=2, and baby class riders size=1 [Lupus]
     	int mob_max_skilllvl; // Max possible skill level [Lupus]
    Index: src/map/map.h
    ===================================================================
    --- src/map/map.h	(revision 792)
    +++ src/map/map.h	(working copy)
    @@ -243,7 +243,7 @@
     //For common mapforeach calls. Since pets cannot be affected, they aren't included here yet.
     #define BL_CHAR (BL_PC|BL_MOB|BL_HOM|BL_MER|BL_ELEM)
     
    -enum npc_subtype { WARP, SHOP, SCRIPT, CASHSHOP };
    +enum npc_subtype { NPCTYPE_TOMB, WARP, SHOP, SCRIPT, CASHSHOP };
     
     enum {
     	RC_FORMLESS=0,	//NOTHING
    Index: src/map/mob.c
    ===================================================================
    --- src/map/mob.c	(revision 792)
    +++ src/map/mob.c	(working copy)
    @@ -102,6 +102,77 @@
     
     	return 0;
     }
    +
    +/*==========================================
    + *              MvP Tomb [GreenBox]
    + *------------------------------------------*/
    +void mvptomb_create(struct mob_data *md, char *killer, time_t time)
    +{
    +	struct npc_data *nd;
    +
    +	if ( md->tomb_nid )
    +		mvptomb_destroy(md);
    +
    +	CREATE(nd, struct npc_data, 1);
    +
    +	nd->bl.id = md->tomb_nid = npc_get_new_npc_id();
    +	
    +    nd->ud.dir = md->ud.dir;
    +	nd->bl.m = md->bl.m;
    +	nd->bl.x = md->bl.x;
    +	nd->bl.y = md->bl.y;
    +	nd->bl.type = BL_NPC;
    +	
    +	safestrncpy(nd->name, "Tomb", sizeof(nd->name));
    +
    +	nd->class_ = 565;
    +	nd->speed = 200;
    +	nd->subtype = NPCTYPE_TOMB;
    +
    +	nd->u.tomb.md = md;
    +	nd->u.tomb.kill_time = time;
    +	
    +	if (killer)
    +		safestrncpy(nd->u.tomb.killer_name, killer, NAME_LENGTH);
    +	else
    +		nd->u.tomb.killer_name[0] = '\0';
    +
    +	map_addnpc(nd->bl.m, nd);
    +	map_addblock(&nd->bl);
    +	status_set_viewdata(&nd->bl, nd->class_);
    +    status_change_init(&nd->bl);
    +    unit_dataset(&nd->bl);
    +    clif_spawn(&nd->bl);
    +
    +}
    +
    +void mvptomb_destroy(struct mob_data *md) {
    +	struct npc_data *nd;
    +
    +	if ( (nd = map_id2nd(md->tomb_nid)) ) {
    +		int m, i;
    +
    +		m = nd->bl.m;
    +		
    +		clif_clearunit_area(&nd->bl,CLR_OUTSIGHT);
    +		
    +		map_delblock(&nd->bl);
    +
    +		ARR_FIND( 0, map[m].npc_num, i, map[m].npc[i] == nd );
    +		if( !(i == map[m].npc_num) ) {
    +			map[m].npc_num--;
    +			map[m].npc[i] = map[m].npc[map[m].npc_num];
    +			map[m].npc[map[m].npc_num] = NULL;
    +		}
    +
    +		map_deliddb(&nd->bl);
    +
    +		aFree(nd);
    +	}
    +
    +	md->tomb_nid = 0;
    +}
    +
     static int mobdb_searchname_array_sub(struct mob_db* mob, const char *str)
     {
     	if (mob == mob_dummy)
    @@ -895,6 +966,10 @@
     		// Added for carts, falcons and pecos for cloned monsters. [Valaris]
     		md->sc.option = md->db->option;
     
    +	// MvP tomb [GreenBox]
    +	if ( md->tomb_nid )
    +		mvptomb_destroy(md);
    +
     	map_addblock(&md->bl);
     	clif_spawn(&md->bl);
     	skill_unit_move(&md->bl,tick,1);
    @@ -2491,6 +2566,10 @@
     	if(!md->spawn) //Tell status_damage to remove it from memory.
     		return 5; // Note: Actually, it's 4. Oh well...
     
    +	// MvP tomb [GreenBox]
    +	if (battle_config.mvp_tomb_enabled && md->spawn->boss)
    +		mvptomb_create(md, mvp_sd ? mvp_sd->status.name : NULL, time(NULL));
    +
     	if( !rebirth )
     		mob_setdelayspawn(md); //Set respawning.
     	return 3; //Remove from map.
    Index: src/map/mob.h
    ===================================================================
    --- src/map/mob.h	(revision 792)
    +++ src/map/mob.h	(working copy)
    @@ -9,6 +9,7 @@
     #include "map.h" // struct status_data, struct view_data, struct mob_skill
     #include "status.h" // struct status data, struct status_change
     #include "unit.h" // unit_stop_walking(), unit_stop_attack()
    +#include "npc.h"
     
     
     #define MAX_RANDOMMONSTER 4
    @@ -149,7 +150,7 @@
     	int level;
     	int target_id,attacked_id;
     	int areanpc_id; //Required in OnTouchNPC (to avoid multiple area touchs)
    -
    +	int tomb_nid;
     	unsigned int next_walktime,last_thinktime,last_linktime,last_pcneartime;
     	short move_fail_count;
     	short lootitem_count;
    @@ -277,6 +278,10 @@
     int mob_clone_spawn(struct map_session_data *sd, int m, int x, int y, const char *event, int master_id, int mode, int flag, unsigned int duration);
     int mob_clone_delete(struct mob_data *md);
     
    +// MvP Tomb System
    +void mvptomb_create(struct mob_data *md, char *killer, time_t time);
    +void mvptomb_destroy(struct mob_data *md);
    +
     void mob_reload(void);
     
     #endif /* _MOB_H_ */
    Index: src/map/npc.c
    ===================================================================
    --- src/map/npc.c	(revision 792)
    +++ src/map/npc.c	(working copy)
    @@ -1087,13 +1087,40 @@
     		clif_cashshop_show(sd,nd);
     		break;
     	case SCRIPT:
    -		run_script(nd->u.scr.script,0,sd->bl.id,nd->bl.id);
    -		break;
    +			run_script(nd->u.scr.script,0,sd->bl.id,nd->bl.id);
    +			break;
    +		case NPCTYPE_TOMB:
    +			npc_tomb(sd,nd);
     	}
     
     	return 0;
     }
     
    +// MvP tomb [GreenBox]
    +int npc_tomb(struct map_session_data* sd, struct npc_data* nd)
    +{
    +	char buffer[200];
    +	char time[10];
    +	
    +	strftime(time, sizeof(time), "%H:%M", localtime(&nd->u.tomb.kill_time));
    +	snprintf(buffer, sizeof(buffer), "[ ^0000EE%s^000000 ]", nd->u.tomb.md->db->name);
    +		clif_scriptmes(sd, nd->bl.id, buffer);
    +		clif_scriptmes(sd, nd->bl.id, "Has met its demise");
    +		snprintf(buffer, sizeof(buffer), "Time of death : ^EE0000%s^000000", time);
    +		clif_scriptmes(sd, nd->bl.id, buffer);
    +		clif_scriptmes(sd, nd->bl.id, "^FFFFFF_^000000");
    +		clif_scriptmes(sd, nd->bl.id, "Defeated by");
    +		snprintf(buffer, sizeof(buffer), "[ ^0000EE%s^000000 ]", nd->u.tomb.killer_name[0] ? nd->u.tomb.killer_name : "Unknown"); 
    +		clif_scriptmes(sd, nd->bl.id, buffer);
    +		clif_scriptclose(sd, nd->bl.id);
    +	return 0;
    +}
    +
     /*==========================================
      *
      *------------------------------------------*/
    Index: src/map/npc.h
    ===================================================================
    --- src/map/npc.h	(revision 792)
    +++ src/map/npc.h	(working copy)
    @@ -62,6 +62,11 @@
     			short x,y; // destination coords
     			unsigned short mapindex; // destination map
     		} warp;
    +		struct {
    +			struct mob_data *md;
    +			time_t kill_time;
    +			char killer_name[NAME_LENGTH];
    +		} tomb;
     	} u;
     };
     
    @@ -160,6 +165,7 @@
     int npc_duplicate4instance(struct npc_data *snd, int m);
     int npc_cashshop_buy(struct map_session_data *sd, int nameid, int amount, int points);
     int npc_cashshop_buylist(struct map_session_data* sd, int n, unsigned short* item_list, int points);
    +int npc_tomb(struct map_session_data* sd, struct npc_data* nd);
     
     extern struct npc_data* fake_nd;
     
    Index: src/map/unit.c
    ===================================================================
    --- src/map/unit.c	(revision 792)
    +++ src/map/unit.c	(working copy)
    @@ -2435,6 +2435,8 @@
     			}
     			if( mob_is_clone(md->class_) )
     				mob_clone_delete(md);
    +			if( md->tomb_nid )
    +				mvptomb_destroy(md);
     			break;
     		}
     		case BL_HOM:
    
    

     

    Enjoy! :D


  3. I really have no idea who created this script, and i'm not claiming this to be my own.

     

    All i did is to modify this script to be compatible with 3ceam.

    here's the thread of the request:

    http://herc.ws/board/topic/12194-rprice-giver-sql-script-for-3ceam-check-this-out/

     

     

    Here's my modified prize giver NPC script for anyone who needs it:

     

    Prize_Giver.txt

     

    //======= 3ceam Script =======================================
    //= Prize Giver NPC
    //===== Modified By: =========================================
    //= Keitenai
    //===== Current Version: =====================================
    //= 1.0
    //===== Compatible With: =====================================
    //= Athena Project
    //===== Description: =========================================
    //= Prize giver for single char, account and more.
    //===== Additional Comments: =================================
    //= 1.0 Modified Version for 3ceam compatibility
    //============================================================
    
    prontera,156,184,4	script	Item Giver	544,{
    	//cutin "v_sprakki04",2;
    	//Check if setups are loaded.
    	if(!.Setup)
    		{
    			callsub OnLoadSetup;
    		}
    
    	//Show GM Panel if player is GM.
    	if(getgmlevel() >= .GMin)
    		menu("Take a prize as a player",-,"Give prize",
    				OnManagement,"Reset Item Give",
    				OnDelete,"IP Limit per Item",
    				OnLimit);
    
    	//Read attached player gifts from SQL table.
    	if(select("Get Account Prize!:Get Character Prize!:Exit") == 1)
    		{
    			set .@query, query_sql("SELECT * FROM `" + .GiftTableName$ + "` WHERE account_id="+getcharid(3),
    				.@gift_id,
    				.@gift_account,
    				.@gift_char,
    				.@gift_item,
    				.@gift_amount,
    				.@gift_duration,
    				.@gift_time
    				); //Account gifts.
    		}
    		else if(@menu == 2)
    		{
    			set .@query, query_sql("SELECT * FROM `" + .GiftTableName$ + "` WHERE char_id="+getcharid(0),
    				.@gift_id,
    				.@gift_account,
    				.@gift_char,
    				.@gift_item,
    				.@gift_amount,
    				.@gift_duration,
    				.@gift_time
    				); //Char gifts.
    		}
    		else goto OnLeave;
    
    	//Check if player don't have gifts.
    	if(!.@query)
    		{
    			mes "[Reward Giver]";
    			mes "Sorry, you don't have any prize";
    
    			cutin "v_sprakki04",255;
    			close;
    		}
    
    	//Build menu from query arrays.
    		mes "[" + strnpcinfo(1) + "]";
    		mes "^009900You got the prize^000000";
    			for( set .@i, 0; .@i < .@query; set .@i, .@i + 1 )
    			{
    				mes "(" + .@gift_amount[.@i] + ") " + getitemname(.@gift_item[.@i]) + ".";
    				set .@menu$, .@menu$ + getitemname(.@gift_item[.@i]) + ":";
    			}
    			next;
    			set .@mid,select(.@menu$); //Show menu.
    			set .@mid,.@mid-1;
    
    	if (.@gift_time[.@mid] && .@gift_time[.@mid] < gettimetick(2))
    	{
    		mes "[Reward Giver]";
    		mes "Sorry, this prize's claim time is already over.";
    
    		cutin "v_sprakki04",255;
    		close;
    	}
    	//Item is now selected. Choose what you want to do with it.
    	mes "[" + strnpcinfo(1) + "]";
    	mes "what you want do with (" + .@gift_amount[.@mid] + ") " + getitemname(.@gift_item[.@mid]) + "?";
    	next;
    	set .@Select,select("^009900Get it^000000:^ff0000Delete it! ^000000:nothings");
    
    	//Receive gift selected.
    	if(.@Select == 1)
    	{
    		//Check weight.
    		if(checkweight( .@gift_item, .@gift_amount ) || .@gift_item[.@mid] == .ZenyID)
    		{
    			mes "[" + strnpcinfo(1) + "]";
    			mes "^009900Get : (" + .@gift_amount[.@mid] + ") " + getitemname(.@gift_item[.@mid]) + ".^000000";
    			if (.ip_limit)
    			{
    				// add ip_address to logs
    				.@ipexist = query_sql("SELECT item_id, ip_address, claim_count FROM " + .GiftTableNameIP$ + " WHERE last_ip = (SELECT last_ip FROM login WHERE account_id="+getcharid(3)+") AND item_id = "+.@gift_item[.@mid]+" LIMIT 1", .@item,.@ip,.@claim_count);
    				if (.@claim_count[0] >= .ip_limit)
    				{
    					next;
    					mes "Sorry you have reached the maximum redeem limit for this IP address";
    					cutin "v_sprakki04",255;
    					close;
    				}
    				if (!.@claim_count[0])
    				{
    					query_sql("INSERT INTO " + .GiftTableNameIP$ + " (give_id,item_id,last_ip,claim_count) VALUES("+.@gift_id+","+.@gift_item+",'(SELECT last_ip FROM login WHERE account_id="+getcharid(3)+")',1)");		
    				}
    				else
    				{
    					query_sql("UPDATE " + .GiftTableNameIP$ + " SET claim_count = "+(.@claim_count[0]+1)+" WHERE item_id = "+.@gift_item[.@mid]+" AND last_ip = (SELECT last_ip FROM login WHERE account_id="+getcharid(3)+")");
    				}
    			}
    			if (.@gift_item[.@mid] == .ZenyID) { // detects zeny ID and give zeny.
    				if (Zeny+.@gift_amount[.@mid] > .MaxZeny)
    				{
    					mes "Please make sure that you have enough space to handle all these zennies and come back later.";
    					cutin "v_sprakki04",255;
    					close;
    				}
    				set Zeny,Zeny+.@gift_amount[.@mid];
    			}
    			else
    			{
    				if (!.@gift_duration)
    				{
    					getitem .@gift_item[.@mid], .@gift_amount[.@mid]; //Give item to player.
    				}
    				else
    				{
    					rentitem .@gift_item[.@mid], .@gift_duration * 60; 
    				}
    			}
    			query_sql( "DELETE FROM `" + .GiftTableName$ + "` WHERE id = " + .@gift_id[.@mid] ); //Remove item from table.
    			cutin "v_sprakki04",255;
    			close;
    		}
    		else
    		{
    			//Overweight
    			mes "^ff0000Sorry ^000000 You can't take it " + getitemname(.@gift_item[.@mid]);
    			mes "Could lose some wight?";
    			cutin "v_sprakki04",255;
    			close;
    		}
    	}
    	//Remove gift selected.
    	else if(.@Select == 2) {
    		mes "[" + strnpcinfo(1) + "]";
    		mes "Are you sure you want dellet it?";
    		mes "Gift: ("+.@gift_amount[.@mid]+") "+getitemname(.@gift_item[.@mid])+".";
    		next;
    		if(select("Yes:No") == 1) {
    			mes "[" + strnpcinfo(1) + "]";
    			mes "^ff0000Dellet: ("+.@gift_amount[.@mid]+") "+getitemname(.@gift_item[.@mid])+".^000000";
    			query_sql("DELETE FROM `" + .GiftTableName$ + "` WHERE id = " + .@gift_id[.@mid]); //Remove item from table.
    			cutin "v_sprakki04",255;
    			close;
    		} else {
    			mes "[" + strnpcinfo(1) + "]";
    			mes "we will save it";
    			cutin "v_sprakki04",255;
    			close;
    		}
    	}
    	//Nothing selected.
    	else
    	{
    		goto OnLeave;
    	}
    
    //GM Panel below:
    OnManagement:
    	if(getgmlevel() < .GMin) goto OnLeave;
    	mes "[" + strnpcinfo(1) + "]";
    	mes "Welvome " + strcharinfo(0) + "!";
    	mes "How I can help you?";
    	next;
    
    	if(select("Make Gift:Nothing") != 1) goto OnLeave;
    
    		//Make new gift.
    		mes "[" + strnpcinfo(1) + "]";
    		mes "Please input the item id.";
    		mes "Default: 501";
    	next;
    		mes "What do you want to give?";
    		set .@zenygive,0;
    			if(select("Item:Zeny") == 1)
    				{
    					input .@new_item, 501, 30000;
    				}
    	next;
    	mes "Do you want to add a claim timer?";
    	if(select("No:Yes")==2)
    	{
    		next;
    		mes "How many minutes do you want this reward to be claimable?";
    		input(.@c);
    		.@claimtime = gettimetick(2)+(.@c*60);
    	}
    	if(select("Continue:Cancel") != 1) goto OnLeave;
    		mes "[" + strnpcinfo(1) + "]";
    		mes "How many items/zeny?";
    		mes "Default: 1";
    	next;
    	//item quantity range of 1 to 1,000.
    	if(.@zenygive)
    	{
    		input .@new_value, 1, .MaxZeny;
    	}
    	else
    	{
    		input .@new_value, 1, 1000;
    	}
    	
    	if(select("Continue:Cancel") != 1) goto OnLeave;
    		mes "[" + strnpcinfo(1) + "]";
    		mes "Please select input type:";
    		mes "1. Single Account";
    		mes "2. Single Character";
    		mes "3. All ^009900Online^000000 Accounts.";
    		mes "4. All Accounts.";
    		mes "5. All ^009900Online^000000 Players/Characters.";
    		mes "6. All Players/Characters.";
    		mes "7. ^ff0000Cancel.^000000";
    	next;
    	switch(select("Single Account:Single Character:^009900Online^000000 Accounts:All Accounts:^009900Online^000000 Characters:All Characters:Cancel"))
    	{
    		//Account gift
    		case 1:
    			mes "[" + strnpcinfo(1) + "]";
    			mes "Please select input type:";
    			mes "By AID or Name?";
    			next;
    			if(select("Account ID:Character Name") == 1)
    			{
    				mes "[" + strnpcinfo(1) + "]";
    				mes "Write account id:";
    				next;
    				input .@new_account, 2000000, 10000000; //Account id range from 2m to 10m.
    				set .@query, query_sql("SELECT account_id FROM `" + .CharTableName$ + "` WHERE account_id = " + .@new_account, .@new_account);
    				if(!.@query) goto OnNotExist;
    				if(select("Continue:Cancel") != 1) goto OnLeave;
    				mes "[" + strnpcinfo(1) + "]";
    				mes "^009900Gift is ready to go!^000000";
    				mes "AID: ^ff0000" + .@new_account + "^000000";
    				mes "------------------";
    				mes "Item: ^ff0000" + getitemname(.@new_item) + "^000000";
    				mes "Quantity: ^ff0000" + .@new_value + "^000000";
    				mes "Duration: " + .@duration + " Minutes";
    				mes "Claim Time: " + .@c + " Minutes";
    				next;
    				if(select("Send Gift:Cancel") != 1) goto OnLeave;
    				mes "[" + strnpcinfo(1) + "]";
    				mes "Gift sending success!";
    				//Create gift. <auto_id>, <account_id> <char_id> <item> <value>
    				query_sql("INSERT INTO `" + .GiftTableName$ + "` (account_id, item, value, duration, timestamp) VALUES(" + .@new_account + ", " + .@new_item + ", " + .@new_value + ", " + .@duration + ", " + .@claimtime + ")");
    			}
    			else
    			{
    				mes "[" + strnpcinfo(1) + "]";
    				mes "Write player name:";
    				next;
    				input .@new_name$;
    				set .@query, query_sql("SELECT account_id FROM `" + .CharTableName$ + "` WHERE name = '" + .@new_name$ + "'", .@new_account);
    				if(!.@query) goto OnNotExist;
    				if(select("Continue:Cancel") != 1) goto OnLeave;
    				mes "[" + strnpcinfo(1) + "]";
    				mes "^009900Gift is ready to go!^000000";
    				mes "AID: ^ff0000" + .@new_account + "^000000";
    				mes "Name: ^ff0000"+ .@new_name$ + "^000000";
    				mes "------------------";
    				mes "Item: ^ff0000" + getitemname(.@new_item) + "^000000";
    				mes "Quantity: ^ff0000" + .@new_value + "^000000";
    				mes "Duration: " + .@duration + " Minutes";
    				mes "Claim Time: " + .@c + " Minutes";
    				next;
    				if(select("Send Gift:Cancel") != 1) goto OnLeave;
    				//Check if player is logged in.
    				if(isloggedin(.@new_account)) {
    					mes "[" + strnpcinfo(1) + "]";
    					mes "Gift sending success!";
    					query_sql("INSERT INTO `" + .GiftTableName$ + "` (account_id, item, value, duration, timestamp) VALUES(" + .@new_account + ", " + .@new_item + ", " + .@new_value + ", " + .@duration + ", " + .@claimtime + ")");
    				} else {
    					//Account was not online.
    					mes "[" + strnpcinfo(1) + "]";
    					mes "Gift sending success!";
    					query_sql("INSERT INTO `" + .GiftTableName$ + "` (account_id, item, value, duration, timestamp) VALUES(" + .@new_account + ", " + .@new_item + ", " + .@new_value + ", " + .@duration + ", " + .@claimtime + ")"); // duplicate to other menus - continue here on giver side
    				}
    			}
    			break;
    
    		//Character gift.
    		case 2:
    			mes "[" + strnpcinfo(1) + "]";
    			mes "Please select input type:";
    			mes "By CID or Name?";
    			next;
    			if(select("Character ID:Character Name") == 1)
    			{
    				mes "[" + strnpcinfo(1) + "]";
    				mes "Write character id:";
    				next;
    				input .@new_char,150000, 10000000; //Char id range from 150k to 10m.
    				set .@query, query_sql("SELECT account_id, name FROM `" + .CharTableName$ + "` WHERE char_id = " + .@new_char, .@new_accountid, .@new_name$);
    				if(!.@query) goto OnNotExist;
    				if(select("Continue:Cancel") != 1) goto OnLeave;
    					mes "[" + strnpcinfo(1) + "]";
    					mes "^009900Gift is ready to go!^000000";
    					mes "CID: ^ff0000" + .@new_char + "^000000";
    					mes "Name: ^ff0000" + .@new_name$ + "^000000";
    					mes "------------------";
    					mes "Item: ^ff0000" + getitemname(.@new_item) + "^000000";
    					mes "Quantity: ^ff0000" + .@new_value + "^000000";
    					mes "Duration: " + .@duration + " Minutes";
    					mes "Claim Time: " + .@c + " Minutes";
    				next;
    				if(select("Send Gift:Cancel") != 1) goto OnLeave;
    				//Check if player is logged in.
    				if(isloggedin(.@new_accountid)) {
    					mes "[" + strnpcinfo(1) + "]";
    					mes "Gift sending success!";
    
    					//Create gift. <auto_id>, <account_id> <char_id> <item> <value>
    					query_sql("INSERT INTO `" + .GiftTableName$ + "` (char_id, item, value, duration, timestamp) VALUES (" + .@new_char + ", " + .@new_item + ", " + .@new_value + "," + .@duration + "," + .@claimtime + ")");
    				} else {
    					//not online ask if we still give the gift.
    					mes "[" + strnpcinfo(1) + "]";
    					mes "The character is not online!";
    					mes "Would you still like to send the gift?";
    					next;
    					if(select("Yes:No") != 1) goto OnLeave;
    					mes "[" + strnpcinfo(1) + "]";
    					mes "Gift sending success!";
    					//Create gift. <auto_id>, <account_id> <char_id> <item> <value>
    					query_sql("INSERT INTO `" + .GiftTableName$ + "` (char_id, item, value, duration, timestamp) VALUES (" + .@new_char + ", " + .@new_item + ", " + .@new_value + "," + .@duration + "," + .@claimtime + ")");
    				}
    
    			}
    			else
    			{
    				mes "[" + strnpcinfo(1) + "]";
    				mes "Write player name:";
    				next;
    				input .@new_name$;
    				set .@query, query_sql("SELECT char_id, account_id FROM `" + .CharTableName$ + "` WHERE name = '" + .@new_name$ + "'", .@new_char, .@new_accountid);
    				if(!.@query) goto OnNotExist;
    				if(select("Continue:Cancel") != 1) goto OnLeave;
    					mes "[" + strnpcinfo(1) + "]";
    					mes "^009900Gift is ready to go!^000000";
    					mes "CID: ^ff0000" + .@new_char + "^000000";
    					mes "Name: ^ff0000"+ .@new_name$ + "^000000";
    					mes "------------------";
    					mes "Item: ^ff0000" + getitemname(.@new_item) + "^000000";
    					mes "Quantity: ^ff0000" + .@new_value + "^000000";
    					mes "Duration: " + .@duration + " Minutes";
    					mes "Claim Time: " + .@c + " Minutes";
    				next;
    				if(select("Send Gift:Cancel") != 1) goto OnLeave;
    				//Check if player is logged in.
    				if(isloggedin(.@new_accountid))
    				{
    					mes "[" + strnpcinfo(1) + "]";
    					mes "Gift sending success!";
    					query_sql("INSERT INTO `" + .GiftTableName$ + "` (char_id, item, value, duration, timestamp) VALUES (" + .@new_char + ", " + .@new_item + ", " + .@new_value + "," + .@duration + "," + .@claimtime + ")");
    				}
    				else
    				{
    					//not online ask if we still give the gift.
    					mes "[" + strnpcinfo(1) + "]";
    					mes "The character is not online!";
    					mes "Would you still like to give the gift?";
    					next;
    					if(select("Yes:No") != 1) goto OnLeave;
    					mes "[" + strnpcinfo(1) + "]";
    					mes "Gift sending success!";
    					//Create gift. <auto_id>, <account_id> <char_id> <item> <value>
    					query_sql("INSERT INTO `" + .GiftTableName$ + "` (char_id, item, value, duration, timestamp) VALUES (" + .@new_char + ", " + .@new_item + ", " + .@new_value + "," + .@duration + "," + .@claimtime + ")");
    				}
    			}
    			announce strcharinfo(0)+" successfully sent " + .@new_value + "x " + getitemname(.@new_item) + " to " + .@new_name$,bc_all;
    			break;
    
    		//Register gift to all online accounts!
    		case 3:
    			mes "[" + strnpcinfo(1) + "]";
    			mes "^009900Gift is ready to go!^000000";
    			mes "Item: ^ff0000" + getitemname(.@new_item) + "^000000";
    			mes "Quantity: ^ff0000" + .@new_value + "^000000";
    			mes "Duration: " + .@duration + " Minutes";	
    			mes "Claim Time: " + .@c + " Minutes";
    			next;
    			if(select("Send Gift:Cancel") != 1) goto OnLeave;
    			mes "[" + strnpcinfo(1) + "]";
    			mes "Please hold...";
    			set .@c, 0; //Counting success.
    			set .@query, query_sql("SELECT account_id FROM `"+.CharTableName$+"` WHERE online=1",.@account);
    			for(set .@i, 0; .@i < .@query; set .@i, .@i + 1) {
    				sleep2 25; //Slowdown the loop abit.
    				.@at = query_sql("SELECT account_id, char_id FROM "+$GiftTableNameAT$+" WHERE account_id = "+.@account[.@i]+"", .@account_id, .@char_id); // check if in the table
    				if (!.@at) {		
    					query_sql("INSERT INTO `" + .GiftTableName$ + "` (account_id, item, value, duration, timestamp) VALUES(" + .@account[.@i] + ", " + .@new_item + ", " + .@new_value + ", " + .@duration + ", " + .@claimtime + ")");
    				}
    			}
    			mes "Gift registered to (" + .@i + ") accounts!";
    			break;
    
    		//Register gift to all accounts!
    		case 4:
    			mes "[" + strnpcinfo(1) + "]";
    			mes "^009900Gift is ready to go!^000000";
    			mes "Item: ^ff0000" + getitemname(.@new_item) + "^000000";
    			mes "Quantity: ^ff0000" + .@new_value + "^000000";
    			mes "Claim Time: " + .@c + " Minutes";		
    			next;
    			if(select("Send Gift:Cancel") != 1) goto OnLeave;
    			mes "[" + strnpcinfo(1) + "]";
    			mes "Please hold...";
    			set .@query, query_sql("SELECT account_id FROM `"+.LoginTableName$+"`",.@account);
    			for(set .@i, 0; .@i < .@query; set .@i, .@i + 1) {
    				sleep2 25; //Slowdown the loop abit.
    					query_sql("INSERT INTO `" + .GiftTableName$ + "` (account_id, item, value, duration, timestamp) VALUES(" + .@account[.@i] + ", " + .@new_item + ", " + .@new_value + ", " + .@duration + ", " + .@claimtime + ")");
    			}
    			mes "Gift registered to (" + .@i + ") accounts!";
    			break;
    
    		//Register gift to all online characters!
    		case 5:
    			mes "[" + strnpcinfo(1) + "]";
    			mes "^009900Gift is ready to go!^000000";
    			mes "Item: ^ff0000" + getitemname(.@new_item) + "^000000";
    			mes "Quantity: ^ff0000" + .@new_value + "^000000";
    			mes "Claim Time: " + .@c + " Minutes";		
    			next;
    			if(select("Send Gift:Cancel") != 1) goto OnLeave;
    			mes "[" + strnpcinfo(1) + "]";
    			mes "Please hold...";
    			set .@c, 0; //Counting success.
    			set .@query, query_sql("SELECT char_id FROM `"+.CharTableName$+"` WHERE online=1",.@char);
    			for(set .@i, 0; .@i < .@query; set .@i, .@i + 1) {
    				sleep2 25; //Slowdown the loop abit.
    				.@at = query_sql("SELECT account_id, char_id FROM "+$GiftTableNameAT$+" WHERE char_id = "+.@char[.@i]+"", .@account_id, .@char_id); // check if in the table
    				if (!.@at) {
    					query_sql("INSERT INTO `" + .GiftTableName$ + "` (char_id, item, value, duration, timestamp) VALUES (" + .@char[.@i] + ", " + .@new_item + ", " + .@new_value + "," + .@duration + "," + .@claimtime + ")");
    				}
    			}
    			mes "Gift registered to (" + .@i + ") players!";
    			break;
    
    		//Register gift to all characters!
    		case 6:
    			mes "[" + strnpcinfo(1) + "]";
    			mes "^009900Gift is ready to go!^000000";
    			mes "Item: ^ff0000" + getitemname(.@new_item) + "^000000";
    			mes "Quantity: ^ff0000" + .@new_value + "^000000";
    			mes "Claim Time: " + .@c + " Minutes";	
    			next;
    			if(select("Send Gift:Cancel") != 1) goto OnLeave;
    			mes "[" + strnpcinfo(1) + "]";
    			mes "Please hold...";
    			set .@query, query_sql("SELECT char_id FROM `"+.CharTableName$+"`",.@char);
    			for(set .@i, 0; .@i < .@query; set .@i, .@i + 1) {
    				sleep2 25; //Slowdown the loop abit.
    				query_sql("INSERT INTO `" + .GiftTableName$ + "` (char_id, item, value, duration, timestamp) VALUES (" + .@char[.@i] + ", " + .@new_item + ", " + .@new_value + "," + .@duration + "," + .@claimtime + ")");
    			}
    			mes "Gift registered to (" + .@i + ") players!";
    			break;
    
    		//Cancel.
    		Default:
    				mes "[Reward Giver]";
    				mes "See you later";
    				break;
    	}
    	close;
    
    OnLeave:
    		mes "[Reward Giver]";
    		mes "See you later";
    		cutin "v_sprakki04",255;
    		close;
    
    OnNotExist:
    		mes "[" + strnpcinfo(1) + "]";
    		mes "This account does not exist!";
    		cutin "v_sprakki04",255;
    		close;
    	
    //============Reset Function=========================
    OnDelete:
    		mes "Which gifts do you want to reset?";
    		mes "1. Single Account";
    		mes "2. Single Character";
    		mes "3. All ^009900Online^000000 Accounts.";
    		mes "4. All Accounts.";
    		mes "5. All ^009900Online^000000 Players/Characters.";
    		mes "6. All Players/Characters.";
    		mes "7. All cancel";
    		switch(select("Single Account:Single Character:^009900Online^000000 Accounts:All Accounts:^009900Online^000000 Characters:All Characters:Specific Item:IPLimit Logs:Cancel"))
    			{
    			case 1: //Single Account
    				mes "[" + strnpcinfo(1) + "]";
    				mes "Please select input type:";
    				mes "By AID or Name?";
    				next;
    				if(select("Account ID:Character Name") == 1)
    				{
    					mes "[" + strnpcinfo(1) + "]";
    					mes "Write account id:";
    					next;
    					input .@new_account, 2000000, 10000000; //Account id range from 2m to 10m.
    					set .@query, query_sql("SELECT account_id FROM `" + .CharTableName$ + "` WHERE account_id = " + .@new_account, .@new_account);
    					if(!.@query) goto OnNotExist;
    					if(select("Continue:Cancel") != 1) goto OnLeave;
    						query_sql("DELETE FROM " + .GiftTableName$ + " WHERE account_id = " + .@new_account);
    				}
    				else
    				{
    					mes "[" + strnpcinfo(1) + "]";
    					mes "Write player name:";
    					next;
    					input .@new_name$;
    					set .@query, query_sql("SELECT account_id FROM `" + .CharTableName$ + "` WHERE name = '" + .@new_name$ + "'", .@new_account);
    					if(!.@query) goto OnNotExist;
    					if(select("Continue:Cancel") != 1) goto OnLeave;
    						query_sql("DELETE FROM " + .GiftTableName$ + " WHERE account_id = " + .@new_account);
    				}
    				break;
    			case 2: //Single Character
    				mes "[" + strnpcinfo(1) + "]";
    				mes "Please select input type:";
    				mes "By CID or Name?";
    				next;
    				if(select("Character ID:Character Name") == 1)
    				{
    					mes "[" + strnpcinfo(1) + "]";
    					mes "Write character id:";
    					next;
    					input .@new_char,150000, 10000000; //Char id range from 150k to 10m.
    					set .@query, query_sql("SELECT account_id, name FROM `" + .CharTableName$ + "` WHERE char_id = " + .@new_char, .@new_accountid, .@new_name$);
    					if(!.@query) goto OnNotExist;
    					if(select("Continue:Cancel") != 1) goto OnLeave;
    						query_sql("DELETE FROM " + .GiftTableName$ + " WHERE char_id = " + .@new_char);
    				}
    				else
    				{
    					mes "[" + strnpcinfo(1) + "]";
    					mes "Write player name:";
    					next;
    					input .@new_name$;
    					set .@query, query_sql("SELECT char_id, account_id FROM `" + .CharTableName$ + "` WHERE name = '" + .@new_name$ + "'", .@new_char, .@new_accountid);
    					if(!.@query) goto OnNotExist;
    					if(select("Continue:Cancel") != 1) goto OnLeave;
    						query_sql("DELETE FROM " + .GiftTableName$ + " WHERE char_id = " + .@new_char);
    				}
    				break;
    			case 3: //All Online Accounts.
    				mes "[" + strnpcinfo(1) + "]";
    				mes "Please hold...";
    				set .@c, 0; //Counting success.
    				set .@query, query_sql("SELECT account_id FROM `"+.CharTableName$+"` WHERE online=1",.@account);
    				for(set .@i, 0; .@i < .@query; set .@i, .@i + 1) {
    					sleep2 25; //Slowdown the loop abit.
    					query_sql("DELETE FROM " + .GiftTableName$ + " WHERE account_id = " + .@account[.@i]);
    				}
    				break;
    			case 4: //All Accounts.
    				query_sql("DELETE FROM " + .GiftTableName$ + " WHERE account_id >= 1");
    				break;
    			case 5: //All Online Players/Characters.
    				mes "[" + strnpcinfo(1) + "]";
    				mes "Please hold...";
    				set .@c, 0; //Counting success.
    				set .@query, query_sql("SELECT char_id FROM `"+.CharTableName$+"` WHERE online=1",.@char);
    				for(set .@i, 0; .@i < .@query; set .@i, .@i + 1)
    					{
    						sleep2 25; //Slowdown the loop abit.
    						query_sql("DELETE FROM " + .GiftTableName$ + " WHERE char_id = " + .@char[.@i]);
    					}
    				break;
    			case 6: //All Players/Characters.
    				query_sql("TRUNCATE TABLE " + .GiftTableName$);
    				break;
    			case 7: // Delete specific item
    				mes "Please type the id of the item you wish to delete";
    				mes "This will delete all entries with the item id you typed";
    				input(.@deletethis);
    				next;
    				mes "Are you sure you want to delete all entries of " + .@deletethis;
    				if (select("Yes:No")==1)
    					{
    						query_sql("DELETE FROM " + .GiftTableName$ + " WHERE item = " + .@deletethis + "");
    					}
    					else
    					{
    						mes "Deletion cancelled";
    						close;
    					}
    			case 8: //All ip logs
    				query_sql("TRUNCATE TABLE " + .GiftTableNameIP$);
    				break;
    			default:
    				break;
    		}
    		next;
    		mes "deletion finished";
    		cutin "v_sprakki04",255;
    		close;
    
    OnLimit:
    	mes "Please enter an ip limit, current limit is " + .ip_limit;
    	input(.ip_limit);
    	mes "Done!";
    	cutin "v_sprakki04",255;
    	close;
    
    //============================================================ 
    // Config/Edit:
    //============================================================ 
    OnLoadSetup:
    	set .Setup, 1;	//OnInit is loaded check.
    	set .GMin, 60;	//Minimum GM level to use gm panel.
    	set .ZenyID,23500; // put this when asked for which item to give zeny.
    	set .MaxZeny,1000000000;
    	//Your table names:
    	set .CharTableName$, "char";	//Character table name(SQL).
    	set .LoginTableName$, "login";
    	set .GiftTableName$, "reward";	//Gift table name(SQL).
    	set .GiftTableNameIP$, "reward_ip";	//Gift table name for ip tracker
    	set $GiftTableNameAT$, "reward_at";	//Gift table name for auto trade tracker
    	//Create gift table <auto_id>, <account_id>, <char_id>, <item>, <value>
    
    	query_sql("CREATE TABLE IF NOT EXISTS `reward` (`id` int(11) NOT NULL AUTO_INCREMENT,`account_id` int(11) unsigned NOT NULL DEFAULT '0',`char_id` int(11) unsigned NOT NULL DEFAULT '0',`item` int(11) NOT NULL DEFAULT '0',`value` int(11) NOT NULL DEFAULT '0',`duration` int(11) NOT NULL DEFAULT '0',`timestamp` int(23) NOT NULL DEFAULT '0',PRIMARY KEY (`id`))");
    	query_sql("CREATE TABLE IF NOT EXISTS `reward_ip` ( `give_id` int(11) NOT NULL,  `item_id` int(11) NOT NULL,  `ip_address` varchar(23) NOT NULL, `claim_count` int(11) NOT NULL,  PRIMARY KEY (`give_id`))");
    	query_sql("CREATE TABLE IF NOT EXISTS `reward_at` (`account_id` int(11) NOT NULL,`char_id` int(11) NOT NULL)");
    	return;
    
    OnInit:
    	callsub OnLoadSetup;
    	end;
    }
    
    /* Manual table update for at tracker 
    CREATE TABLE IF NOT EXISTS `reward_at` (
      `account_id` int(11) NOT NULL,
      `char_id` int(11) NOT NULL
    );
    */
    -	script	anti_trader	-1,{
    	
    OnInit:
    	.is_anti_trade = 1; // 0 to disable
    	end;
    	
    }
    function	script	PG_30Seconds	{
    	//dispbottom "anti trader 30sec";
    	//Check if Vending (normal or @at)
    	if(checkvending() >= 1)
    	{
    	   // mark as auto trader
    	   	.@query = query_sql("SELECT account_id, char_id FROM "+$GiftTableNameAT$+" WHERE account_id = "+getcharid(3)+"", .@account_id, .@char_id); // check if in the table
    		if (!.@query)
    		{ // add if not there yet
    			query_sql("INSERT INTO "+$GiftTableNameAT$+"(account_id,char_id) VALUES("+getcharid(3)+","+getcharid(0)+")");
    			//dispbottom "you have been marked as auto trader";
    			stopnpctimer;
    			detachnpctimer;
    			end;
    		}
    	}
    	return;
    }
    function	script	PG_Login	{
    	//dispbottom "at delete";
    	.@query = query_sql("SELECT account_id, char_id FROM "+$GiftTableNameAT$+" WHERE account_id = "+getcharid(3)+"", .@account_id, .@char_id); // check if in the table
    	if (.@query)
    	{ // remove to reverify vending status
    		query_sql("DELETE FROM "+$GiftTableNameAT$+" WHERE account_id = "+getcharid(3)+"");
    	}
    }
    	
    

  4. I saw some people asking to make the costume converter compatible with 3ceam.
    So i look upon it and just so happen to caught my interest even though i'm not fond
    of costume system.
     
    so without further ado!
    Here's a patch i made for you guys.
     
    EDIT: 
     
       V2 Fixed missing script.c dependencies

       V3 Removed the relocation of ammo as informed by 15peaces that rytech moved it to the last for ammo-fix.

            sorry, i was not aware about it.

     
    3CEAM_COSTUME_CONVERTER_V3.patch
     
     

    Index: conf/battle/battle.conf
    ===================================================================
    --- conf/battle/battle.conf	(revision 801)
    +++ conf/battle/battle.conf	(working copy)
    @@ -171,3 +171,9 @@
     // range. For example, Sonic Blow requires a 2 cell distance before autocasting is allowed.
     // This setting also affects autospellwhenhit.
     autospell_check_range: no
    +
    +// ****************************************
    +// Reserved Costume ID's
    +// ****************************************
    +// Reserved Char ID for costume converted items.
    +reserved_costume_id: 999998
    \ No newline at end of file
    Index: npc/custom/costume.txt
    ===================================================================
    --- npc/custom/costume.txt	(nonexistent)
    +++ npc/custom/costume.txt	(working copy)
    @@ -0,0 +1,146 @@
    +//===== Hercules Script ======================================
    +//= Headgear to Costume converter >> Costume to Headgear converter
    +//===== By: ==================================================
    +//= Rebel, Zephyrus [rAthena]
    +//= Mhalicot [Hercules]
    +//===== Current Version: =====================================
    +//= 1.1
    +//===== Compatible With: =====================================
    +//= Hercules
    +//===== Description: =========================================
    +//= Allows a user to convert the equipped headgear 
    +//	(on Top, Mid or Low) into a costume item. 
    +//	It will remove any card and refine of the Item.
    +//= Allows a user to restore the equipped costume headgear 
    +//	(on Top, Mid or Low) into its original form. 
    +//	It will not return any card or refine of the item.
    +//===== Additional Comments: =================================
    +//= 1.0 Initial script [All of this script are credit to
    +//	Rebel, Zephyrus of [rAthena] and revised by [Mhalicot]
    +//	to make it compatible in Hercules.]
    +//= 1.1 Denied if Headgear is rental, has refine,
    +//	or has card[Mhalicot]
    +//	Note: You must apply the patch in order to use this script
    +//============================================================
    +-	script	Costume Clown	-1,{
    +	mes "[Clown]";
    +	mes "Here you can convert your headgears into a Costume Headgear or restore to its Original form.";
    +	switch(select("I want to convert.:I want to restore.:No thanks.")) {
    +	case 1:
    +			next;
    +			mes "[Clown]";
    +			mes "Please, select what to convert.";
    +			mes "Remember, cards and refine will be removed.";
    +			next;
    +				setarray .@Position$[1],"Top","Mid","Low";
    +				setarray .@Position[1],     1,    9,   10;
    +				set .@Menu$,"";
    +			for( set .@i, 1; .@i < 5; set .@i, .@i + 1 )
    +			{
    +				if( getequipisequiped(.@Position[.@i]) )
    +				set .@Menu$, .@Menu$ + .@Position$[.@i] + "-" + "[" + getequipname(.@Position[.@i]) + "]";
    +				set .@Menu$, .@Menu$ + ":";
    +			}
    +			set .@Part, .@Position[ select(.@Menu$) ];
    +			set .@id, getequipid(.@Part);
    +			set .@ref, getequiprefinerycnt(.@Part);
    +			if( !getequipisequiped(.@Part) )
    +			{
    +				mes "[Clown]";
    +				mes "Your not wearing anything there...";
    +				close;
    +			}
    +			mes "[Clown]";
    +			mes "You want to Costume your " + getitemname(getequipid(.@Part)) + "?";
    +			next;
    +			if( select("Yes, proceed:No, I am sorry.") == 2 )
    +			{
    +				mes "[Clown]";
    +				mes "Need some time to think about it, huh?";
    +				mes "Alright, I can understand.";
    +				close;
    +			}
    +			for(set .@i,0; .@i<4; set .@i,.@i+1)
    +				set .@slot[.@i], getequipcardid(.@Part,.@i);
    +			if (.@slot[0]>4000 && .@slot[0]<5000) { // If it has card don't convert
    +				mes "[Clown]";
    +				mes "A card? Here?!";
    +				mes "As I said before, I don't convert headgear with cards.";
    +				emotion e_hmm;
    +				close;
    +			}
    +			getinventorylist;
    +			for(set .@i,0; .@i<@inventorylist_count; set .@i,.@i+1)
    +				if (@inventorylist_expire[.@i] != 0 && @inventorylist_equip[.@i] != 0) { // If rental don't convert
    +				mes "[Clown]";
    +				mes "Sorry, I don't convert a rental headgear!";
    +				emotion e_hmm;
    +				close;
    +				}
    +				if (.@ref > 0) { // If refine don't convert
    +				mes "[Clown]";
    +				mes "Sorry please keep in mind.";
    +				mes "I don't convert headgear with refine.";
    +				emotion e_hmm;
    +				close;
    +				}
    +			if (!countitem(.@id)) { 
    +				mes "[Clown]";
    +				mes "Where is "+getitemname(@id)+"...?";
    +				npctalk "You're a snoozy cheater!";
    +				logmes "CHEATER: Tried to sign an item not having it: "+getitemname(@id);
    +				emotion e_wah;
    +				close;
    +			}
    +			costume .@Part; // Convert the Headgear
    +			mes "[Clown]";
    +			mes "Done, enjoy your costume headgear.";
    +			close;
    +	case 2:
    +			next;
    +			mes "Please, select what to restore.";
    +			mes "Remember, I will only restore it back without refine and cards.";
    +			next;
    +				setarray .@Position$[1],"Top","Mid","Low";
    +				setarray .@Position[1],     13,    12,   11;
    +				set .@Menu$,"";
    +			for( set .@i, 1; .@i < 5; set .@i, .@i + 1 )
    +			{
    +				if( getequipisequiped(.@Position[.@i]) )
    +				set .@Menu$, .@Menu$ + .@Position$[.@i] + "-" + "[" + getequipname(.@Position[.@i]) + "]";
    +				set .@Menu$, .@Menu$ + ":";
    +			}
    +			set .@Part, .@Position[ select(.@Menu$) ];
    +			if( !getequipisequiped(.@Part) )
    +			{
    +				mes "[Clown]";
    +				mes "Your not wearing anything there...";
    +				close;
    +			}
    +			mes "[Clown]";
    +			mes "You want to restore your " + getitemname(getequipid(.@Part)) + "?";
    +			next;
    +			if( select("Yes, proceed:No, I am sorry.") == 2 )
    +			{
    +				mes "[Clown]";
    +				mes "Need some time to think about it, huh?";
    +				mes "Alright, I can understand.";
    +				close;
    +			}
    +			a = getequipid(.@Part);			
    +			delitem a,1;
    +			getitem a,1;
    +			
    +			mes "[Clown]";
    +			mes "Done, enjoy your restored headgear.";
    +			close;
    +	case 3:
    +		mes "[Clown]";
    +		mes "Very well. Return at once if you seek my services.";
    +		close;
    +	}
    +}
    +// --------------------------------------------------------------------------
    +// Use duplicates to put your npc on different cities
    +// --------------------------------------------------------------------------
    +prontera,155,181,4	duplicate(Costume Clown)	Costume Clown#1	715
    \ No newline at end of file
    Index: npc/scripts_custom.conf
    ===================================================================
    --- npc/scripts_custom.conf	(revision 801)
    +++ npc/scripts_custom.conf	(working copy)
    @@ -9,6 +9,7 @@
     //                     Your scripts go here!!
     // --------------------------------------------------------------
     // ----------------------- Basic  Scripts -----------------------
    +npc: npc/custom/costume.txt
     // -- Card Remover
     //npc: npc/custom/card_remover.txt
     // -- Write your name on your equipment/weapon (mini-quest)
    Index: src/map/atcommand.c
    ===================================================================
    --- src/map/atcommand.c	(revision 801)
    +++ src/map/atcommand.c	(working copy)
    @@ -1679,7 +1679,7 @@
     ACMD_FUNC(item)
     {
     	char item_name[100];
    -	int number = 0, item_id, flag;
    +	int number = 0, item_id, flag = 0, costume = 0;
     	struct item item_tmp;
     	struct item_data *item_data;
     	int get_count, i;
    @@ -1704,6 +1704,27 @@
     		clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name.
     		return -1;
     	}
    +	
    +	
    +	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->equip&EQP_HEAD_LOW) &&
    +			!(item_data->equip&EQP_HEAD_MID) &&
    +			!(item_data->equip&EQP_HEAD_TOP) &&
    +			!(item_data->equip&EQP_COSTUME_HEAD_LOW) &&
    +			!(item_data->equip&EQP_COSTUME_HEAD_MID) &&
    +			!(item_data->equip&EQP_COSTUME_HEAD_TOP) )
    +		{
    +			clif_displaymessage(fd, "You cannot costume this item. Costume only work for headgears.");
    +			return -1;
    +		}
    +		costume = 1;
    +	}
     
     	item_id = item_data->nameid;
     	get_count = number;
    @@ -1718,6 +1739,13 @@
     			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);
    +			}
    +
     			if ((flag = pc_additem(sd, &item_tmp, get_count)))
     				clif_additem(sd, 0, 0, flag);
     		}
    @@ -9218,6 +9246,7 @@
     	{ "kamic",             40,40,     atcommand_kami },
     	{ "heal",              40,60,     atcommand_heal },
     	{ "item",              60,60,     atcommand_item },
    +	{ "costumeitem",       99,99,     atcommand_item },
     	{ "item2",             60,60,     atcommand_item2 },
     	{ "itemreset",         40,40,     atcommand_itemreset },
     	{ "blvl",              60,60,     atcommand_baselevelup },
    Index: src/map/battle.c
    ===================================================================
    --- src/map/battle.c	(revision 801)
    +++ src/map/battle.c	(working copy)
    @@ -5848,6 +5848,7 @@
     	{ "buyer_name",                         &battle_config.buyer_name,                      1,      0,      1,              },
     	{ "skill_wall_check",                   &battle_config.skill_wall_check,                1,      0,      1,              },
     	{ "cell_stack_limit",                   &battle_config.cell_stack_limit,                1,      1,      255,            },
    +	{ "reserved_costume_id",                &battle_config.reserved_costume_id,             999998, 0,      INT_MAX,        },
     // eAthena additions
     	{ "item_logarithmic_drops",             &battle_config.logarithmic_drops,               0,      0,      1,              },
     	{ "item_drop_common_min",               &battle_config.item_drop_common_min,            1,      1,      10000,          },
    Index: src/map/battle.h
    ===================================================================
    --- src/map/battle.h	(revision 801)
    +++ src/map/battle.h	(working copy)
    @@ -540,6 +540,9 @@
     	int oktoberfest_ignorepalette;
     	int summer2_ignorepalette;
     
    +	// Costume System
    +	int reserved_costume_id;
    +
     	// Homunculus Limits
     	int max_homunculus_hp;
     	int max_homunculus_sp;
    Index: src/map/map.c
    ===================================================================
    --- src/map/map.c	(revision 801)
    +++ src/map/map.c	(working copy)
    @@ -1677,6 +1677,12 @@
     
     	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 )
     	{
    Index: src/map/pc.c
    ===================================================================
    --- src/map/pc.c	(revision 801)
    +++ src/map/pc.c	(working copy)
    @@ -845,7 +845,7 @@
     
     int pc_equippoint(struct map_session_data *sd,int n)
     {
    -	int ep = 0;
    +	int ep = 0, char_id = 0;
     
     	nullpo_ret(sd);
     
    @@ -863,6 +863,15 @@
     			(sd->class_&MAPID_UPPERMASK) == MAPID_KAGEROUOBORO))//Kagerou and Oboro can dual wield daggers. [Rytech]
     			return EQP_ARMS;
     	}
    +	
    +	if( battle_config.reserved_costume_id &&
    +		sd->status.inventory[n].card[0] == CARD0_CREATE &&
    +		(char_id = MakeDWord(sd->status.inventory[n].card[2],sd->status.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; }
    +	}
     	return ep;
     }
     
    @@ -2082,8 +2091,8 @@
     				if( autobonus[i].bonus_script )
     				{
     					int j;
    -					ARR_FIND( 0, EQI_MAX-1, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus[i].pos );
    -					if( j < EQI_MAX-1 )
    +					ARR_FIND( 0, EQI_MAX_BONUS, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus[i].pos );
    +					if( j < EQI_MAX_BONUS )
     						script_run_autobonus(autobonus[i].bonus_script,sd->bl.id,sd->equip_index[j]);
     				}
     				continue;
    @@ -2113,8 +2122,8 @@
     	if( autobonus->other_script )
     	{
     		int j;
    -		ARR_FIND( 0, EQI_MAX-1, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus->pos );
    -		if( j < EQI_MAX-1 )
    +		ARR_FIND( 0, EQI_MAX_BONUS, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus->pos );
    +		if( j < EQI_MAX_BONUS )
     			script_run_autobonus(autobonus->other_script,sd->bl.id,sd->equip_index[j]);
     	}
     
    Index: src/map/pc.h
    ===================================================================
    --- src/map/pc.h	(revision 801)
    +++ src/map/pc.h	(working copy)
    @@ -563,6 +563,8 @@
     	EQI_ARMOR,
     	EQI_HAND_L,
     	EQI_HAND_R,
    +	EQI_MAX_BONUS = 10,
     	EQI_COSTUME_HEAD_LOW,
     	EQI_COSTUME_HEAD_MID,
     	EQI_COSTUME_HEAD_TOP,
    @@ -574,7 +576,6 @@
     	EQI_SHADOW_SHOES,
     	EQI_SHADOW_ACC_R,
     	EQI_SHADOW_ACC_L,
     	EQI_AMMO,
     	EQI_MAX
     };
     
    Index: src/map/script.c
    ===================================================================
    --- src/map/script.c	(revision 801)
    +++ src/map/script.c	(working copy)
    @@ -208,6 +208,12 @@
     DBMap* script_get_label_db(){ return scriptlabel_db; }
     DBMap* script_get_userfunc_db(){ return userfunc_db; }
     
    +// important buildin function references for usage in scripts
    +static int buildin_set_ref = 0;
    +static int buildin_callsub_ref = 0;
    +static int buildin_callfunc_ref = 0;
    +static int buildin_getelementofarray_ref = 0;
    +
     // Caches compiled autoscript item code. 
     // Note: This is not cleared when reloading itemdb.
     static DBMap* autobonus_db=NULL; // char* script -> char* bytecode
    @@ -903,7 +909,7 @@
     /// The argument list can have parenthesis or not.
     /// The number of arguments is checked.
     static
    -const char* parse_callfunc(const char* p, int require_paren)
    +const char* parse_callfunc(const char* p, int require_paren, int is_custom)
     {
     	const char* p2;
     	const char* arg=NULL;
    @@ -917,17 +923,32 @@
     		arg = buildin_func[str_data[func].val].arg;
     	} else if( str_data[func].type == C_USERFUNC || str_data[func].type == C_USERFUNC_POS ){
     		// script defined function
    -		int callsub = search_str("callsub");
    -		add_scriptl(callsub);
    +		add_scriptl(buildin_callsub_ref);
     		add_scriptc(C_ARG);
     		add_scriptl(func);
    -		arg = buildin_func[str_data[callsub].val].arg;
    +		arg = buildin_func[str_data[buildin_callsub_ref].val].arg;
     		if( *arg == 0 )
     			disp_error_message("parse_callfunc: callsub has no arguments, please review it's definition",p);
     		if( *arg != '*' )
     			++arg; // count func as argument
    -	} else
    -		disp_error_message("parse_line: expect command, missing function name or calling undeclared function",p);
    +	} else {
    +#ifdef SCRIPT_CALLFUNC_CHECK
    +		const char* name = get_str(func);
    +		if( !is_custom && strdb_get(userfunc_db, name) == NULL ) {
    +#endif
    +			disp_error_message("parse_line: expect command, missing function name or calling undeclared function",p);
    +#ifdef SCRIPT_CALLFUNC_CHECK
    +		} else {;
    +			add_scriptl(buildin_callfunc_ref);
    +			add_scriptc(C_ARG);
    +			add_scriptc(C_STR);
    +			while( *name ) add_scriptb(*name ++);
    +			add_scriptb(0);
    +			arg = buildin_func[str_data[buildin_callfunc_ref].val].arg;
    +			if( *arg != '*' ) ++ arg;
    +		}
    +#endif
    +	}
     
     	p = skip_word(p);
     	p = skip_space(p);
    @@ -1002,6 +1023,157 @@
     	str_data[LABEL_NEXTLINE].label     = -1;
     }
     
    +/// Parse a variable assignment using the direct equals operator
    +/// @param p script position where the function should run from
    +/// @return NULL if not a variable assignment, the new position otherwise
    +const char* parse_variable(const char* p)
    +{
    +	int i, j, word;
    +	c_op type = C_NOP;
    +	const char *p2 = NULL;
    +	const char *var = p;
    +			
    +	// skip the variable where applicable
    +	p = skip_word(p);
    +	p = skip_space(p);
    +
    +	if( p == NULL )
    +	{// end of the line or invalid buffer
    +		return NULL;
    +	}
    +
    +	if( *p == '[' )
    +	{// array variable so process the array as appropriate
    +		for( p2 = p, i = 0, j = 1; p; ++ i )
    +		{
    +			if( *p ++ == ']' && --(j) == 0 ) break;
    +			if( *p == '[' ) ++ j;
    +		}
    +
    +		if( !(p = skip_space(p)) )
    +		{// end of line or invalid characters remaining
    +			disp_error_message("Missing right expression or closing bracket for variable.", p);
    +		}
    +	}
    +
    +	if( type == C_NOP &&
    +	!( ( p[0] == '=' && p[1] != '=' && (type = C_EQ) ) // =
    +	|| ( p[0] == '+' && p[1] == '=' && (type = C_ADD) ) // +=
    +	|| ( p[0] == '-' && p[1] == '=' && (type = C_SUB) ) // -=
    +	|| ( p[0] == '^' && p[1] == '=' && (type = C_XOR) ) // ^=
    +	|| ( p[0] == '|' && p[1] == '=' && (type = C_OR ) ) // |=
    +	|| ( p[0] == '&' && p[1] == '=' && (type = C_AND) ) // &=
    +	|| ( p[0] == '*' && p[1] == '=' && (type = C_MUL) ) // *=
    +	|| ( p[0] == '/' && p[1] == '=' && (type = C_DIV) ) // /=
    +	|| ( p[0] == '%' && p[1] == '=' && (type = C_MOD) ) // %=
    +	|| ( p[0] == '~' && p[1] == '=' && (type = C_NOT) ) // ~=
    +	|| ( p[0] == '+' && p[1] == '+' && (type = C_ADD_PP) ) // ++
    +	|| ( p[0] == '-' && p[1] == '-' && (type = C_SUB_PP) ) // --
    +	|| ( p[0] == '<' && p[1] == '<' && p[2] == '=' && (type = C_L_SHIFT) ) // <<=
    +	|| ( p[0] == '>' && p[1] == '>' && p[2] == '=' && (type = C_R_SHIFT) ) // >>=
    +	) )
    +	{// failed to find a matching operator combination so invalid
    +		return NULL;
    +	}
    +
    +	switch( type )
    +	{
    +		case C_EQ:
    +		{// incremental modifier
    +			p = skip_space( &p[1] );
    +		}
    +		break;
    +
    +		case C_L_SHIFT:
    +		case C_R_SHIFT:
    +		{// left or right shift modifier
    +			p = skip_space( &p[3] );
    +		}
    +		break;
    +
    +		default:
    +		{// normal incremental command
    +			p = skip_space( &p[2] );
    +		}
    +	}
    +
    +	if( p == NULL )
    +	{// end of line or invalid buffer
    +		return NULL;
    +	}
    +	
    +	// push the set function onto the stack
    +	add_scriptl(buildin_set_ref);
    +	add_scriptc(C_ARG);
    +
    +	// always append parenthesis to avoid errors
    +	syntax.curly[syntax.curly_count].type = TYPE_ARGLIST;
    +	syntax.curly[syntax.curly_count].count = 0;
    +	syntax.curly[syntax.curly_count].flag = ARGLIST_PAREN;
    +
    +	// increment the total curly count for the position in the script
    +	++ syntax.curly_count;
    +	
    +	// parse the variable currently being modified
    +	word = add_word(var);
    +
    +	if( str_data[word].type == C_FUNC || str_data[word].type == C_USERFUNC || str_data[word].type == C_USERFUNC_POS )
    +	{// cannot assign a variable which exists as a function or label
    +		disp_error_message("Cannot modify a variable which has the same name as a function or label.", p);
    +	}
    +
    +	if( p2 )
    +	{// process the variable index
    +		const char* p3 = NULL;
    +
    +		// push the getelementofarray method into the stack
    +		add_scriptl(buildin_getelementofarray_ref);
    +		add_scriptc(C_ARG);
    +		add_scriptl(word);
    +			
    +		// process the sub-expression for this assignment
    +		p3 = parse_subexpr(p2 + 1, 1);
    +		p3 = skip_space(p3);
    +
    +		if( *p3 != ']' )
    +		{// closing parenthesis is required for this script
    +			disp_error_message("Missing closing ']' parenthesis for the variable assignment.", p3);
    +		}
    +
    +		// push the closing function stack operator onto the stack
    +		add_scriptc(C_FUNC);
    +		p3 ++;
    +	}
    +	else
    +	{// simply push the variable or value onto the stack
    +		add_scriptl(word);
    +	}
    +	
    +	if( type == C_ADD_PP || type == C_SUB_PP )
    +	{// incremental operator for the method
    +		add_scripti(1);
    +		add_scriptc(type == C_ADD_PP ? C_ADD : C_SUB);
    +	}
    +	else
    +	{// process the value as an expression
    +		p = parse_subexpr(p, -1);
    +
    +		if( type != C_EQ )
    +		{// push the type of modifier onto the stack
    +			add_scriptc(type);
    +		}
    +	}
    +
    +	// decrement the curly count for the position within the script
    +	-- syntax.curly_count;
    +	
    +	// close the script by appending the function operator
    +	add_scriptc(C_FUNC);
    +		
    +	// push the buffer from the method
    +	return p;
    +}
    +
     /*==========================================
      * €‚̉ðÍ
      *------------------------------------------*/
    @@ -1059,6 +1231,8 @@
     		p++;	//'"'
     	} else {
     		int l;
    +		const char* pv;
    +
     		// label , register , function etc
     		if(skip_word(p)==p)
     			disp_error_message("parse_simpleexpr: unexpected character",p);
    @@ -1065,12 +1239,25 @@
     
     		l=add_word(p);
     		if( str_data[l].type == C_FUNC || str_data[l].type == C_USERFUNC || str_data[l].type == C_USERFUNC_POS)
    -			return parse_callfunc(p,1);
    +			return parse_callfunc(p,1,0);
    +#ifdef SCRIPT_CALLFUNC_CHECK
    +		else {
    +			const char* name = get_str(l);
    +			if( strdb_get(userfunc_db,name) != NULL ) {
    +				return parse_callfunc(p,1,1);
    +			}
    +		}
    +#endif
     
    +		if( (pv = parse_variable(p)) )
    +		{// successfully processed a variable assignment
    +			return pv;
    +		}
    +
     		p=skip_word(p);
     		if( *p == '[' ){
     			// array(name[i] => getelementofarray(name,i) )
    -			add_scriptl(search_str("getelementofarray"));
    +			add_scriptl(buildin_getelementofarray_ref);
     			add_scriptc(C_ARG);
     			add_scriptl(l);
     			
    @@ -1196,7 +1383,15 @@
     	if(p2 != NULL)
     		return p2;
     
    -	p = parse_callfunc(p,0);
    +	// attempt to process a variable assignment
    +	p2 = parse_variable(p);
    +
    +	if( p2 != NULL )
    +	{// variable assignment processed so leave the method
    +		return parse_syntax_close(p2 + 1);
    +	}
    +
    +	p = parse_callfunc(p,0,0);
     	p = skip_space(p);
     
     	if(parse_syntax_for_flag) {
    @@ -1919,6 +2114,11 @@
     			str_data[n].type = C_FUNC;
     			str_data[n].val = i;
     			str_data[n].func = buildin_func[i].func;
    +
    +			if( !strcmp(buildin_func[i].name, "set") ) buildin_set_ref = n; else
    +			if( !strcmp(buildin_func[i].name, "callsub") ) buildin_callsub_ref = n; else
    +			if( !strcmp(buildin_func[i].name, "callfunc") ) buildin_callfunc_ref = n; else
    +			if( !strcmp(buildin_func[i].name, "getelementofarray") ) buildin_getelementofarray_ref = n;
     		}
     	}
     }
    @@ -3442,7 +3642,7 @@
     			run_func(st);
     			if(st->state==GOTO){
     				st->state = RUN;
    -				if( gotocount>0 && (--gotocount)<=0 ){
    +				if( !st->freeloop && gotocount>0 && (--gotocount)<=0 ){
     					ShowError("run_script: infinity loop !\n");
     					script_reportsrc(st);
     					st->state=END;
    @@ -3490,7 +3690,7 @@
     			st->state=END;
     			break;
     		}
    -		if( cmdcount>0 && (--cmdcount)<=0 ){
    +		if( !st->freeloop && cmdcount>0 && (--cmdcount)<=0 ){
     			ShowError("run_script: infinity loop !\n");
     			script_reportsrc(st);
     			st->state=END;
    @@ -15073,6 +15273,134 @@
     	return 0;
     }
     
    +/**
    + * Retrieves quantity of arguments provided to callfunc/callsub.
    + * getargcount() -> amount of arguments received in a function
    + **/
    +BUILDIN_FUNC(getargcount) {
    +	struct script_retinfo* ri;
    +
    +	if( st->stack->defsp < 1 || st->stack->stack_data[st->stack->defsp - 1].type != C_RETINFO ) {
    +		ShowError("script:getargcount: used out of function or callsub label!\n");
    +		st->state = END;
    +		return 1;
    +	}
    +	ri = st->stack->stack_data[st->stack->defsp - 1].u.ri;
    +
    +	script_pushint(st, ri->nargs);
    +
    +	return 0;
    +}
    +
    +/**
    + * is_function(<function name>) -> 1 if function exists, 0 otherwise
    + **/
    +BUILDIN_FUNC(is_function) {
    +	const char* str = script_getstr(st,2);
    +
    +	if( ((struct script_code*)strdb_get(userfunc_db, str)) != NULL )
    +		script_pushint(st,1);
    +	else
    +		script_pushint(st,0);
    +
    +	return 0;
    +}
    +
    +/**
    + * freeloop(<toggle>) -> toggles this script instance's looping-check ability
    + **/
    +BUILDIN_FUNC(freeloop) {
    +
    +	if( script_getnum(st,2) )
    +		st->freeloop = 1;
    +	else
    +		st->freeloop = 0;
    +
    +	script_pushint(st, st->freeloop);
    +
    +	return 0;
    +}
    +
    +BUILDIN_FUNC(consumeitem)
    +{
    +	TBL_PC *sd;
    +	struct script_data *data;
    +	struct item_data *item_data;
    +
    +	sd = script_rid2sd(st);
    +	if( sd == NULL )
    +		return 0;
    +
    +	data = script_getdata( st, 2 );
    +	get_val( st, data );
    +
    +	if( data_isstring( data ) ){
    +		const char *name = conv_str( st, data );
    +
    +		if( ( item_data = itemdb_searchname( name ) ) == NULL ){
    +			ShowError( "buildin_consumeitem: Nonexistant item %s requested.\n", name );
    +			return 1;
    +		}
    +	}else if( data_isint( data ) ){
    +		unsigned short nameid = conv_num( st, data );
    +
    +		if( ( item_data = itemdb_exists( nameid ) ) == NULL ){
    +			ShowError("buildin_consumeitem: Nonexistant item %hu requested.\n", nameid );
    +			return 1;
    +		}
    +	}else{
    +		ShowError("buildin_consumeitem: invalid data type for argument #1 (%d).\n", data->type );
    +		return 1;
    +	}
    +
    +	run_script( item_data->script, 0, sd->bl.id, 0 );
    +	return 0;
    +}
    +
    +/*==========================================
    + * Costume Items
    + *------------------------------------------*/
    +BUILDIN_FUNC(costume)
    +{
    +	int i = -1, num, ep;
    +	TBL_PC *sd;
    +
    +	num = script_getnum(st,2); // Equip Slot
    +	sd = script_rid2sd(st);
    +
    +	if( sd == NULL )
    +		return 0;
    +	if( num > 0 && num <= ARRAYLENGTH(equip) )
    +		i = pc_checkequip(sd, equip[num - 1]);
    +	if( i < 0 )
    +		return 0;
    +
    +	ep = sd->status.inventory[i].equip;
    +	if( !(ep&EQP_HEAD_LOW) && !(ep&EQP_HEAD_MID) && !(ep&EQP_HEAD_TOP) )
    +		return 0;
    +
    +	pc_unequipitem(sd,i,2);
    +	clif_delitem(sd,i,1,3);
    +	// --------------------------------------------------------------------
    +	sd->status.inventory[i].refine = 0;
    +	sd->status.inventory[i].attribute = 0;
    +	sd->status.inventory[i].card[0] = CARD0_CREATE;
    +	sd->status.inventory[i].card[1] = 0;
    +	sd->status.inventory[i].card[2] = GetWord(battle_config.reserved_costume_id, 0);
    +	sd->status.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; }
    +	// --------------------------------------------------------------------
    +
    +	clif_additem(sd,i,1,0);
    +	pc_equipitem(sd,i,ep);
    +	clif_misceffect(&sd->bl,3);
    +
    +	return 0;
    +}
    +
     // declarations that were supposed to be exported from npc_chat.c
     #ifdef PCRE_SUPPORT
     BUILDIN_FUNC(defpattern);
    @@ -15464,6 +15792,15 @@
     	BUILDIN_DEF(bg_getareausers,"isiiii"),
     	BUILDIN_DEF(bg_updatescore,"sii"),
     
    +		/**
    +	 * rAthena and beyond!
    +	 **/
    +	BUILDIN_DEF(getargcount,""),
    +	BUILDIN_DEF(is_function,"s"),
    +	BUILDIN_DEF(freeloop,"i"),
    +	BUILDIN_DEF(consumeitem,"v?"),
    +	BUILDIN_DEF(costume,"i"),
    +
     	// Instancing
     	BUILDIN_DEF(instance_create,"si"),
     	BUILDIN_DEF(instance_destroy,"?"),
    Index: src/map/script.h
    ===================================================================
    --- src/map/script.h	(revision 801)
    +++ src/map/script.h	(working copy)
    @@ -68,7 +68,9 @@
     	C_LNOT, // ! a
     	C_NOT, // ~ a
     	C_R_SHIFT, // a >> b
    -	C_L_SHIFT // a << b
    +	C_L_SHIFT, // a << b
    +	C_ADD_PP, // ++a
    +	C_SUB_PP, // --a
     } c_op;
     
     struct script_retinfo {
    @@ -125,6 +127,7 @@
     	//For backing up purposes
     	struct script_state *bk_st;
     	int bk_npcid;
    +	unsigned freeloop : 1;// used by buildin_freeloop
     };
     
     struct script_reg {
    Index: src/map/status.c
    ===================================================================
    --- src/map/status.c	(revision 801)
    +++ src/map/status.c	(working copy)
    @@ -2471,7 +2471,7 @@
     	pc_delautobonus(sd,sd->autobonus3,ARRAYLENGTH(sd->autobonus3),true);
     
     	// Parse equipment.
    -	for( i = 0; i < EQI_MAX - 1; i++ )
    +	for( i = 0; i < EQI_MAX_BONUS; i++ )
     	{
     		current_equip_item_index = index = sd->equip_index[i]; //We pass INDEX to current_equip_item_index - for EQUIP_SCRIPT (new cards solution) [Lupus]
     		if( index < 0 )
    
    

     

    Kindly report for any missing dependencies.
    i will fix it
     
    :D

    3CEAM_COSTUME_CONVERTER.patch

    3CEAM_COSTUME_CONVERTER_V2.patch

    costume_v2.txt


  5. Finally i am able to post here.

     

    Now here's my simple 3rd to Expanded Class job changer script release.

    Hope this would help you guys. :D

     

    3E_jobchanger.txt

     

     

    //======= 3ceam Script =======================================
    //= Job Changer NPC
    //===== By: ==================================================
    //= Keitenai
    //===== Current Version: =====================================
    //= 1.1
    //===== Compatible With: =====================================
    //= Athena Project
    //===== Description: =========================================
    //= Job changer including 3rd and expanded classes.
    //===== Additional Comments: =================================
    //= 1.0 First Version
    //= 1.1 Fixed oboro showing as kagerou, and vise versa.
    //============================================================
    
    -	script	Job Changer	-1,{
    	
    	mes "^ff0000[Job Master]^000000";
    
    			if(Class >= 4054 && Class <= 4085) goto Max;
    			if(Upper == 1 && Class >= 4008 && Class <= 4022)goto Third_Job;
    			if(JobLevel < 10) goto Low_JobLevel;
    
    	switch(Class)
    	{ case 4001: case Job_Baby: case 0:
    				skill 142,1,0;
    				skill 143,1,0;
    
    		mes "Hello there! you may select the job you want to change into";
    		if(lastJob != 0 && Class == 4001)
    			{ switch (lastJob)
    				{
    					case  7:  case 14:   set @target_job, 4002; break;
    					case 15:  case  8:   set @target_job, 4005; break;
    					case 18:  case 10:   set @target_job, 4006; break;
    					case 17:  case 12:   set @target_job, 4007; break;
    					case 9:   case 16:   set @target_job, 4003; break;
    					case 11:  case 19:  case 20: set @target_job,  4004;
    					break;
    				}
    			}
    			else
    			{
    				switch
    					(select(
    						"Swordsman",
    						"Mage",
    						"Archer",
    						"Acolyte",
    						"Merchant",
    						"Thief",
    						"Super Novice",
    						"Taekwon",
    						"Gunslinger",
    						"Ninja"
    					))
    					{
    						case 7:
    							if(Class == 4001 | $@Super_Novice > BaseLevel)
    								goto Requirements;
    							if(Upper == 2)
    								set @target_job, 4045; else	set @target_job, 23;
    								break;
    						case 8:
    							if(Class == 4001 | Upper == 2)
    								goto Requirements;
    								set @target_job, Job_Taekwon;
    								break;
    						case 9:
    						case 10:
    							if(Class == 4001 | Upper == 2)
    								goto Requirements;
    								set @target_job, @menu + 15;
    								break;
    						default:
    							set @target_job, @menu;
    							if(Class == 4001) set @target_job, @target_job + 4001;
    							break;
    					}
    			}
    		mes "Are you sure you want to change to " + JobName(@target_job) + "?";
    		if(select("No","Yes") == 2)
    		{
    				callfunc "Job_Change",
    				@target_job;
    
    			if(@target_job == 24 || @target_job == 25 || @target_job == Job_Taekwon)
    			{
    				callfunc "F_ClearJobVar";
    			}
    			else
    			{
    				if($@Platinum_Skill) goto Obtain_Platinum;
    			}
    		}
    			close; break; default:
    
    		if(Class >=24 && Class <=25)
    		{
    			if(BaseLevel < 99 || JobLevel < 40) goto Requirements;
    
    		mes "Are you sure you want to change to Expanded Class?";
    			if(select("Yes","No")==1)
    			{
    					switch(Class){
    						case 24:
    							set @target_job, 4215;
    							break;
    						case 25:
    							if(Sex!=0){
    								set @target_job, 4211;
    							}else{
    								set @target_job, 4212;
    							}
    							break;
    						}
    
    		mes "Are you sure you want to change to " + JobName(@target_job) + "?";
    			if(select("No","Yes") == 2)
    				{
    				callfunc "Job_Change", @target_job;
    				//resetlvl(1);
    				atcommand "@blvl +99";
    				specialeffect2 381;
    				close;
    				}
    			}
    		}
    
    		if(JobLevel < $@Min_JobLevel) goto Low_JobLevel;
    		deletearray @job_opt, getarraysize(@job_opt);
    		if(Class < 7 || Class == 4046 || (Class > 4023 && Class < 4030) || (Class > 4001 && Class < 4008))
    		{
    			if(lastJob != 0)
    			{
    				set @target_job, lastJob + 4001;
    			}
    			else
    			{
    				switch(Class)
    					{
    						case 4002: case 4024: case 1:
    							set @job_opt[0],  7;
    							set @job_opt[1], 14;
    							break;
    						case 4003: case 4025: case 2:
    							set @job_opt[0],  9;
    							set @job_opt[1], 16;
    							break;
    						case 4004: case 4026: case 3:
    							set @job_opt[0], 11;
    							if(Sex == 0)
    								set @job_opt[1], 20;
    							else
    								set @job_opt[1], 19;
    							break;
    						case 4005: case 4027: case 4:
    							set @job_opt[0], 8;
    							set @job_opt[1], 15;
    							break;
    						case 4006: case 4028: case 5:
    							set @job_opt[0], 10;
    							set @job_opt[1], 18;
    							break;
    						case 4007: case 4029: case 6:
    							set @job_opt[0], 12;
    							set @job_opt[1], 17;
    							break;						
    						default:
    							set @job_opt[0], 4047;
    							set @job_opt[1], 4049;
    							break;
    					}
    
    					mes "Hello there! you may select the job you want to change into";
    					set @target_job, @job_opt[select(JobName(@job_opt[0]), JobName(@job_opt[1]))-1];
    					if(Class > 4001 && Class < 4008) set @target_job, @target_job + 4001;
    			}
    
    				mes "Are you sure you want to change to " + JobName(@target_job) + "?";
    				if(select("No","Yes")==2)
    				{
    					callfunc "Job_Change", @target_job;
    					if(@target_job == 4047 || @target_job == 4049)
    					{
    						callfunc "F_ClearJobVar";
    					}
    					else
    					{
    						if($@Platinum_Skill) goto Obtain_Platinum;
    					}
    				}
    				close;
    		}
    			if(checkfalcon() || checkcart() || checkriding()) goto Riding;
    			if((Class >=7) && (Class <=142))
    			{
    				mes "Do you want to reborn?";
    				if(select("Yes","No")==1)
    				{
    					if(BaseLevel < 99 || JobLevel < 50) goto Requirements;
    					set lastJob, Class;
    					if(Class == 72)
    					{
    						set lastJob, 7;
    					}
    					else
    					{
    						if(Class == 142)
    						{
    							set lastJob, 14;
    						}
    					}
    					jobchange 4001; resetlvl(1);
    					skill 142,1,0;  skill 143,1,0;
    				}
    				close;
    			}
    	}
    	mes "You've already reached the maximum class for your job";
    close;
    
    Third_Job:
    			if(checkfalcon() || checkcart() || checkriding()) goto Riding;
    	mes "Are you sure you want to change to 3rd Class?";
    			if(select("Yes","No")==1)
    				{
    				if(BaseLevel < 99 || JobLevel < 50) goto Requirements;
    					switch(Class)
    					{
    						case 4008: set @target_job, 4060; break;
    						case 4009: set @target_job, 4063; break;
    						case 4010: set @target_job, 4061; break;
    						case 4011: set @target_job, 4064; break;
    						case 4012: set @target_job, 4062; break;
    						case 4013: set @target_job, 4065; break;
    						case 4015: set @target_job, 4073; break;
    						case 4016: set @target_job, 4077; break;
    						case 4017: set @target_job, 4074; break;
    						case 4018: set @target_job, 4079; break;
    						case 4019: set @target_job, 4078; break;
    						case 4020: set @target_job, 4075; break;
    						case 4021: set @target_job, 4076; break;
    					}
    	mes "Are you sure you want to change to " + JobName(@target_job) + "?";
    			if(select("No","Yes") == 2)
    				{
    				callfunc "Job_Change", @target_job;
    				//atcommand "@blvl +99";
    				specialeffect2 381;
    				close;
    				}
    }
    close;
    
    Obtain_Platinum:
    	if (BaseClass==23) goto Platinum_SuperNovice; if (BaseClass==1)  goto Platinum_Swordsman;
    	if (BaseClass==2)  goto Platinum_Magician;    if (BaseClass==3)  goto Platinum_Archer;
    	if (BaseClass==4)  goto Platinum_Acolyte;     if (BaseClass==5)  goto Platinum_Merchant;
    	if (BaseClass==6)  goto Platinum_Thief;
    	close;
    Platinum_SuperNovice: skill 142,1,0; close;
    Platinum_Swordsman:   skill 142,1,0; skill 144,1,0; skill 145,1,0; skill 146,1,0; close;
    Platinum_Magician:    skill 142,1,0; skill 157,1,0; close;
    Platinum_Archer:      skill 142,1,0; skill 147,1,0; skill 148,1,0; close;
    Platinum_Acolyte:     skill 142,1,0; skill 156,1,0; close;
    Platinum_Merchant:    skill 142,1,0; skill 153,1,0; skill 154,1,0; skill 155,1,0; close;
    Platinum_Thief:       skill 142,1,0; skill 149,1,0; skill 150,1,0; skill 151,1,0; skill 152,1,0; close;
    
    Riding:
    	mes "Please remove your cart,falcon or peco";
    	mes "Please come again soon!";
    	close;
    
    Low_BaseLevel:
    	mes "I'm sorry, you do not seem to have enough Base Levels";
    	mes "Please come again soon!";
    	close;
    
    Low_JobLevel:
    	mes "I'm sorry, you do not seem to have enough Job Levels";
    	mes "Please come again soon!";
    	close;
    
    Requirements:
    	mes "I'm sorry, you do not meet the requirements to change";
    	mes "Please come again soon!";
    	close;
    
    Max:
    	mes "I'm sorry, there are no further classes for your job.";
    	close;
    
    OnInit:
    		// Settings
    		set $@Min_JobLevel,  40; //Minimum job level requirement for changing.
    		set $@Platinum_Skill, 1; //Give Platinum skills on Jobchange.
    		set $@Super_Novice,  45; //Minimum Base Level to change into Super Novice.
    		end;
    }
    
    prontera,161,195,3	duplicate(Job Changer)	Job Changer#prt	430
    payon,148,230,6	duplicate(Job Changer)	Job Changer#pay	430
    rachel,135,115,3	duplicate(Job Changer)	Job Changer#rac	430
    
    
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.