// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
// Copyright (c) 2014 - 2015 Evol developers
#include "common/hercules.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <time.h>
#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/chat.h"
#include "map/chrif.h"
#include "map/guild.h"
#include "map/homunculus.h"
#include "map/instance.h"
#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 = script->rid2sd(st);
if (sd == NULL)
{
sd = script->nick2sd(st, script_getstr(st, 2));
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;
}
/// <type>=0 : will destroy both the item and the cards.
/// <type>=1 : will keep the item, but destroy the cards.
/// <type>=2 : will keep the cards, but destroy the item.
/// <type>=? : 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("<map name>",<x>,<y>,<type>) -> <bool>
///
/// @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#, <target: 0 - NPC, 1 - PC>, <NPC/PC name>
*------------------------------------------*/
//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(<id>, <strkey>[ ,<defval>])\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(<id>, <strkey>, <newval>)\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(<var>{,<min>{,<max>}}) -> <int>
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;
}
///////////////////////////////////////////////////////////////////////////////
// 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 <guild_id>{,<type>};
* @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;
}
/*==========================================
* 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); // <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}})
BUILDIN(harm)
{
struct block_list *src;
struct block_list *bl;
struct status_data *tstatus;
struct map_session_data *sd = NULL;
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);
}
// 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;
}
// Overflow checks
if( dmg == INT_MIN ) dmg++;
if( dmg == INT_MAX ) dmg--;
// Source (sd), might be null
if(st->rid != 0 && map->id2sd(st->rid) != NULL)
sd = script->rid2sd(st);
// Default source to self if needed
if (sd == NULL) {
src = bl;
} else {
src = &sd->bl;
}
// 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;
}
//////////////////////////////////////////////////////////
/*
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;
}
*/