Jump to content

keitenai

Members
  • Content Count

    15
  • Joined

  • Last visited

  • Days Won

    1

keitenai last won the day on March 8 2023

keitenai had the most liked content!

About keitenai

  • Rank
    Member

Contact Methods

  • Website URL
    http://ragnaworld.net/

Profile Information

  • Gender
    Not Telling
  • Github
    keitenai
  • Emulator
    3CeAM

Recent Profile Visitors

2230 profile views
  1. http://herc.ws/board/topic/12442-nydhoggur-dun-fix/?p=72232
  2. As i mentioned in 3ceam facebook group, that nydhoggur dun quest is bugged. Here's a script to fix the issue. quests_13_2.txt
  3. keitenai

    @security system

    i got it from his github https://github.com/zephyrus-cr/eamod it's open to public so i assume the rights for the code has already expired.
  4. keitenai

    @security system

    removed patch as pointed out of having no permission to redistribute
  5. 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;
  6. Here's MVP tomb stone patch that i made compatible with 3ceam V1 : 3CEAM_MVPTOMB.patch 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!
  7. @@15peaces, Thanks for informing me. i was not aware that about the ammo-fix. i've updated the patch
  8. Update: added a optional script version where it requires and item to use the NPC
  9. Request granted. I've updated my post. http://herc.ws/board/topic/12181-costume-converter/?p=70935
  10. Here you go http://herc.ws/board/topic/12200-prize-giver-npc/
  11. keitenai

    Prize Giver NPC

    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)+""); } }
  12. Revert the changes from the first patch before applying the V2 patch. else you will have double function patches like you have now
  13. 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 3CEAM_COSTUME_CONVERTER.patch 3CEAM_COSTUME_CONVERTER_V2.patch costume_v2.txt
  14. Sweeeeeeet! this is awesome Rytech. thanks!!
  15. keitenai

    3E Jobchanger

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