// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL. // Copyright (c) 2014 - 2015 Evol developers #include "common/hercules.h" #include #include #include #include #include #include "common/HPMi.h" #include "common/memmgr.h" #include "common/utils.h" #include "common/timer.h" #include "common/random.h" #include "map/achievement.h" #include "map/atcommand.h" #include "map/battle.h" #include "map/battleground.h" #include "map/chat.h" #include "map/chrif.h" #include "map/guild.h" #include "map/homunculus.h" #include "map/instance.h" #ifdef PYTHON_LOGS #include "map/log.h" #endif #include "map/mapreg.h" #include "map/mob.h" #include "map/npc.h" #include "map/pc.h" #include "map/quest.h" #include "map/refine.h" #include "map/script.h" #include "map/skill.h" #include "map/map.h" #include "emap/clif.h" #include "emap/craft.h" #include "emap/craftconf.h" #include "emap/lang.h" #include "emap/map.h" #include "emap/hashtable.h" #include "emap/scriptdefines.h" #include "emap/send.h" #include "emap/data/bgd.h" #include "emap/data/mapd.h" #include "emap/data/session.h" #include "emap/struct/bgdext.h" #include "emap/struct/mapdext.h" #include "emap/struct/sessionext.h" #include "emap/utils/formatutils.h" extern int mountScriptId; extern char global_npc_str[1001]; uint32 MakeDWord(uint16 word0, uint16 word1) { return ((uint32)(word0)) | ((uint32)(word1 << 0x10)); } BUILDIN(l) { format_sub(st, 1); return true; } BUILDIN(lg) { format_sub(st, 2); return true; } BUILDIN(setCamNpc) { getSD(); TBL_NPC *nd = NULL; int x = 0; int y = 0; if (script_hasdata(st, 2)) { nd = npc->name2id (script_getstr(st, 2)); } else { if (!st->oid) { ShowWarning("npc not attached\n"); script->reportsrc(st); return false; } nd = map->id2nd(st->oid); } if (!nd) { ShowWarning("npc not found\n"); script->reportsrc(st); return false; } if (sd->bl.m != nd->bl.m) { ShowWarning("npc and player located in other maps\n"); script->reportsrc(st); return false; } if (script_hasdata(st, 3) && script_hasdata(st, 4)) { x = script_getnum(st, 3); y = script_getnum(st, 4); } send_npccommand2(sd, st->oid, 2, nd->bl.id, x, y); return true; } BUILDIN(setCam) { send_npccommand2(script->rid2sd (st), st->oid, 2, 0, script_getnum(st, 2), script_getnum(st, 3)); return true; } BUILDIN(moveCam) { send_npccommand2(script->rid2sd (st), st->oid, 4, 0, script_getnum(st, 2), script_getnum(st, 3)); return true; } BUILDIN(restoreCam) { getSD(); send_npccommand(sd, st->oid, 3); return true; } BUILDIN(npcTalk3) { const char *msg; getSD(); TBL_NPC *nd = map->id2nd(st->oid); const char *str = script_getstr(st, 2); if (!nd) { ShowWarning("npc not found\n"); script->reportsrc(st); return false; } if (!str) { ShowWarning("error in string\n"); script->reportsrc(st); return false; } if (sd) msg = lang_pctrans (nd->name, sd); else msg = nd->name; if (!msg) { ShowWarning("error in string\n"); script->reportsrc(st); return false; } if (strlen(str) + strlen(msg) > 450) { ShowWarning("text message too big\n"); script->reportsrc(st); return false; } if (nd) { char message[500]; char name[500]; strcpy (name, msg); strtok(name, "#"); strcpy (message, name); strcat (message, " : "); strcat (message, str); send_local_message (sd->fd, &(nd->bl), message); } return true; } BUILDIN(closeDialog) { getSD(); //send_npccommand(sd, st->oid, 5); send_npccommand(sd, st->oid, 14); return true; } BUILDIN(closeClientDialog) { getSD(); send_npccommand(sd, st->oid, 14); return true; } // npcshopattach(npc) will tell the scripts to run an event // Enabling OnBuyItem and OnSellItem events of npc BUILDIN(npcshopattach) { const char* npcname = script_getstr(st,2); struct npc_data* nd = npc->name2id(npcname); int flag = 1; if( script_hasdata(st,3) ) flag = script_getnum(st,3); if( !nd ) { //Not found. script_pushint(st,0); return true; } if (flag) nd->master_nd = map->id2nd(st->oid); else nd->master_nd = NULL; script_pushint(st,1); return true; } BUILDIN(shop) { getSD(); TBL_NPC *nd = npc->name2id (script_getstr(st, 2)); if (!nd) { ShowWarning("shop npc not found\n"); script->reportsrc(st); return false; } // TMW2 Shops /* Move this to a new function, and comment the autoclose Skip the forced check of SHOP type because I don't like it. st->state = sd->state.dialog == 1 ? CLOSE : END; clif->scriptclose(sd, st->oid); */ clif->npcbuysell (sd, nd->bl.id); return true; } #define paramToItem(param) \ if (script_isstringtype(st, param)) \ { \ i_data = itemdb->search_name (script_getstr(st, param)); \ } \ else \ { \ item_id = script_getnum (st, param); \ if (item_id) \ i_data = itemdb->search (item_id); \ } BUILDIN(getItemLink) { struct item_data *i_data = NULL; char *item_name; int item_id = 0; paramToItem(2); item_name = (char *) aCalloc (1000, sizeof (char)); TBL_PC *sd = script->rid2sd(st); if (sd) { if (i_data) { if (!script_hasdata(st, 3)) { sprintf(item_name, "[@@%u|@@]", (unsigned)i_data->nameid); } else { sprintf(item_name, "[@@%u", (unsigned)i_data->nameid); int f; for (f = 3; f < 7 && script_hasdata(st, f); f ++) { paramToItem(f); if (i_data) { char buf[100]; sprintf(buf, ",%u", (unsigned)i_data->nameid); strcat(item_name, buf); } } strcat(item_name, "|@@]"); } } else if (item_id > 0) { sprintf(item_name, "[@@%u|Unknown Item@@]", (unsigned)item_id); } else { sprintf(item_name, "[Unknown Item]"); } } else { if (i_data) sprintf(item_name, "[%s]", i_data->jname); else sprintf(item_name, "[Unknown Item]"); } script_pushstr(st, item_name); return true; } #undef paramToItem BUILDIN(requestLang) { getSDReturn(-1); if (!sd->state.menu_or_input) { // first invocation, display npc input box sd->state.menu_or_input = 1; st->state = RERUNLINE; // send lang request send_npccommand(sd, st->oid, 0); clif->scriptinputstr(sd, st->oid); } else { // take received text/value and store it in the designated variable sd->state.menu_or_input = 0; int lng = -1; if (*global_npc_str) lng = lang_getId(global_npc_str); script_pushint(st, lng); st->state = RUN; } return true; } BUILDIN(requestItem) { getSDReturn(0); if (!sd->state.menu_or_input) { // first invocation, display npc input box sd->state.menu_or_input = 1; st->state = RERUNLINE; // send item request send_npccommand(sd, st->oid, 10); } else { // take received text/value and store it in the designated variable sd->state.menu_or_input = 0; st->state = RUN; int item = 0; if (!*global_npc_str) { ShowWarning("npc string not found\n"); script_pushint(st, 0); script->reportsrc(st); return false; } if (sscanf (global_npc_str, "%5d", &item) < 1) { ShowWarning("input data is not item id\n"); script_pushint(st, 0); script->reportsrc(st); return false; } script_pushint(st, item); } return true; } BUILDIN(requestItems) { getSDReturnS("0,0"); int count = 1; if (script_hasdata(st, 2)) { count = script_getnum(st, 2); if (count < 0) count = 1; } if (!sd->state.menu_or_input) { // first invocation, display npc input box sd->state.menu_or_input = 1; st->state = RERUNLINE; // send item request with limit count send_npccommand2(sd, st->oid, 10, count, 0, 0); } else { // take received text/value and store it in the designated variable sd->state.menu_or_input = 0; st->state = RUN; if (!*global_npc_str) { ShowWarning("npc string not found\n"); script_pushstr(st, aStrdup("0,0")); script->reportsrc(st); return false; } script_pushstr(st, aStrdup(global_npc_str)); } return true; } BUILDIN(requestItemIndex) { getSessionDataReturn(client, -1); if (!sd->state.menu_or_input) { // first invocation, display npc input box sd->state.menu_or_input = 1; st->state = RERUNLINE; // send item request if (client) send_npccommand(sd, st->oid, 11); } else { // take received text/value and store it in the designated variable sd->state.menu_or_input = 0; st->state = RUN; int item = -1; if (!*global_npc_str) { script_pushint(st, -1); ShowWarning("npc string not found\n"); script->reportsrc(st); return false; } if (sscanf (global_npc_str, "%5d", &item) < 1) { script_pushint(st, -1); ShowWarning("input data is not item id\n"); script->reportsrc(st); return false; } script_pushint(st, item); } return true; } BUILDIN(requestItemsIndex) { getSessionDataReturnS(client, "-1"); int count = 1; if (script_hasdata(st, 2)) { count = script_getnum(st, 2); if (count < 0) count = 1; } if (!sd->state.menu_or_input) { // first invocation, display npc input box sd->state.menu_or_input = 1; st->state = RERUNLINE; // send item request with limit count if (client) send_npccommand2(sd, st->oid, 11, count, 0, 0); } else { // take received text/value and store it in the designated variable sd->state.menu_or_input = 0; st->state = RUN; if (!*global_npc_str) { script_pushstr(st, aStrdup("-1")); ShowWarning("npc string not found\n"); script->reportsrc(st); return false; } script_pushstr(st, aStrdup(global_npc_str)); } return true; } BUILDIN(requestCraft) { getSessionData(client); int count = 1; if (script_hasdata(st, 2)) { count = script_getnum(st, 2); if (count < 0) count = 1; } if (!sd->state.menu_or_input) { // first invocation, display npc input box sd->state.menu_or_input = 1; st->state = RERUNLINE; // send item request with limit count if (client) send_npccommand2(sd, st->oid, 12, count, 0, 0); } else { // take received text/value and store it in the designated variable sd->state.menu_or_input = 0; st->state = RUN; if (!*global_npc_str) { ShowWarning("npc string not found\n"); script->reportsrc(st); script_pushstr(st, aStrdup("")); return false; } script_pushstr(st, aStrdup(global_npc_str)); } return true; } BUILDIN(setq) { int i; getSD(); int quest_id = script_getnum(st, 2); if (quest->check(sd, quest_id, HAVEQUEST) < 0) quest->add(sd, quest_id, 0); ARR_FIND(0, sd->num_quests, i, sd->quest_log[i].quest_id == quest_id); if (i == sd->num_quests) { ShowError("Quest with id=%d not found\n", quest_id); script->reportsrc(st); return false; } sd->quest_log[i].count[0] = script_getnum(st, 3); if (script_hasdata(st, 4)) sd->quest_log[i].count[1] = script_getnum(st, 4); if (script_hasdata(st, 5)) sd->quest_log[i].count[2] = script_getnum(st, 5); if (script_hasdata(st, 6)) sd->quest_log[i].time = script_getnum(st, 6); sd->save_quest = true; if (map->save_settings & 64) chrif->save(sd,0); eclif_quest_add(sd, &sd->quest_log[i]); return true; } BUILDIN(getq) { int i; getSDReturn(0); int quest_id = script_getnum(st, 2); if (quest->check(sd, quest_id, HAVEQUEST) < 0) { script_pushint(st, 0); return true; } ARR_FIND(0, sd->num_quests, i, sd->quest_log[i].quest_id == quest_id); if (i == sd->num_quests) { script_pushint(st, 0); return true; } script_pushint(st, sd->quest_log[i].count[0]); return true; } BUILDIN(getq2) { int i; getSDReturn(0); int quest_id = script_getnum(st, 2); if (quest->check(sd, quest_id, HAVEQUEST) < 0) { script_pushint(st, 0); return true; } ARR_FIND(0, sd->num_quests, i, sd->quest_log[i].quest_id == quest_id); if (i == sd->num_quests) { script_pushint(st, 0); return true; } script_pushint(st, sd->quest_log[i].count[1]); return true; } BUILDIN(getq3) { int i; getSDReturn(0); int quest_id = script_getnum(st, 2); if (quest->check(sd, quest_id, HAVEQUEST) < 0) { script_pushint(st, 0); return true; } ARR_FIND(0, sd->num_quests, i, sd->quest_log[i].quest_id == quest_id); if (i == sd->num_quests) { script_pushint(st, 0); return true; } script_pushint(st, sd->quest_log[i].count[2]); return true; } BUILDIN(getqTime) { int i; getSDReturn(0); int quest_id = script_getnum(st, 2); if (quest->check(sd, quest_id, HAVEQUEST) < 0) { script_pushint(st, 0); return true; } ARR_FIND(0, sd->num_quests, i, sd->quest_log[i].quest_id == quest_id); if (i == sd->num_quests) { script_pushint(st, 0); return true; } script_pushint(st, sd->quest_log[i].time); return true; } BUILDIN(setNpcDir) { int newdir; TBL_NPC *nd = 0; if (script_hasdata(st, 3)) { nd = npc->name2id (script_getstr(st, 2)); newdir = script_getnum(st, 3); } else if (script_hasdata(st, 2)) { if (!st->oid) { ShowWarning("npc not found\n"); script->reportsrc(st); return false; } nd = map->id2nd(st->oid); newdir = script_getnum(st, 2); } if (!nd) { ShowWarning("npc not found\n"); script->reportsrc(st); return false; } if (newdir < 0) newdir = 0; else if (newdir > 7) newdir = 7; nd->dir = newdir; npc->enable(nd->exname, 1); return true; } BUILDIN(rif) { const char *str = 0; if (script_getnum(st, 2)) { str = script_getstr(st, 3); if (str) script_pushstr(st, aStrdup(str)); else script_pushconststr(st, (char *)""); } else if (script_hasdata(st, 4)) { str = script_getstr(st, 4); if (str) script_pushstr(st, aStrdup(str)); else script_pushconststr(st, (char *)""); } else { script_pushconststr(st, (char *)""); } return true; } BUILDIN(setMapMask) { const char *const mapName = script_getstr(st, 2); if (!mapName) { ShowWarning("invalid map name\n"); script->reportsrc(st); return false; } const int m = map->mapname2mapid(mapName); if (m < 0) { ShowWarning("map not found\n"); script->reportsrc(st); return false; } getMapData(m); const int val = script_getnum(st, 3); const unsigned int old = mapData->mask; mapData->mask = val; if (old != mapData->mask) send_mapmask_brodcast(m, mapData->mask); return true; } // sendMapMask(mask{, "player name"}) BUILDIN(sendMapMask) { const int val = script_getnum(st, 2); struct map_session_data *sd = NULL; if (script_hasdata(st, 3) && script_isstringtype(st, 3)) { sd = script->nick2sd(st, script_getstr(st, 3)); } else { sd = script->rid2sd(st); } if (sd == NULL) { ShowWarning("player not attached\n"); script->reportsrc(st); return false; } send_mapmask(sd->fd, val); return true; } BUILDIN(getMapMask) { const char *const mapName = script_getstr(st, 2); if (!mapName) { script_pushint(st, 0); ShowWarning("invalid map name\n"); script->reportsrc(st); return false; } const int m = map->mapname2mapid(mapName); if (m < 0) { script_pushint(st, 0); ShowWarning("map not found\n"); script->reportsrc(st); return false; } getMapDataReturn(m, 0); script_pushint(st, mapData->mask); return true; } BUILDIN(addMapMask) { const char *const mapName = script_getstr(st, 2); if (!mapName) { ShowWarning("invalid map name\n"); script->reportsrc(st); return false; } const int m = map->mapname2mapid(mapName); if (m < 0) { ShowWarning("map not found\n"); script->reportsrc(st); return false; } getMapData(m); const int val = script_getnum(st, 3); const unsigned int old = mapData->mask; mapData->mask |= val; if (old != mapData->mask) send_mapmask_brodcast(m, mapData->mask); return true; } BUILDIN(removeMapMask) { const char *const mapName = script_getstr(st, 2); if (!mapName) { ShowWarning("invalid map name\n"); script->reportsrc(st); return true; } const int m = map->mapname2mapid(mapName); if (m < 0) { ShowWarning("map not found\n"); script->reportsrc(st); return false; } getMapData(m); const int val = script_getnum(st, 3); const unsigned int old = mapData->mask; mapData->mask |= val; mapData->mask ^= val; if (old != mapData->mask) send_mapmask_brodcast(m, mapData->mask); return true; } BUILDIN(setNpcSex) { TBL_NPC *nd = NULL; int sex = 0; if (script_hasdata(st, 3)) { nd = npc->name2id (script_getstr(st, 2)); sex = script_getnum(st, 3); } if (!nd) { ShowWarning("npc not found\n"); script->reportsrc(st); return false; } clif->clearunit_area(&nd->bl, CLR_OUTSIGHT); nd->vd.sex = sex; clif->spawn(&nd->bl); return true; } BUILDIN(showAvatar) { int id = 0; if (script_hasdata(st, 2)) id = script_getnum(st, 2); send_npccommand2(script->rid2sd (st), st->oid, 6, id, 0, 0); return true; } BUILDIN(setAvatarDir) { int newdir = script_getnum(st, 2); if (newdir < 0) newdir = 0; else if (newdir > 7) newdir = 7; send_npccommand2(script->rid2sd (st), st->oid, 7, newdir, 0, 0); return true; } BUILDIN(setAvatarAction) { send_npccommand2(script->rid2sd (st), st->oid, 8, script_getnum(st, 2), 0, 0); return true; } BUILDIN(clear) { send_npccommand(script->rid2sd (st), st->oid, 9); return true; } BUILDIN(changeMusic) { const char *const mapName = script_getstr(st, 2); const char *const music = script_getstr(st, 3); if (!music) { ShowWarning("invalid music file\n"); script->reportsrc(st); return false; } if (!mapName) { ShowWarning("invalid map file\n"); script->reportsrc(st); return false; } const int m = map->mapname2mapid(mapName); if (m < 0) { ShowWarning("map not found\n"); script->reportsrc(st); return false; } send_changemusic_brodcast(m, music); return true; } // changePlayerMusic(music) BUILDIN(changePlayerMusic) { const char *const music = script_getstr(st, 2); //ShowWarning("ChangePlayerMusic called\n"); if (!music) { ShowWarning("invalid music file\n"); script->reportsrc(st); return false; } //ShowWarning("Music defined as %s\n", (char*)(music)); struct map_session_data *sd = NULL; sd = script->rid2sd(st); if (sd == NULL) { ShowWarning("player not attached\n"); script->reportsrc(st); return false; } //ShowWarning("Sending data\n"); send_changemusic(sd->fd, music); return true; } BUILDIN(setNpcDialogTitle) { const char *const name = script_getstr(st, 2); if (!name) { ShowWarning("invalid window title\n"); script->reportsrc(st); return false; } TBL_PC *sd = script->rid2sd (st); if (!sd) { ShowWarning("player not attached\n"); script->reportsrc(st); return false; } send_changenpc_title(sd, st->oid, name); return true; } BUILDIN(getMapName) { TBL_PC *sd = script->rid2sd(st); if (!sd) { script_pushstr(st, aStrdup("")); ShowWarning("player not attached\n"); script->reportsrc(st); return false; } if (sd->bl.m == -1) { script_pushstr(st, aStrdup("")); ShowWarning("invalid map\n"); script->reportsrc(st); return false; } script_pushstr(st, aStrdup(map->list[sd->bl.m].name)); return true; } BUILDIN(unequipById) { int nameid = 0; int i; struct item_data *item_data; TBL_PC *sd = script->rid2sd(st); if (sd == NULL) { ShowWarning("player not attached\n"); script->reportsrc(st); return false; } nameid = script_getnum(st, 2); if((item_data = itemdb->exists(nameid)) == NULL) { ShowWarning("item %d not found\n", nameid); script->reportsrc(st); return false; } for (i = 0; i < EQI_MAX; i++) { const int idx = sd->equip_index[i]; if (idx >= 0) { if (sd->status.inventory[idx].nameid == nameid) pc->unequipitem(sd, idx, 1 | 2); } } return true; } BUILDIN(isPcDead) { TBL_PC *sd; if (script_hasdata(st, 2)) { if (script_isstringtype(st, 2)) sd = script->nick2sd(st, script_getstr(st, 2)); else sd = map->id2sd(script_getnum(st, 2)); } else { sd = script->rid2sd(st); } if (sd == NULL) { ShowWarning("player not attached\n"); script->reportsrc(st); return false; } script_pushint(st, pc_isdead(sd) ? 1 : 0); return true; } static int buildin_getareadropitem_sub_del(struct block_list *bl, va_list ap) { if (!bl) return 0; const int item = va_arg(ap, int); int *const amount = va_arg(ap, int *); TBL_ITEM *drop = (TBL_ITEM *)bl; if (drop->item_data.nameid == item) { (*amount) += drop->item_data.amount; map->clearflooritem(&drop->bl); } return 0; } BUILDIN(getAreaDropItem) { const char *const str = script_getstr(st, 2); int16 m; int x0 = script_getnum(st, 3); int y0 = script_getnum(st, 4); int x1 = script_getnum(st, 5); int y1 = script_getnum(st, 6); int item; int amount = 0; if (script_isstringtype(st, 7)) { const char *name = script_getstr(st, 7); struct item_data *item_data = itemdb->search_name(name); item = UNKNOWN_ITEM_ID; if (item_data) item = item_data->nameid; } else { item = script_getnum(st, 7); } if ((m = map->mapname2mapid(str)) < 0) { script_pushint(st, -1); ShowWarning("map not found\n"); script->reportsrc(st); return false; } if (script_hasdata(st, 8) && script_getnum(st, 8)) { map->foreachinarea(buildin_getareadropitem_sub_del, m, x0, y0, x1, y1, BL_ITEM, item, &amount); } else { map->foreachinarea(script->buildin_getareadropitem_sub, m, x0, y0, x1, y1, BL_ITEM, item, &amount); } script_pushint(st, amount); return true; } BUILDIN(clientCommand) { getSD(); const char *const command = script_getstr(st, 2); if (!command) { ShowWarning("invalid client command\n"); script->reportsrc(st); return false; } send_client_command(sd, command); return true; } BUILDIN(isUnitWalking) { int id = 0; if (script_hasdata(st, 2)) id = script_getnum(st, 2); else id = st->oid; struct block_list *bl = map->id2bl(id); if (!bl) { ShowWarning("invalid unit id\n"); script->reportsrc(st); script_pushint(st, 0); return false; } struct unit_data *ud = unit->bl2ud(bl); if (!ud) { ShowWarning("invalid unit data\n"); script->reportsrc(st); script_pushint(st, 0); return false; } script_pushint(st, ud->walktimer != INVALID_TIMER); return true; } BUILDIN(failedRefIndex) { getSD() getInventoryIndex(2) if (sd->status.inventory[n].nameid <= 0 || sd->status.inventory[n].amount <= 0) return false; // Call before changing refine to 0. achievement->validate_refine(sd, n, false); sd->status.inventory[n].refine = 0; if (sd->status.inventory[n].equip) pc->unequipitem(sd, n, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE); clif->refine(sd->fd, 1, n, sd->status.inventory[n].refine); pc->delitem(sd, n, 1, 0, DELITEM_FAILREFINE, LOG_TYPE_SCRIPT); clif->misceffect(&sd->bl, 2); return true; } BUILDIN(downRefIndex) { getSD() getInventoryIndex(2) if (sd->status.inventory[n].nameid <= 0 || sd->status.inventory[n].amount <= 0) return false; const int down = script_getnum(st, 3); logs->pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->status.inventory[n], sd->inventory_data[n]); if (sd->status.inventory[n].equip) pc->unequipitem(sd, n, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE); sd->status.inventory[n].refine -= down; sd->status.inventory[n].refine = cap_value(sd->status.inventory[n].refine, 0, MAX_REFINE); clif->refine(sd->fd, 2, n, sd->status.inventory[n].refine); clif->delitem(sd, n, 1, DELITEM_MATERIALCHANGE); logs->pick_pc(sd, LOG_TYPE_SCRIPT, 1, &sd->status.inventory[n], sd->inventory_data[n]); clif->additem(sd, n, 1, 0); achievement->validate_refine(sd, n, false); // Achievements [Smokexyz/Hercules] clif->misceffect(&sd->bl, 2); return true; } BUILDIN(successRefIndex) { getSD() getInventoryIndex(2) if (sd->status.inventory[n].nameid <= 0 || sd->status.inventory[n].amount <= 0) return false; const int up = script_getnum(st, 3); logs->pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->status.inventory[n],sd->inventory_data[n]); if (sd->status.inventory[n].refine >= MAX_REFINE) return true; sd->status.inventory[n].refine += up; sd->status.inventory[n].refine = cap_value( sd->status.inventory[n].refine, 0, MAX_REFINE); if (sd->status.inventory[n].equip) pc->unequipitem(sd, n, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE); clif->refine(sd->fd, 0, n, sd->status.inventory[n].refine); clif->delitem(sd, n, 1, DELITEM_MATERIALCHANGE); logs->pick_pc(sd, LOG_TYPE_SCRIPT, 1, &sd->status.inventory[n],sd->inventory_data[n]); clif->additem(sd, n, 1, 0); clif->misceffect(&sd->bl, 3); achievement->validate_refine(sd, n, true); // Achievements [Smokexyz/Hercules] if (sd->status.inventory[n].refine == 10 && sd->status.inventory[n].card[0] == CARD0_FORGE && sd->status.char_id == (int)MakeDWord(sd->status.inventory[n].card[2], sd->status.inventory[n].card[3])) { // Fame point system [DracoRPG] switch (sd->inventory_data[n]->wlv) { case 1: pc->addfame(sd, RANKTYPE_BLACKSMITH, 1); // Success to refine to +10 a lv1 weapon you forged = +1 fame point break; case 2: pc->addfame(sd, RANKTYPE_BLACKSMITH, 25); // Success to refine to +10 a lv2 weapon you forged = +25 fame point break; case 3: pc->addfame(sd, RANKTYPE_BLACKSMITH, 1000); // Success to refine to +10 a lv3 weapon you forged = +1000 fame point break; } } return true; } BUILDIN(successRemoveCardsIndex) { int i = -1, c, cardflag = 0; getSD() getInventoryIndex(2) if (sd->status.inventory[n].nameid <= 0 || sd->status.inventory[n].amount <= 0) return false; i = n; if (itemdb_isspecial(sd->status.inventory[i].card[0])) return true; for (c = sd->inventory_data[i]->slot - 1; c >= 0; --c) { if (sd->status.inventory[i].card[c] && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD) { // extract this card from the item int flag; struct item item_tmp; memset(&item_tmp, 0, sizeof(item_tmp)); cardflag = 1; item_tmp.nameid = sd->status.inventory[i].card[c]; item_tmp.identify = 1; sd->status.inventory[i].card[c] = 0; if ((flag = pc->additem(sd, &item_tmp, 1, LOG_TYPE_SCRIPT))) { // get back the cart in inventory clif->additem(sd, 0, 0, flag); map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0, false); } } } if (cardflag == 1) { pc->unequipitem(sd, i, PCUNEQUIPITEM_FORCE); clif->delitem(sd, i, 1, DELITEM_MATERIALCHANGE); clif->additem(sd, i, 1, 0); pc->equipitem(sd, i, sd->status.inventory[i].equip); clif->misceffect(&sd->bl,3); } return true; } /// =0 : will destroy both the item and the cards. /// =1 : will keep the item, but destroy the cards. /// =2 : will keep the cards, but destroy the item. /// =? : will just display the failure effect. BUILDIN(failedRemoveCardsIndex) { int i = -1, c, cardflag = 0; getSD() getInventoryIndex(2) if (sd->status.inventory[n].nameid <= 0 || sd->status.inventory[n].amount <= 0) return false; i = n; int typefail = script_getnum(st, 3); if (itemdb_isspecial(sd->status.inventory[i].card[0])) return true; for (c = sd->inventory_data[i]->slot - 1; c >= 0; --c) { if (sd->status.inventory[i].card[c] && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD) { cardflag = 1; if (typefail == 1) sd->status.inventory[i].card[c] = 0; if (typefail == 2) { // add cards to inventory, clear int flag; struct item item_tmp; memset(&item_tmp, 0, sizeof(item_tmp)); item_tmp.nameid = sd->status.inventory[i].card[c]; item_tmp.identify = 1; if ((flag = pc->additem(sd, &item_tmp, 1, LOG_TYPE_SCRIPT))) { clif->additem(sd, 0, 0, flag); map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0, false); } } } } if (cardflag == 1) { if (typefail == 0 || typefail == 2) { // destroy the item pc->delitem(sd, i, 1, 0, DELITEM_FAILREFINE, LOG_TYPE_SCRIPT); } else if (typefail == 1) { pc->unequipitem(sd, i, PCUNEQUIPITEM_FORCE); clif->delitem(sd, i, 1, DELITEM_MATERIALCHANGE); clif->additem(sd, i, 1, 0); pc->equipitem(sd, i, sd->status.inventory[i].equip); } clif->misceffect(&sd->bl, 2); } return true; } BUILDIN(getCardByIndex) { getSD() getInventoryIndex(2) if (sd->status.inventory[n].nameid <= 0 || sd->status.inventory[n].amount <= 0) { script_pushint(st, 0); return false; } const int c = script_getnum(st, 3); if (c < 0 || c >= MAX_SLOTS) { script_pushint(st, 0); return false; } if (itemdb_isspecial(sd->status.inventory[n].card[0])) { script_pushint(st, 0); return true; } const int card = sd->status.inventory[n].card[c]; if (card && itemdb_type(card) == IT_CARD) { script_pushint(st, card); } else { script_pushint(st, 0); } return true; } BUILDIN(removeCardByIndex) { getSD() getInventoryIndex(2) if (sd->status.inventory[n].nameid <= 0 || sd->status.inventory[n].amount <= 0) { ShowWarning("zero amount\n"); script_pushint(st, -1); return false; } if (sd->status.inventory[n].equip) { ShowWarning("item equipped\n"); script_pushint(st, -1); return false; } const int c = script_getnum(st, 3); if (c < 0 || c >= MAX_SLOTS) { ShowWarning("wrong slot id\n"); script_pushint(st, -1); return false; } const int amount = sd->status.inventory[n].amount; clif->delitem(sd, n, amount, DELITEM_FAILREFINE); sd->status.inventory[n].card[c] = 0; clif->additem(sd, n, amount, 0); status_calc_pc(sd, SCO_NONE); script_pushint(st, 0); return true; } BUILDIN(npcSit) { TBL_NPC *nd = NULL; if (script_hasdata(st, 2)) { nd = npc->name2id (script_getstr(st, 2)); } else { if (!st->oid) { ShowWarning("npc not attached\n"); script->reportsrc(st); return false; } nd = map->id2nd(st->oid); } if (!nd) { ShowWarning("npc not found\n"); script->reportsrc(st); return false; } nd->vd.dead_sit = 2; clif->sitting(&nd->bl); return true; } BUILDIN(npcStand) { TBL_NPC *nd = NULL; if (script_hasdata(st, 2)) { nd = npc->name2id (script_getstr(st, 2)); } else { if (!st->oid) { ShowWarning("npc not attached\n"); script->reportsrc(st); return false; } nd = map->id2nd(st->oid); } if (!nd) { ShowWarning("npc not found\n"); script->reportsrc(st); return false; } nd->vd.dead_sit = 0; clif->standing(&nd->bl); return true; } BUILDIN(npcWalkTo) { struct npc_data *nd = map->id2nd(st->oid); int x = 0, y = 0; x = script_getnum(st, 2); y = script_getnum(st, 3); if (nd) { unit->bl2ud2(&nd->bl); // ensure nd->ud is safe to edit if (nd->ud == NULL) { ShowWarning("buildin_npcwalkto: floating NPC don't have unit data.\n"); script_pushint(st, 0); return false; } if (!nd->status.hp) { status_calc_npc(nd, SCO_FIRST); } else { status_calc_npc(nd, SCO_NONE); } nd->vd.dead_sit = 0; script_pushint(st, unit->walktoxy(&nd->bl, x, y, 0)); return true; } else { ShowWarning("npc not found\n"); script->reportsrc(st); script_pushint(st, 0); return false; } } BUILDIN(setBgTeam) { int bgId = script_getnum(st, 2); int teamId = script_getnum(st, 3); struct battleground_data *bgd = bg->team_search(bgId); struct BgdExt *data = bgd_get(bgd); if (!data) { ShowWarning("bettle ground not found\n"); script->reportsrc(st); return false; } data->teamId = teamId; return true; } // chatjoin chatId [,char [,password]] BUILDIN(chatJoin) { int chatId = script_getnum(st, 2); TBL_PC *sd = NULL; const char *password = ""; if (script_hasdata(st, 4)) { if (script_isstringtype(st, 3)) sd = map->nick2sd(script_getstr(st, 3), false); if (script_isstringtype(st, 4)) password = script_getstr(st, 4); } else if (script_hasdata(st, 3)) { if (script_isstringtype(st, 3)) sd = map->nick2sd(script_getstr(st, 3), false); } else { sd = script->rid2sd(st); } if (!sd) { ShowWarning("player not found\n"); script->reportsrc(st); return false; } chat->join(sd, chatId, password); return true; } /// Retrieves the value of the specified flag of the specified cell. /// /// checknpccell("",,,) -> /// /// @see cell_chk* constants in const.txt for the types BUILDIN(checkNpcCell) { int16 m = map->mapname2mapid(script_getstr(st, 2)); int16 x = script_getnum(st, 3); int16 y = script_getnum(st, 4); cell_chk type = (cell_chk)script_getnum(st, 5); if (m == -1) { ShowWarning("checknpccell: Attempted to run on unexsitent map '%s', type %u, x/y %d,%d\n", script_getstr(st, 2), type, x, y); return true; } TBL_NPC *nd = map->id2nd(st->oid); struct block_list *bl = NULL; if (nd) bl = &nd->bl; script_pushint(st, map->getcell(m, bl, x, y, type)); return true; } BUILDIN(setCells) { int m; const char *mapname = script_getstr(st, 2); int x1 = script_getnum(st, 3); int y1 = script_getnum(st, 4); int x2 = script_getnum(st, 5); int y2 = script_getnum(st, 6); int mask = script_getnum(st, 7); const char *name = script_getstr(st, 8); if ((m = map->mapname2mapid(mapname)) < 0) return true; // Invalid Map emap_iwall_set2(m, 0, x1, y1, x2, y2, mask, name); return true; } BUILDIN(delCells) { const char *name = script_getstr(st,2); map->iwall_remove(name); return true; } BUILDIN(setMount) { getSD() int mount = script_getnum(st, 2); pc_setglobalreg(sd, mountScriptId, mount); status_calc_pc(sd, SCO_NONE); send_pc_info(&sd->bl, &sd->bl, AREA); send_pc_own_flags(&sd->bl); return true; } BUILDIN(setSkin) { if (!st->oid) return false; getSD() const char *skin = script_getstr(st, 2); send_pc_skin(sd->fd, st->oid, skin); return true; } BUILDIN(initCraft) { getSDReturn(-1) int var = str_to_craftvar(sd, script_getstr(st, 2)); script_pushint(st, var); return true; } BUILDIN(dumpCraft) { getSD() craft_dump(sd, script_getnum(st, 2)); return true; } BUILDIN(deleteCraft) { getSD() craft_delete(script_getnum(st, 2)); return true; } BUILDIN(getCraftSlotId) { getSDReturn(0) const struct craft_slot *crslot = craft_get_slot(script_getnum(st, 2), script_getnum(st, 3)); if (!crslot) return false; const int len = VECTOR_LENGTH(crslot->items); if (len > 0) { struct item_pair *pair = &VECTOR_INDEX(crslot->items, 0); const int invIndex = pair->index; const int item_id = sd->status.inventory[invIndex].nameid; script_pushint(st, item_id); } else { script_pushint(st, 0); } return true; } BUILDIN(getCraftSlotAmount) { getSDReturn(0) const struct craft_slot *crslot = craft_get_slot(script_getnum(st, 2), script_getnum(st, 3)); if (!crslot) return false; const int len = VECTOR_LENGTH(crslot->items); if (len > 0) { int slot; int amount = 0; for (slot = 0; slot < len; slot ++) { struct item_pair *pair = &VECTOR_INDEX(crslot->items, slot); const int invIndex = pair->index; const int item_id = sd->status.inventory[invIndex].nameid; if (item_id > 0) { const int item_amount = sd->status.inventory[invIndex].amount; if (item_amount > 0) amount += pair->amount; } } script_pushint(st, amount); } else { script_pushint(st, 0); } return true; } BUILDIN(validateCraft) { getSDReturn(0) const bool valid = craft_validate(sd, script_getnum(st, 2)); script_pushint(st, valid ? 1 : 0); return true; } BUILDIN(findCraftEntry) { getSDReturn(-1) const int id = craft_find_entry(sd, script_getnum(st, 2), script_getnum(st, 3)); script_pushint(st, id); return true; } BUILDIN(getCraftRecipe) { // arg 0: recipe id // arg 1: inventory id // arg 2: qty array // arg 3: item array // returns size struct script_data *data4 = script_getdata(st, 4); struct script_data *data5 = script_getdata(st, 5); if (!data_isreference(data4) || reference_toconstant(data4) || !data_isreference(data5) || reference_toconstant(data5)) { ShowError("script:getcraftrecipe: 3rd and 4th arguments must be variables\n"); st->state = END; return false; } int recipe_id = script_getnum(st, 2); struct craft_db_entry *entry = idb_get(craftconf_db, recipe_id); if (!entry) { // recipe does not exist script_pushint(st, -1); return true; } int inventory_id = script_getnum(st, 3); int inv_count = VECTOR_LENGTH(entry->inventories); if (inventory_id >= inv_count) { // inventory does not exist script_pushint(st, -2); return true; } struct craft_db_inventory *entry_inventory = &VECTOR_INDEX(entry->inventories, inventory_id); int32 id4 = reference_getid(data4); uint32 start4 = reference_getindex(data4); const char *name4 = reference_getname(data4); struct reg_db *ref4 = reference_getref(data4); int32 id5 = reference_getid(data5); uint32 start5 = reference_getindex(data5); const char *name5 = reference_getname(data5); struct reg_db *ref5 = reference_getref(data5); size_t size = 0; for (int i = 0; i < craft_inventory_size; i++) { struct item_pair *entryItem = &entry_inventory->items[i]; uint32 index4 = start4 + size; uint32 index5 = start5 + size; script->set_reg(st, NULL, reference_uid(id4, index4), name4, (const void *)h64BPTRSIZE(entryItem->amount), ref4); script->set_reg(st, NULL, reference_uid(id5, index5), name5, (const void *)h64BPTRSIZE(entryItem->index), ref5); size++; } script_pushint(st, size); return true; } BUILDIN(useCraft) { getSD() return craft_use(sd, script_getnum(st, 2)); } BUILDIN(getCraftCode) { getSDReturn(-1) script_pushint(st, craft_get_entry_code(sd, script_getnum(st, 2))); return true; } BUILDIN(getInvIndexLink) { getSDReturnS("") int index = script_getnum (st, 2); if (index < 0 || index >= MAX_INVENTORY || (sd && index >= sd->status.inventorySize)) { script_pushstr(st, ""); return false; } const int item_id = sd->status.inventory[index].nameid; const struct item_data *i_data = NULL; if (item_id) i_data = itemdb->search(item_id); char *const item_name = (char *) aCalloc (1000, sizeof (char)); if (sd) { if (i_data) { const struct item *const item = &sd->status.inventory[index]; if (item->card[0] == CARD0_PET || item->card[0] == CARD0_FORGE || item->card[0] == CARD0_CREATE) { sprintf(item_name, "[@@%u|@@]", (unsigned)i_data->nameid); } else { sprintf(item_name, "[@@%u", (unsigned)i_data->nameid); int f; for (f = 0; f < 4 && item->card[f]; f ++) { char buf[100]; sprintf(buf, ",%u", (unsigned)item->card[f]); strcat(item_name, buf); } strcat(item_name, "|@@]"); } } else if (item_id > 0) { sprintf(item_name, "[@@%u|Unknown Item@@]", (unsigned)item_id); } else { sprintf(item_name, "[Unknown Item]"); } } else { if (i_data) sprintf(item_name, "[%s]", i_data->jname); else sprintf(item_name, "[Unknown Item]"); } script_pushstr(st, item_name); return true; } /*========================================== * Shows an emoticon on top of the player/npc * emotion emotion#, , *------------------------------------------*/ //Optional second parameter added by [Skotlex] BUILDIN(emotion) { int player = 0; int type = script_getnum(st, 2); if (script_hasdata(st, 3)) player = script_getnum(st, 3); if (player != 0) { struct map_session_data *sd = NULL; if (script_hasdata(st, 4)) sd = script->nick2sd(st, script_getstr(st, 4)); else sd = script->rid2sd(st); if (sd != NULL) clif->emotion(&sd->bl, type); } else if (script_hasdata(st, 4)) { struct npc_data *nd = npc->name2id(script_getstr(st, 4)); if (nd != NULL) clif->emotion(&nd->bl,type); } else { clif->emotion(map->id2bl(st->oid), type); } return true; } BUILDIN(setLook) { const int type = script_getnum(st, 2); const int val = script_getnum(st, 3); struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) return true; pc->changelook(sd, type, val); send_changelook2(sd, &sd->bl, sd->bl.id, type, val, 0, NULL, 0, AREA); return true; } BUILDIN(setFakeCells) { const int x1 = script_getnum(st, 2); const int y1 = script_getnum(st, 3); int x2 = x1, y2 = y1, block_type = 0; if (script_hasdata(st, 6)) { if (script_isinttype(st, 5) && script_isinttype(st, 6)) { x2 = script_getnum(st, 4); y2 = script_getnum(st, 5); block_type = script_getnum(st, 6); } else { ShowError("all arguments must be of type int"); return false; } } else { block_type = script_getnum(st, 4); } getSD(); send_setwall_single(sd->fd, sd->bl.m, 0, x1, y1, x2, y2, block_type); return true; } #define checkHashTableExists(id) \ if (!htreg->hashtable_exists(id)) \ { \ ShowError("%s: hashtable with id=%d does not exist\n", __func__, (int)id); \ script_pushint(st, 0); \ return false; \ } BUILDIN(htNew) { int64 id = htreg->new_hashtable(); script_pushint(st, id); return true; } BUILDIN(htGet) { int64 id = script_getnum(st, 2); checkHashTableExists(id); struct DBData defval_s; struct DBData *defval = &defval_s; const char * key = script_getstr(st, 3); if (script_hasdata(st, 4)) { if (script_isstringtype(st, 4)) { defval->type = DB_DATA_PTR; defval->u.ptr = (void*)script_getstr(st, 4); } else if (script_isinttype(st, 4)) { defval->type = DB_DATA_INT; defval->u.i = script_getnum(st, 4); } else { ShowError("usage: htget(, [ ,])\n"); return false; } } else { defval = NULL; } const struct DBData *result = htreg->hashtable_getvalue(id, key, defval); if (result) { switch(result->type) { case DB_DATA_INT: case DB_DATA_UINT: script_pushint(st, result->u.i); break; case DB_DATA_PTR: script_pushstrcopy(st, result->u.ptr); break; } } else { script_pushint(st, 0); } return true; } BUILDIN(htPut) { int64 id = script_getnum(st, 2); checkHashTableExists(id); struct DBData value; const char * key = script_getstr(st, 3); if (script_isstringtype(st, 4)) { value.type = DB_DATA_PTR; value.u.ptr = (void*)aStrdup(script_getstr(st, 4)); } else if (script_isinttype(st, 4)) { value.type = DB_DATA_INT; value.u.i = script_getnum(st, 4); } else { ShowError("usage: htput(, , )\n"); return false; } htreg->hashtable_setvalue(id, key, value); return true; } BUILDIN(htClear) { int64 id = script_getnum(st, 2); checkHashTableExists(id); htreg->clear_hashtable(id); return true; } BUILDIN(htDelete) { int64 id = script_getnum(st, 2); checkHashTableExists(id); htreg->destroy_hashtable(id); return true; } BUILDIN(htSize) { int64 id = script_getnum(st, 2); checkHashTableExists(id); script_pushint(st, htreg->hashtable_size(id)); return true; } BUILDIN(htExists) { int64 id = script_getnum(st, 2); script_pushint(st, htreg->hashtable_exists(id)); return true; } BUILDIN(htIterator) { int64 id = script_getnum(st, 2); checkHashTableExists(id); script_pushint(st, htreg->create_iterator(id)); return true; } #undef checkHashTableExists #define checkHtIteratorExists(id) \ if (!htreg->iterator_exists(id)) \ { \ ShowError("%s: htIterator with id=%d does not exist\n", __func__, (int)id); \ script_pushint(st, 0); \ return false; \ } BUILDIN(htiFirstKey) { int64 id = script_getnum(st, 2); checkHtIteratorExists(id); const char * key = htreg->iterator_firstkey(id); if (key) script_pushstrcopy(st, key); else script_pushstrcopy(st, ""); return true; } BUILDIN(htiLastKey) { int64 id = script_getnum(st, 2); checkHtIteratorExists(id); const char * key = htreg->iterator_lastkey(id); if (key) script_pushstrcopy(st, key); else script_pushstrcopy(st, ""); return true; } BUILDIN(htiNextKey) { int64 id = script_getnum(st, 2); checkHtIteratorExists(id); const char * key = htreg->iterator_nextkey(id); if (key) script_pushstrcopy(st, key); else script_pushstrcopy(st, ""); return true; } BUILDIN(htiPrevKey) { int64 id = script_getnum(st, 2); checkHtIteratorExists(id); const char * key = htreg->iterator_prevkey(id); if (key) script_pushstrcopy(st, key); else script_pushstrcopy(st, ""); return true; } BUILDIN(htiCheck) { int64 id = script_getnum(st, 2); checkHtIteratorExists(id); if (htreg->iterator_check(id)) script_pushint(st, 1); else script_pushint(st, 0); return true; } BUILDIN(htiDelete) { int64 id = script_getnum(st, 2); checkHtIteratorExists(id); htreg->destroy_iterator(id); return true; } #undef checkHtIteratorExists BUILDIN(getLabel) { script_pushint(st, script_getnum(st, 2)); return true; } BUILDIN(toLabel) { script_pushlabel(st, script_getnum(st, 2)); return true; } // replace default input with bigger text buffer /// Get input from the player. /// For numeric inputs the value is capped to the range [min,max]. Returns 1 if /// the value was higher than 'max', -1 if lower than 'min' and 0 otherwise. /// For string inputs it returns 1 if the string was longer than 'max', -1 is /// shorter than 'min' and 0 otherwise. /// /// input({,{,}}) -> BUILDIN(input) { struct script_data* data; int64 uid; const char* name; int min; int max; struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) return true; data = script_getdata(st, 2); if (!data_isreference(data)) { ShowError("script:input: not a variable\n"); script->reportdata(data); st->state = END; return false; } uid = reference_getuid(data); name = reference_getname(data); min = (script_hasdata(st,3) ? script_getnum(st,3) : script->config.input_min_value); max = (script_hasdata(st,4) ? script_getnum(st,4) : script->config.input_max_value); #ifdef SECURE_NPCTIMEOUT sd->npc_idle_type = NPCT_WAIT; #endif if (!sd->state.menu_or_input) { // first invocation, display npc input box sd->state.menu_or_input = 1; st->state = RERUNLINE; if (is_string_variable(name)) { clif->scriptinputstr(sd, st->oid); } else { sd->npc_amount_min = min; sd->npc_amount_max = max; clif->scriptinput(sd, st->oid); } } else { // take received text/value and store it in the designated variable sd->state.menu_or_input = 0; if (is_string_variable(name)) { int len = (int)strlen(global_npc_str); script->set_reg(st, sd, uid, name, global_npc_str, script_getref(st,2)); script_pushint(st, (len > max ? 1 : len < min ? -1 : 0)); } else { int amount = sd->npc_amount; script->set_reg(st, sd, uid, name, (const void *)h64BPTRSIZE(cap_value(amount,min,max)), script_getref(st,2)); script_pushint(st, (amount > max ? 1 : amount < min ? -1 : 0)); } st->state = RUN; } return true; } BUILDIN(slide) { getSDReturn(false); const int x = script_getnum(st,2); const int y = script_getnum(st,3); const int16 m = sd->bl.m; if (x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys) { ShowError("slide: attempt to place player %s (%d:%d) on invalid coordinates (%d,%d)\n", sd->status.name, sd->status.account_id, sd->status.char_id, x, y); script->reportsrc(st); return false; } if (map->getcell(m, &sd->bl, x, y, CELL_CHKNOPASS) && pc_get_group_level(sd) < battle->bc->gm_ignore_warpable_area) { return false; } clif->slide(&sd->bl, x, y); unit->movepos(&sd->bl, x, y, 1, 0); return true; } BUILDIN(getItemOptionIdByIndex) { getSD() getInventoryIndex(2) if (sd->status.inventory[n].nameid <= 0 || sd->status.inventory[n].amount <= 0) { script_pushint(st, 0); return false; } const int optIndex = script_getnum(st, 3); if (optIndex < 0 || optIndex >= MAX_ITEM_OPTIONS) { script_pushint(st, 0); return false; } const int optType = sd->status.inventory[n].option[optIndex].index; script_pushint(st, optType); return true; } BUILDIN(getItemOptionValueByIndex) { getSD() getInventoryIndex(2) if (sd->status.inventory[n].nameid <= 0 || sd->status.inventory[n].amount <= 0) { script_pushint(st, 0); return false; } const int optIndex = script_getnum(st, 3); if (optIndex < 0 || optIndex >= MAX_ITEM_OPTIONS) { script_pushint(st, 0); return false; } const int optValue = sd->status.inventory[n].option[optIndex].value; script_pushint(st, optValue); return true; } BUILDIN(getItemOptionParamByIndex) { getSD() getInventoryIndex(2) if (sd->status.inventory[n].nameid <= 0 || sd->status.inventory[n].amount <= 0) { script_pushint(st, 0); return false; } const int optIndex = script_getnum(st, 3); if (optIndex < 0 || optIndex >= MAX_ITEM_OPTIONS) { script_pushint(st, 0); return false; } const int optParam = sd->status.inventory[n].option[optIndex].param; script_pushint(st, optParam); return true; } BUILDIN(setItemOptionByIndex) { getSD() getInventoryIndex(2) if (sd->status.inventory[n].nameid <= 0 || sd->status.inventory[n].amount <= 0) return false; if (itemdb->isstackable2(sd->inventory_data[n])) return false; // not allow change equipped items if (sd->status.inventory[n].equip != 0) return false; const int optIndex = script_getnum(st, 3); if (optIndex < 0 || optIndex >= MAX_ITEM_OPTIONS) { ShowError("Wrong optIndex in setitemoptionbyindex\n"); return false; } int optType = 0; int optValue = 0; if (script_hasdata(st, 5)) { optType = script_getnum(st, 4); optValue = script_getnum(st, 5); } else { optType = sd->status.inventory[n].option[optIndex].index; optValue = script_getnum(st, 4); } if (optType != 0 && itemdb->option_exists(optType) == NULL) { ShowError("Wrong optType in setitemoptionbyindex\n"); return false; } clif->delitem(sd, n, 1, DELITEM_MATERIALCHANGE); logs->pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->status.inventory[n], sd->inventory_data[n]); sd->status.inventory[n].option[optIndex].index = optType; sd->status.inventory[n].option[optIndex].value = optValue; clif->additem(sd, n, 1, 0); logs->pick_pc(sd, LOG_TYPE_SCRIPT, 1, &sd->status.inventory[n], sd->inventory_data[n]); return true; } BUILDIN(isInstance) { const int instance_id = script_getnum(st, 2); script_pushint(st, instance->valid(instance_id) ? 1 : 0); return true; } BUILDIN(getNpcSubtype) { TBL_NPC *nd = map->id2nd(st->oid); if (script_hasdata(st, 2)) { if (script_isstringtype(st, 2)) { nd = npc->name2id(script_getstr(st, 2)); } else { nd = map->id2nd(script_getnum(st, 2)); } } if (!nd) { ShowWarning("npc not found\n"); script->reportsrc(st); return false; } script_pushint(st, nd->subtype); return true; } /*========================================== * return the battle stats of a structure * Supported values are most of UDT_* ones * Not all values are supported; Only those without * another assessor are (eg. MaxHP vs UDT_MAXHP) * * From 1 onwards: Str, Agi, Vit, Int, Dex, Luck * From 7 onwards: AtkMin, AtkMax, Def, MDef, Hit, Flee * From 13 onwards: MAtkMin, MatkMax *------------------------------------------*/ BUILDIN(readBattleParam) { struct map_session_data *sd; sd = script->id2sd(st, script_getnum(st, 2)); int data = script_getnum(st,3); // Error if (sd == NULL) { ShowError("Target is not player in readbattleparam(%d)\n", data); script_pushint(st, -1); return true; } switch (data) { // * From 1 onwards: Str, Agi, Vit, Int, Dex, Luck case UDT_STR: script_pushint(st, sd->battle_status.str); break; case UDT_AGI: script_pushint(st, sd->battle_status.agi); break; case UDT_VIT: script_pushint(st, sd->battle_status.vit); break; case UDT_INT: script_pushint(st, sd->battle_status.int_); break; case UDT_DEX: script_pushint(st, sd->battle_status.dex); break; case UDT_LUK: script_pushint(st, sd->battle_status.luk); break; case UDT_ATKRANGE: script_pushint(st, sd->battle_status.rhw.range); break; case UDT_ATKMIN: script_pushint(st, sd->battle_status.rhw.atk); break; case UDT_ATKMAX: script_pushint(st, sd->battle_status.rhw.atk+sd->battle_status.batk); break; case UDT_DEF: script_pushint(st, sd->battle_status.def); break; case UDT_MDEF: script_pushint(st, sd->battle_status.mdef+sd->battle_status.mdef2); break; case UDT_HIT: script_pushint(st, sd->battle_status.hit); break; case UDT_FLEE: script_pushint(st, sd->battle_status.flee); break; case UDT_MATKMIN: script_pushint(st, sd->battle_status.matk_min); break; case UDT_MATKMAX: script_pushint(st, sd->battle_status.matk_max); break; case UDT_CRIT: script_pushint(st, sd->battle_status.cri); break; case UDT_ELETYPE: script_pushint(st, sd->battle_status.def_ele); break; case UDT_ADELAY: script_pushint(st, sd->battle_status.adelay); break; case UDT_DMOTION: script_pushint(st, sd->battle_status.dmotion); break; default: ShowError("Wrong paramType in readbattleparam(%d)\nAre you sure you used the right constants?\n", data); script_pushint(st, -1); break; } return true; } BUILDIN(kick) { struct map_session_data *tsd = NULL; if (script_isstringtype(st, 2)) { tsd = map->nick2sd(script_getstr(st, 2), false); } else { tsd = map->id2sd(script_getnum(st, 2)); } if (tsd == NULL) { // silently fail script_pushint(st, 0); return true; } // clif_authfail_fd reason // see https://github.com/ManaPlus/ManaPlus/blob/master/src/net/eathena/generalrecv.cpp#L48 int reason = 15; // default: 15 - disconnection forced by a GM if (script_hasdata(st, 3)) { reason = script_getnum(st, 3); } if (tsd->fd > 0) { clif->authfail_fd(tsd->fd, reason); } else { map->quit(tsd); } script_pushint(st, 1); return true; } /////////////////////////////////////////////////////////////////////////////// // TMW2 Custom Commands /////////////////////////////////////////////////////////////////////////////// /*========================================== * Return the data of the @guild_id * null if not found *------------------------------------------*/ BUILDIN(getguildinfo) { int guild_id; struct guild* g; guild_id = script_getnum(st,2); if( ( g = guild->search(guild_id) ) != NULL ) { mapreg->setreg(reference_uid(script->add_variable("$@guildinfo_lvl"), guild_id),g->guild_lv); mapreg->setreg(reference_uid(script->add_variable("$@guildinfo_avg"), guild_id),g->average_lv); mapreg->setreg(reference_uid(script->add_variable("$@guildinfo_exp"), guild_id),(int)(g->exp)); mapreg->setreg(reference_uid(script->add_variable("$@guildinfo_nxp"), guild_id),(int)(g->next_exp)); } else { //script_pushconststr(st,"null"); script_pushint(st,0); } return true; } /*========================================== * Return the level of the @guild_id * -1 if not found *------------------------------------------*/ BUILDIN(getguildlvl) { int guild_id; struct guild* g; guild_id = script_getnum(st,2); if( ( g = guild->search(guild_id) ) != NULL ) { script_pushint(st,g->guild_lv); } else { script_pushint(st,-1); } return true; } /*========================================== * Return the average player level of the @guild_id * -1 if not found *------------------------------------------*/ BUILDIN(getguildavg) { int guild_id; struct guild* g; guild_id = script_getnum(st,2); if( ( g = guild->search(guild_id) ) != NULL ) { script_pushint(st,g->average_lv); } else { script_pushint(st,-1); } return true; } /*========================================== * Return the experience of the @guild_id * -1 if not found *------------------------------------------*/ BUILDIN(getguildexp) { int guild_id; struct guild* g; guild_id = script_getnum(st,2); if( ( g = guild->search(guild_id) ) != NULL ) { script_pushint(st,(int)(g->exp)); } else { script_pushint(st,-1); } return true; } /*========================================== * Return the experience to level up for the @guild_id * -1 if not found *------------------------------------------*/ BUILDIN(getguildnxp) { int guild_id; struct guild* g; guild_id = script_getnum(st,2); if( ( g = guild->search(guild_id) ) != NULL ) { script_pushint(st,(int)(g->next_exp)); } else { script_pushint(st,-1); } return true; } /*========================================== * Return the EXP tax for (guild, position) * -1 if not found *------------------------------------------*/ BUILDIN(getguildpostax) { int guild_id, gpos; struct guild* g; guild_id = script_getnum(st,2); gpos = script_getnum(st,3); if( ( g = guild->search(guild_id) ) != NULL ) { script_pushint(st,g->position[gpos].exp_mode); } else { script_pushint(st,-1); } return true; } /*========================================== * Return the title (guild, position) * "" if not found *------------------------------------------*/ BUILDIN(getguildpostitle) { int guild_id, gpos; struct guild* g; guild_id = script_getnum(st,2); gpos = script_getnum(st,3); if( ( g = guild->search(guild_id) ) != NULL ) { script_pushstrcopy(st, g->position[gpos].name); } else { script_pushstr(st,""); } return true; } /*========================================== * Change a position for the @guild_id * -1 if not found * This will be superseed by ManaPlus eventually * and is only a quick fix until 4144 can work with GUI. * Everyone knows C is easier than C++ >.> * WARNING Not sanitized *------------------------------------------*/ BUILDIN(setguildrole) { int guild_id; int idx; int mode; int exp_mode; const char *name; struct guild* g; guild_id = script_getnum(st,2); idx = script_getnum(st,3); mode = script_getnum(st,4); exp_mode = script_getnum(st,5); name = script_getstr(st,6); if( ( g = guild->search(guild_id) ) != NULL ) { script_pushint(st, guild->change_position(guild_id, idx, mode, exp_mode, name)); } else { script_pushint(st,-1); } return true; } /*========================================== * Get the information of the members of a guild by type. * getguildmember {,}; * @param guild_id: ID of guild * @param type: * 0 : name (default) * 1 : character ID * 2 : account ID *------------------------------------------*/ BUILDIN(getguildmember) { struct guild *g = NULL; int j = 0; g = guild->search(script_getnum(st,2)); if (g) { int i, type = 0; if (script_hasdata(st,3)) type = script_getnum(st,3); for ( i = 0; i < MAX_GUILD; i++ ) { if ( g->member[i].account_id ) { switch (type) { case 2: mapreg->setreg(reference_uid(script->add_variable("$@guildmemberaid"), j),g->member[i].account_id); break; case 1: mapreg->setreg(reference_uid(script->add_variable("$@guildmembercid"), j), g->member[i].char_id); break; default: mapreg->setregstr(reference_uid(script->add_variable("$@guildmembername$"), j), g->member[i].name); break; } mapreg->setreg(reference_uid(script->add_variable("$@guildmemberpos"), j),g->member[i].position); j++; } } } mapreg->setreg(script->add_variable("$@guildmembercount"), j); return true; } /*========================================== * Give homunculus exp *------------------------------------------*/ BUILDIN(gethomunexp) { int base=0; struct map_session_data *sd = script->rid2sd(st); if (sd == NULL || sd->hd == NULL) return true; base = script_getnum(st,2); if (base < 0) return true; // Cannot give EXP to inactive or dead homunculus if (!homun_alive(sd->hd)) return true; homun->gainexp(sd->hd, base); return true; } /*========================================== * Send resting homunculus in a mission * Homun must be resting. Returns true on success. *------------------------------------------*/ BUILDIN(deployhomunculus) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL || sd->hd == NULL) return true; /* // Homunculus must be resting if (sd->hd->homunculus.vaporize != HOM_ST_REST) return true; // Add morph state. //sd->hd->homunculus.vaporize=HOM_ST_MORPH; */ // Using the function, I don't need it resting homun->vaporize(sd, HOM_ST_MORPH, true); // Return true script_pushint(st,true); return true; } /*========================================== * Returns the Homunculus from a mission * Homun must be morph. Returns true on success. *------------------------------------------*/ BUILDIN(recallhomunculus) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL || sd->hd == NULL) return true; // Homunculus must be vapor if (sd->hd->homunculus.vaporize != HOM_ST_MORPH) return true; // Remove morph state. sd->hd->homunculus.vaporize=HOM_ST_REST; homun->call(sd); // Respawn homunculus. // Return true script_pushint(st,true); return true; } /*========================================== * Returns the Homunculus sleep status *------------------------------------------*/ BUILDIN(homstatus) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL || sd->hd == NULL) return true; // Return the status (0 - active; 1 - resting ; 2 - mission) // BUT Dead homunculus is not active (send RESTING instead) if (!sd->hd->homunculus.vaporize && !homun_alive(sd->hd)) script_pushint(st,1); else script_pushint(st,sd->hd->homunculus.vaporize); return true; } /*========================================== * return the updated stats of sd (use bonus constants) * Supported values: bStr~bLuk, bMaxHP, bMaxSP, bDef, bMdef, bAtk *------------------------------------------*/ BUILDIN(readparam2) { struct map_session_data *sd; int data = script_getnum(st,2); // Account ID/Player Name is also supported if (script_hasdata(st, 3)) { if (script_isstringtype(st, 3)) { sd = script->nick2sd(st, script_getstr(st, 3)); } else { sd = script->id2sd(st, script_getnum(st, 3)); } } else { sd = script->rid2sd(st); } // Error if (sd == NULL) { script_pushint(st, -1); return true; } switch (data) { case 13: script_pushint(st, sd->battle_status.str); break; case 14: script_pushint(st, sd->battle_status.agi); break; case 15: script_pushint(st, sd->battle_status.vit); break; case 16: script_pushint(st, sd->battle_status.int_); break; case 17: script_pushint(st, sd->battle_status.dex); break; case 18: script_pushint(st, sd->battle_status.luk); break; case 6: script_pushint(st, sd->battle_status.max_hp); break; case 8: script_pushint(st, sd->battle_status.max_sp); break; case 45: script_pushint(st, sd->battle_status.def); break; case 41: script_pushint(st, sd->battle_status.batk+sd->battle_status.rhw.atk); break; default: ShowError("Wrong paramType in readparam2(%d)\nAre you sure you used bonus constants?\nSupported values: bMaxHP, bMaxSP, bStr, bAgi, bVit, bInt, bDex, bLuk, bAtk, bDef\n", data); script_pushint(st, -1); break; } return true; } /*========================================== * *------------------------------------------*/ BUILDIN(debugmes) { struct StringBuf buf; StrBuf->Init(&buf); if (!script->sprintf_helper(st, 2, &buf)) { StrBuf->Destroy(&buf); script_pushint(st, 0); return false; } ShowDebug("script debug : %d %d : %s\n", st->rid, st->oid, StrBuf->Value(&buf)); StrBuf->Destroy(&buf); script_pushint(st, 1); return true; } /*========================================== * *------------------------------------------*/ BUILDIN(consolewarn) { struct StringBuf buf; StrBuf->Init(&buf); if (!script->sprintf_helper(st, 2, &buf)) { StrBuf->Destroy(&buf); script_pushint(st, 0); return false; } ShowWarning("script warning : %d %d : %s\n", st->rid, st->oid, StrBuf->Value(&buf)); StrBuf->Destroy(&buf); script_pushint(st, 1); return true; } /*========================================== * *------------------------------------------*/ BUILDIN(consolebug) { struct StringBuf buf; StrBuf->Init(&buf); if (!script->sprintf_helper(st, 2, &buf)) { StrBuf->Destroy(&buf); script_pushint(st, 0); return false; } ShowError("script error : %d %d : %s\n", st->rid, st->oid, StrBuf->Value(&buf)); StrBuf->Destroy(&buf); script_pushint(st, 1); return true; } /*========================================== * *------------------------------------------*/ BUILDIN(consoleinfo) { struct StringBuf buf; StrBuf->Init(&buf); if (!script->sprintf_helper(st, 2, &buf)) { StrBuf->Destroy(&buf); script_pushint(st, 0); return false; } ShowDebug("script notice : %d %d : %s\n", st->rid, st->oid, StrBuf->Value(&buf)); ShowNotice("%s\n", StrBuf->Value(&buf)); StrBuf->Destroy(&buf); script_pushint(st, 1); return true; } /*========================================== * gmcommand [MouseJstr] *------------------------------------------*/ BUILDIN(atcommand) { struct map_session_data *sd, *dummy_sd = NULL; int fd; const char* cmd; bool ret = true; cmd = script_getstr(st,2); if (st->rid) { sd = script->rid2sd(st); if (sd == NULL) return true; fd = sd->fd; } else { //Use a dummy character. sd = dummy_sd = pc->get_dummy_sd(); fd = 0; if (st->oid) { struct block_list* bl = map->id2bl(st->oid); memcpy(&sd->bl, bl, sizeof(struct block_list)); if (bl->type == BL_NPC) safestrncpy(sd->status.name, BL_UCAST(BL_NPC, bl)->name, NAME_LENGTH); } } if (!atcommand->exec(fd, sd, cmd, false)) { ShowWarning("script: buildin_atcommand: failed to execute command '%s'\n", cmd); script->reportsrc(st); ret = false; } if (dummy_sd) aFree(dummy_sd); return ret; } /*========================================== * *------------------------------------------*/ BUILDIN(countitem) { int count = 0; struct item_data* id = NULL; struct map_session_data *sd; if (script_hasdata(st,3)) { int account_id = script_getnum(st,3); sd = script->id2sd(st, account_id); // if (sd == NULL) { return true; } } else { sd = script->rid2sd(st);// attached player if (sd == NULL) return true; } if (sd == NULL) return true; if( script_isstringtype(st, 2) ) { // item name id = itemdb->search_name(script_getstr(st, 2)); } else { // item id id = itemdb->exists(script_getnum(st, 2)); } if( id == NULL ) { ShowError("buildin_countitem: Invalid item '%s'.\n", script_getstr(st,2)); // returns string, regardless of what it was script_pushint(st,0); return false; } int nameid = id->nameid; for (int i = 0; i < sd->status.inventorySize; i++) { if (sd->status.inventory[i].nameid == nameid) count += sd->status.inventory[i].amount; } script_pushint(st,count); return true; } /*========================================== * Set arrays with info of all sd inventory : * @inventorylist_id, @inventorylist_amount, @inventorylist_equip, * @inventorylist_refine, @inventorylist_identify, @inventorylist_attribute, * @inventorylist_card(0..3), * @inventorylist_opt_id(0..MAX_ITEM_OPTIONS), * @inventorylist_opt_val(0..MAX_ITEM_OPTIONS), * @inventorylist_opt_param(0..MAX_ITEM_OPTIONS), * @inventorylist_expire, @inventorylist_bound, @inventorylist_favorite, * @inventorylist_idx * @inventorylist_count = scalar *------------------------------------------*/ BUILDIN(getinventorylist) { struct map_session_data *sd = script->rid2sd(st); char script_var[SCRIPT_VARNAME_LENGTH]; int j = 0, k = 0; if (sd == NULL) return true; // This implementation allows empty slots to be filled for (int i = 0; i < sd->status.inventorySize; i++) { pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_id"), j), sd->status.inventory[i].nameid); pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_amount"), j), sd->status.inventory[i].amount); if (sd->status.inventory[i].equip != 0) { pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_equip"), j), pc->equippoint(sd, i)); } else { pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_equip"), j), 0); } pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_refine"), j), sd->status.inventory[i].refine); pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_identify"), j), sd->status.inventory[i].identify); pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_attribute"), j), sd->status.inventory[i].attribute); for (k = 0; k < MAX_SLOTS; k++) { sprintf(script_var, "@inventorylist_card%d", k + 1); pc->setreg(sd, reference_uid(script->add_variable(script_var), j), sd->status.inventory[i].card[k]); } for (k = 0; k < MAX_ITEM_OPTIONS; k++) { sprintf(script_var, "@inventorylist_opt_id%d", k + 1); pc->setreg(sd, reference_uid(script->add_variable(script_var), j), sd->status.inventory[i].option[k].index); sprintf(script_var, "@inventorylist_opt_val%d", k + 1); pc->setreg(sd, reference_uid(script->add_variable(script_var), j), sd->status.inventory[i].option[k].value); sprintf(script_var, "@inventorylist_opt_param%d", k + 1); pc->setreg(sd, reference_uid(script->add_variable(script_var), j), sd->status.inventory[i].option[k].param); } pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_expire"), j), sd->status.inventory[i].expire_time); pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_bound"), j), sd->status.inventory[i].bound); pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_favorite"), j), sd->status.inventory[i].favorite); pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_idx"), j), i); j++; } pc->setreg(sd, script->add_variable("@inventorylist_count"), j); return true; } // Returns the Acc. ID of the owner of an instance BUILDIN(InstanceOwner) { const int instance_id = script_getnum(st, 2); // Do instance exists? if (!instance->valid(instance_id)) { script_pushint(st, false); return true; } // Note: This does not returns type! // using this against party/guilds instances not advised. // returns 0 if either instance doesn't exists or is global script_pushint(st, (int)instance->list[instance_id].owner_id); return true; } // Advanced monster data overrider // aggravate(guid) BUILDIN(aggravate) { struct block_list *bl; struct map_session_data *sd = NULL; bl = map->id2bl(script_getnum(st, 2)); // We only work with mobs if (bl == NULL) { ShowWarning("buildin_aggravate: Error in finding object with given GID %d!\n", script_getnum(st, 2)); script_pushint(st, -1); return false; } if (bl->type != BL_MOB) { ShowWarning("buildin_aggravate: GID %d is not a monster!\n", script_getnum(st, 2)); script_pushint(st, -1); return false; } // Player must be attached sd = script->rid2sd(st); if (sd == NULL) { ShowWarning("buildin_aggravate: Ran without player attached!"); return true; } // Create monster structure struct mob_data *md = BL_UCAST(BL_MOB, bl); // Override the provoke flag md->state.provoke_flag = sd->status.account_id; // We could use mob->target() // But I want aggravate to apply without any checks // Skipping chase checks md->target_id = sd->status.account_id; return true; } // Returns the estimated damage (ATK or MATK) // Advantage over getunitdata is: Takes crit and etc. in account // types: 1- physical; 2- magic. // calcdmg(source, target, type) BUILDIN(calcdmg) { struct block_list *src; struct block_list *bl; int attack_type, range, damage; struct map_session_data *sd; // Fill data from scripts src = map->id2bl(script_getnum(st, 2)); bl = map->id2bl(script_getnum(st, 3)); attack_type = script_getnum(st,4); // Nullity check for source if (src == NULL) { ShowWarning("buildin_calcdmg: Error in finding object with given GID %d!\n", script_getnum(st, 2)); script_pushint(st, 0); return false; } // Maybe we don't want a target? if (script_getnum(st, 3) <= 0) { sd = BL_CAST(BL_PC, src); switch(attack_type) { case BF_WEAPON: range = sd->battle_status.rhw.atk2-sd->battle_status.rhw.atk; if (range <= 1) damage = sd->battle_status.rhw.atk; else damage = rnd()%range + sd->battle_status.rhw.atk; damage = damage + rnd()%sd->battle_status.batk; script_pushint(st, damage); break; case BF_MAGIC: range = sd->battle_status.matk_max-sd->battle_status.matk_min; if (range <= 1) script_pushint(st, sd->battle_status.matk_min); else script_pushint(st, rnd()%range + sd->battle_status.matk_min); break; default: ShowWarning("buildin_calcdmg: Invalid attack type %d!\n", attack_type); script_pushint(st, 0); return false; } return true; } // Nullity check for target if (bl == NULL) { ShowWarning("buildin_calcdmg: Error in finding object with given GID %d!\n", script_getnum(st, 3)); script_pushint(st, 0); return false; } // Get ATK or MATK struct Damage d; switch(attack_type) { case BF_WEAPON: d = battle->calc_weapon_attack(src, bl, 0,0,0); break; case BF_MAGIC: d = battle->calc_magic_attack(src, bl, 0,0,0); break; default: ShowWarning("buildin_calcdmg: Invalid attack type %d!\n", attack_type); script_pushint(st, 0); return false; break; } script_pushint(st, d.damage); return true; } // Like heal() but works against anything (casts battle funcs) // types: 1- physical; 2- magic. // Any other number: misc (no calculation) // harm(guid, raw_damage, {type{, element{, source}}}) BUILDIN(harm) { struct block_list *src; struct block_list *bl; struct status_data *tstatus; int attack_type = BF_MISC; short elemental = ELE_NEUTRAL; // Fill data from scripts bl = map->id2bl(script_getnum(st, 2)); int dmg = script_getnum(st, 3); // Attack Type if (script_hasdata(st,4)) { attack_type = script_getnum(st,4); } // Attack Element if (script_hasdata(st,5)) { elemental = script_getnum(st,5); } // Source (sd), might be null if (script_hasdata(st,6)) { src = map->id2bl(script_getnum(st, 6)); } else if (st->rid != 0 && map->id2sd(st->rid) != NULL) { struct map_session_data *sd = script->rid2sd(st); // Default source to self if needed if (sd == NULL) { src = bl; } else { src = &sd->bl; } } else { src = bl; } // Nullity checks if (bl == NULL) { ShowWarning("buildin_harm: Error in finding object with given GID %d!\n", script_getnum(st, 2)); script_pushint(st, 0); return false; } // Nullity checks which a fallback exists if (src == NULL) { ShowWarning("buildin_harm: Invalid source!\n"); src = bl; } // Overflow checks if( dmg == INT_MIN ) dmg++; if( dmg == INT_MAX ) dmg--; // Calculate defese (unaffected if not BF_WEAPON nor BF_MAGIC) switch(attack_type) { case BF_WEAPON: dmg = battle->calc_defense(BF_WEAPON, src, bl, 0, 0, dmg, 0, 0); break; case BF_MAGIC: dmg = battle->calc_defense(BF_MAGIC, src, bl, 0, 0, dmg, 0, 0); break; } // Elemental fix tstatus = status->get_status_data(bl); dmg=battle->attr_fix(src, bl, dmg, elemental, tstatus->def_ele, tstatus->ele_lv); // Apply the damage, skip any other checks or whatelse if ( dmg ) { if (dmg < 0) status->heal(bl, -dmg, 0, STATUS_HEAL_DEFAULT); else { // status_damage(*src, *target, in_hp, in_sp, walkdelay, flag) status->damage(src, bl, dmg, 0, 0, 0); clif->damage(src, bl, 0, 0, dmg, 0, BDT_ENDURE, 0); } } script_pushint(st, dmg); return true; } /*========================================== * Resets RNG seed *------------------------------------------*/ BUILDIN(resetrng) { //rnd->init(); unsigned int seed; double tmp; // Reinitialize the random number generator srand(time(NULL)); // Define a new seed tmp=1.0 * rand() / RAND_MAX; // Ranges from [0;1] seed=tmp * UINT_MAX; // Ranges from 0 to 4294967294 (It'll never be 100%) rnd->seed(seed); printf("\n\nWARNING\n\nRandomness seed updated to %u\n\n", seed); script_pushint(st, 0); return true; } /*========================================== * Get skill name *------------------------------------------*/ BUILDIN(getskillname) { int skill_id = script_getnum(st, 2); if (skill_id < 0) { script_pushstr(st, ""); return false; } script_pushstrcopy(st, skill->get_desc(skill_id)); return true; } BUILDIN(bgnew) { const char *map_name, *ev = "", *dev = ""; int x, y, map_index = 0, bg_id; map_name = script_getstr(st,2); if( strcmp(map_name,"-") != 0 ) { map_index = script->mapindexname2id(st,map_name); if( map_index == 0 ) { // Invalid Map script_pushint(st,0); return true; } } x = script_getnum(st,3); y = script_getnum(st,4); ev = script_getstr(st,5); // Logout Event dev = script_getstr(st,6); // Die Event if ((bg_id = bg->create(map_index, x, y, ev, dev)) == 0) { // Creation failed script_pushint(st,0); return true; } script_pushint(st,bg_id); return true; } BUILDIN(bgjoin) { int bgId = script_getnum(st, 2); const char* map_name = script_getstr(st, 3); int x = script_getnum(st,4); int y = script_getnum(st,5); struct map_session_data *sd; int map_index; if( (map_index = script->mapindexname2id(st,map_name)) == 0 ) return true; // Invalid Map if (script_hasdata(st,6)) { int account_id = script_getnum(st,6); sd = script->id2sd(st, account_id); // if (sd == NULL) { return true; } } else { sd = script->rid2sd(st);// attached player if (sd == NULL) return true; } if (sd == NULL) return true; if( bg->team_join(bgId, sd) ) { pc->setpos(sd, map_index, x, y, CLR_TELEPORT); script_pushint(st,1); } else script_pushint(st,0); return true; } /*========================================== * Sends something over PyLog *------------------------------------------*/ BUILDIN(apicall) { #ifdef PYTHON_LOGS char bf1[1024], bf3[2048], bf4[16]; sprintf(bf1,"SQL→INSERT INTO `api_export` (`type`, `data`) VALUES ('%d', '?1')", script_getnum(st, 2)); logs->pylog(bf1); sprintf(bf3, "SAD1→%s", script_getstr(st, 3)); logs->pylog(bf3); sprintf(bf4, "SQLRUN→"); logs->pylog(bf4); script_pushint(st, 1); #else script_pushint(st, 0); #endif return true; } /*========================================== * Sends something over PyLog *------------------------------------------*/ BUILDIN(apiasync) { #ifdef PYTHON_LOGS char bf1[2048]; sprintf(bf1, "%s→%s", script_getstr(st, 2), script_getstr(st, 3)); logs->pylog(bf1); script_pushint(st, 1); #else script_pushint(st, 0); #endif return true; } ////////////////////////////////////////////////////////// /* switch (bl->type) { case BL_MOB: struct mob_data *md = BL_UCAST(BL_MOB, bl); nullpo_retr(false, md); break; case BL_HOM: struct homun_data *hd = BL_UCAST(BL_HOM, bl); nullpo_retr(false, hd); break; case BL_PET: struct pet_data *pd = BL_UCAST(BL_PET, bl); nullpo_retr(false, pd); break; case BL_MER: struct mercenary_data *mc = BL_UCAST(BL_MER, bl); nullpo_retr(false, mc); break; case BL_ELEM: struct elemental_data *ed = BL_UCAST(BL_ELEM, bl); nullpo_retr(false, ed); break; case BL_NPC: struct npc_data *nd = BL_UCAST(BL_NPC, bl); nullpo_retr(false, nd); break; default: ShowError("buildin_harm: Unknown object!\n"); script_pushint(st, 0); return false; break; } */