// TMW2 Script
// Evol functions.
// Authors:
// 4144
// Travolta
// gumi
// Jesusalva
// Description:
// Built-in essential functions.
function script menuimage {
return getarg(0) + "|" + getarg(1);
}
function script dnext {
if (@dnext >= GSET_LONGMENU_DENSITY) {
@dnext=0;
next;
} else {
@dnext+=1;
}
return;
}
function script menuaction {
return "[" + getarg(0) + "]";
}
function script setq1 {
// Quest, val1 , val2 , val3 , time
setq getarg(0), getarg(1), getq2(getarg(0)), getq3(getarg(0)), getqtime(getarg(0));
return;
}
function script setq2 {
// Quest, val1 , val2 , val3 , time
setq getarg(0), getq(getarg(0)), getarg(1), getq3(getarg(0)), getqtime(getarg(0));
return;
}
function script setq3 {
// Quest, val1 , val2 , val3 , time
setq getarg(0), getq(getarg(0)), getq2(getarg(0)), getarg(1), getqtime(getarg(0));
return;
}
function script setqtime {
// Quest, val1 , val2 , val3 , time
setq getarg(0), getq(getarg(0)), getq2(getarg(0)), getq3(getarg(0)), getarg(1);
return;
}
function script mesn {
if (getargcount() > 0) {
.@s$ = "[" + getarg(0) + "]";
} else {
.@s$ = "[" + strnpcinfo(1) + "]";
}
mes .@s$;
return;
}
function script mesq {
mes "\"" + getarg(0)+ "\"";
return;
}
function script g {
return Sex == 0 ? getarg(0) : getarg(1);
}
function script b {
return "##B" + getarg(0) + "##b";
}
function script col {
.@color = getarg(1,9);
if (.@color < 0) .@color = 0;
if (.@color > 9) .@color = 9;
return "##" + .@color + getarg(0) + "##0";
}
function script adddefaultskills {
if (getskilllv(NV_BASIC) < 7) {
skill NV_BASIC, 7, 0;
}
if (getskilllv(TMW2_FAKESKILL) < 1) {
skill TMW2_FAKESKILL, 1, 0;
}
return;
}
function script addremovemapmask {
setmapmask getarg(0), (getmapmask(getarg(0)) | (getarg(1) + getarg(2))) ^ getarg(2);
return;
}
function script mesc {
mes col(getarg(0),getarg(1,9));
return;
}
function script get_race {
.@g=getarg(0, Class);
return l($@allraces$[.@g]);
}
// tutmes (message, {header=Tutorial, headerfirst=True})
function script tutmes {
.@header$=getarg(1, l("TUTORIAL"));
.@showheader=getarg(2, true);
.@tcol=9; // Tutorial color code
if (TUTORIAL) {
dnext;
if (.@showheader) {
mesf(".:: %s ::.", .@header$);
mesc getarg(0), .@tcol;
} else {
mesc .@header$+": "+getarg(0), .@tcol;
}
}
return;
}
// Function to show narrator text. Accepts string args.
// If first arg is a number N, then it represents bit flags.
// Bit flags :
// 0x1 -- blank line at beginning
// 0x2 -- blank line at the end
// 0x4 -- use last "next;"
// 0x8 -- don't use first "mesn;"
function script narrator {
.@start = 0;
.@argc = getargcount();
.@flags = 0;
if (.@argc > 1 && !isstr(getarg(0)))
{
.@start = 1;
.@flags = getarg(0);
}
if (.@flags & 0x1)
mes "";
if (!(.@flags & 0x8))
mesn l("Narrator");
for (.@i = .@start; .@i < .@argc; .@i++)
{
mes col(getarg(.@i), 9);
if (.@i < .@argc - 1)
next;
}
if (.@flags & 0x4)
next;
else if (.@flags & 0x2)
mes "";
return;
}
// Function to show NPC speech. Accepts string args.
// If first arg is a number N, then it represents bit flags.
// Bit flags :
// 0x1 -- blank line at beginning
// 0x2 -- blank line at the end
// 0x4 -- use last "next;"
// 0x8 -- don't use first "mesn;"
function script speech {
.@start = 0;
.@argc = getargcount();
.@flags = 0;
if (.@argc > 1 && !isstr(getarg(0)))
{
.@start = 1;
.@flags = getarg(0);
}
if (.@flags & 0x1)
mes "";
if (!(.@flags & 0x8))
mesn;
for (.@i = .@start; .@i < .@argc; .@i++)
{
mesq getarg(.@i);
if (.@i < .@argc - 1)
next;
}
if (.@flags & 0x4)
next;
else if (.@flags & 0x2)
mes "";
return;
}
// Show debug message if .debug variable of NPC is set to 1
function script npcdebug {
if (getvariableofnpc(.debug, strnpcinfo(3)))
debugmes strnpcinfo(3) + ": " + getarg(0);
return;
}
function script askyesno {
return select(menuaction(l("Yes")),
menuaction(l("No")));
}
// Argument:
// 0 Quest variable
// 1 Current value
// 2 Next value
function script compareandsetq {
if (getq(getarg(0)) == getarg(1))
{
setq getarg(0), getarg(2);
return true;
}
return false;
}
// Use a delay to prevent spams from NPC that display text without the
// use of (a) close/next function(s).
// Argument:
// 0 Text to display
// 1 Lock delay (default = 1)
// 2 Message function: (default = 0)
// 0 = npctalk3
// 1 = npctalk
// 2 = message
// TODO: Use temp player var, because NPC var affect other players
function script npctalkonce {
// lock mechanism
switch (getarg(2, 0))
{
case 1:
if (gettimetick(2) <= getvariableofnpc(.talk_lock, strnpcinfo(NPC_NAME_UNIQUE)))
return false;
set(getvariableofnpc(.talk_lock, strnpcinfo(NPC_NAME_UNIQUE)), gettimetick(2) + getarg(1, 1));
break;
default:
if (gettimetick(2) <= @NPC_TALK_LOCK[getnpcid()])
return false;
@NPC_TALK_LOCK[getnpcid()] = gettimetick(2) + getarg(1, 1);
}
// talk mechanism
switch (getarg(2, 0))
{
case 0: npctalk3(getarg(0)); break;
case 1: npctalk(getarg(0)); break;
case 2: message(strcharinfo(0), getarg(0));
}
return true;
}
// Randomizer functions
/////////////////////////////////////////////
// pseudo-fix randomness
// rand2( min, max )
function script rand2 {
if (getargcount() == 2) {
.@min=getarg(0)*100;
.@max=getarg(1)*100+99;
} else {
.@min=0;
.@max=getarg(0)*100-1;
}
return rand(.@min, .@max)/100;
}
// returns one argument randomly
// any( <arg>{, ...<arg>} )
function script any {
return getarg(rand2(getargcount()));
}
// returns any member of the array
// any_of( <array> )
function script any_of {
return getelementofarray(getarg(0), getarrayindex(getarg(0)) + rand2(getarraysize(getarg(0)) - getarrayindex(getarg(0))));
}
function script die {
if ($HARDCORE) {
@grace=true;
addtimer 10, "#GlobalHandler::OnDie"; // Wait script execution to finish
//setparam(Hp, 1);
//warp "000-1", 22, 22;
//end; // MUST be end; to mimic official behavior
} else {
addtimer 10, "#GlobalHandler::OnDie"; // Wait script execution to finish
}
return;
}
// Returns if a map is on PVP Mode or Not
// ispvpmap( {mapid} )
function script ispvpmap {
.@mapa$=getarg(0, getmapname());
return (getmapflag(.@mapa$, mf_pvp) || getmapflag(.@mapa$, mf_pvp_noparty) || getmapflag(.@mapa$, mf_pvpnoguild));
}
// TMW2 Custom Functions
/////////////////////////////////////////////
// Function meant to be used by Main Storyline Quest
// msObjective ( condition , message )
function script msObjective {
if (getarg(0))
mesc getarg(1), 2;
else
mesc getarg(1), 9;
return;
}
function script getmap {
if (getmapxy(.@mapName$, .@xpos, .@ypos, getarg(0,0)) != 0)
return false;
// TODO: Maybe use getmapname() instead of getmapxy?
return .@mapName$;
}
// isin( map, x1, y1, {[x2, y2][radius]} )
function script isin {
if (getmapxy(.@mapName$, .@xpos, .@ypos, 0) != 0)
return false;
if (.@mapName$ != getarg(0))
return false;
if (getarg(4,-1) < 0) {
// Radius Based
if (.@xpos >= getarg(1)-getarg(3) && .@xpos <= getarg(1)+getarg(3) && .@ypos >= getarg(2)-getarg(3) && .@ypos <= getarg(2)+getarg(3))
return true;
} else {
// Coordinate based
if (.@xpos >= getarg(1) && .@xpos <= getarg(3) && .@ypos >= getarg(2) && .@ypos <= getarg(4))
return true;
}
return false;
}
// Clear output of getinventorylist()
// delinventorylist()
function script delinventorylist {
deletearray @inventorylist_id;
deletearray @inventorylist_amount;
deletearray @inventorylist_equip;
deletearray @inventorylist_refine;
deletearray @inventorylist_identify;
deletearray @inventorylist_attribute;
deletearray @inventorylist_card1;
deletearray @inventorylist_card2;
deletearray @inventorylist_card3;
deletearray @inventorylist_card4;
deletearray @inventorylist_expire;
deletearray @inventorylist_bound;
@inventorylist_count=0;
return;
}
// Get some acc id, even if offline
// ( Name )
function script gf_accid {
.@nb = query_sql("SELECT `account_id` FROM `char` WHERE `name`='"+escape_sql(getarg(0))+"' LIMIT 1", .@value);
return .@value[0];
}
// Get some char id, even if offline
// ( Name )
function script gf_charnameid {
.@nb = query_sql("SELECT `char_id` FROM `char` WHERE `name`='"+escape_sql(getarg(0))+"' LIMIT 1", .@value);
return .@value[0];
}
// Get some char name from char ID, even if offline
// ( Name )
function script gf_charname {
.@nb = query_sql("SELECT `name` FROM `char` WHERE `char_id`="+escape_sql(getarg(0))+" LIMIT 1", .@value$);
return .@value$[0];
}
// Get some char ID from account ID, even if offline
// ( Name )
function script gf_charid {
.@nb = query_sql("SELECT `char_id` FROM `char` WHERE `account_id`="+escape_sql(getarg(0))+" LIMIT 1", .@value$);
return .@value$[0];
}
// Request pincode and validate it. Use any non-4-digits code to cancel. Failure will dc you.
// Returns 1 if pin check is OK.
function script validatepin {
if (#FIRST_TIME < 2) {
mesc l("ERROR: You must set a PinCode to make use of this function."), 1;
return 0;
}
mesc l("Please insert your pincode."), 1;
mesc l("WARNING: If you insert wrong pincode, you'll be disconnected.");
mesc l("Use @@ to cancel.", "##B-1##b");
mes "";
input .@pin$;
if (getstrlen(.@pin$) != 4)
return 0;
query_sql("SELECT userid FROM `login` WHERE account_id="+escape_sql(getcharid(3))+" AND pincode='"+escape_sql(.@pin$)+"' LIMIT 2", .@value$);
if (getarraysize(.@value$) != 1) {
atcommand "@kick "+strcharinfo(0);
return 0;
}
// Enforce some cooldown to prevent an eventual exploit/abuse
sleep2(rand2(150, 400));
mesc l("Thanks, @@. We just wanted to be sure it was you.", .@value$[0]);
mes "";
return true;
}
// Something went wrong and must be reported (named after raise Exception in python)
// Exception( BugID, {Flags{, Return Code}} )
function script Exception {
// Fill variable
.@msg$=getarg(0);
.@gf=getarg(1,RB_DEFAULT);
if (.@gf & RB_DISPBOTTOM)
dispbottom("ERROR: "+.@msg$);
if (.@gf & RB_DEBUGMES)
debugmes("[Warning] "+.@msg$);
if (.@gf & RB_SPEECH)
mesc("ERROR, REPORT ME! "+.@msg$, 1);
if (.@gf & RB_IRCBROADCAST)
channelmes("#world", "Error in script: "+.@msg$);
if (.@gf & RB_GLOBALANNOUNCE)
announce("Error in script: "+.@msg$, bc_all);
if (.@gf & RB_PLEASEREPORT) {
if (.@gf & RB_DISPBOTTOM)
dispbottom("Please take a screenshot and report this bug, explaining how it happened.");
if (.@gf & RB_SPEECH)
mesc("Please take a screenshot and report this bug, explaining how it happened."), 1;
}
if (.@gf & RB_ISFATAL) {
if (.@gf & RB_DISPBOTTOM)
dispbottom("This error is fatal, we stop execution.");
if (.@gf & RB_DEBUGMES)
debugmes("[Error] The error is fatal.");
if (.@gf & RB_SPEECH) {
mesc l("This error is fatal, we stop execution."), 1;
close;
}
end;
}
return getarg(2, 0);
}
// mescordialog(text, color, {dialog=1})
function script mescordialog {
if (getarg(2, true))
mesc getarg(0), getarg(1);
else
dispbottom col(getarg(0), getarg(1));
return;
}
// Delayed healing. Takes 3~5 seconds. Variates with Vit up to +100%.
// The vit can have an additional 20% bonus as well.
function script itheal {
.@bas=getarg(0);
.@vit=readbattleparam(getcharid(3), UDT_VIT);
.@vit=cap_value(.@vit-1, 0, 100);
if (getargcount() > 2)
.@tim=getarg(3);
else
.@tim=rand2(3,5);
.@min=.@bas*(100+.@vit)/100;
.@max=.@bas*(100+.@vit*120/100)/100;
// Now divide the HP values by the time
.@min=max(1, .@min/.@tim);
.@max=max(1, .@max/.@tim);
callfunc("SC_Bonus", .@tim, SC_S_LIFEPOTION, .@min, .@max);
if (getarg(1,0) > 0)
heal 0, getarg(1, 0);
return;
}
// sqldate({day variation, month variation})
function script sqldate {
.@d=gettime(GETTIME_DAYOFMONTH)+getarg(0, 0);
.@m=gettime(GETTIME_MONTH)+getarg(1, 0);
.@y=gettime(GETTIME_YEAR);
// Overflow prevention
if (.@d <= 0) {
.@d=1;
}
while (.@m > 12) {
.@y+=1;
.@m-=12;
}
while (.@m < 1) {
.@y-=1;
.@m+=12;
}
.@strdate$=sprintf("%04d-%02d-%02d %02d:%02d:%02d", .@y, .@m, .@d, gettime(GETTIME_HOUR), gettime(GETTIME_MINUTE), gettime(GETTIME_SECOND));
return .@strdate$;
}
// Makes a monster aggro
// set_aggro( monster{, mode=MD_AGGRESSIVE} )
function script set_aggro {
.@m=getarg(0);
.@x=getarg(1, MD_AGGRESSIVE);
.@op=getunitdata(.@m, UDT_MODE);
.@op=.@op|.@x;
setunitdata(.@m, UDT_MODE, .@op);
return;
}
// Special function which makes a date as a number
// numdate( - )
function script numdate {
.@strdate$=sprintf("%04d%02d%02d", gettime(GETTIME_YEAR), gettime(GETTIME_MONTH), gettime(GETTIME_DAYOFMONTH));
// Debug payload
if ($@OVERRIDE_NUMDATE)
return $@OVERRIDE_NUMDATE;
return atoi(.@strdate$);
}
// json_encode( {varname, varvalue}, {varname 2, varvalue 2}... )
// returns string
function script json_encode {
if (getargcount() < 2 || getargcount() % 2 != 0)
return Exception("json_encode arguments must be paired");
.@json$="{";
.@tab=true;
// For arguments
for (.@i=0;.@i < getargcount(); .@i++) {
// Close previous item
if (.@tab)
.@tab=false;
else
.@json$+=",";
// Input variable name
.@json$+="\""+getarg(.@i)+"\": ";
// Input variable value
if (isstr(getarg(.@i+1)))
.@json$+="\""+getarg(.@i+1)+"\"";
else
.@json$+=getarg(.@i+1);
// Advance
.@i++;
}
// Close the JSON
.@json$+="}";
return .@json$;
}
// api_send( code, data )
// sends to API
function script api_send {
.@cde=getarg(0);
.@fm$=escape_sql(getarg(1));
query_sql("INSERT INTO `api_export` (`type`, `data`) VALUES ('"+.@cde+"', \""+.@fm$+"\")");
return;
}
// Linking functions
/////////////////////////////////////////////
function script getquestlink {
return "[@@q" + getarg(0) + "|@@]";
}
function script getmonsterlink {
return "[@@m" + getarg(0) + "|@@]";
}
function script getpetlink {
return "[@@p" + getarg(0) + "|@@]";
}
function script getmercenarylink {
return "[@@M" + getarg(0) + "|@@]";
}
function script gethomunculuslink {
return "[@@h" + getarg(0) + "|@@]";
}
// Legacy functions
/////////////////////////////////////////////
function script mapexit {
debugmes "TRYING TO MAPEXIT IS DEPRECATED";
return;
}
function script destroy {
disablenpc strnpcinfo(0);
return;
}
function script npcaction {
debugmes "Deprecated unitaction (did you mean npcsit; or whatever?)";
.@a=getarg(0, 0);
if (.@a == 9)
clear;
return;
}
function script gmlog {
logmes(getarg(0), LOGMES_ATCOMMAND);
return;
}
function script getx {
getmapxy(.@m$, .@x, .@y, 0);
return .@x;
}
function script gety {
getmapxy(.@m$, .@x, .@y, 0);
return .@y;
}
function script getnpcx {
return .x;
}
function script getnpcy {
return .y;
}
function script title {
setnpcdialogtitle getarg(0);
return;
}
function script camera {
if (getarg(0, "") != "")
setcamnpc getarg(0);
else
restorecam;
return;
}
function script mapmask {
sendmapmask getarg(0);
return;
}
function script getmask {
return 1; //getmapmask(getmapname()); // TODO: Return original map masks
}
// isat( map, x, y )
function script isat {
return isin(getarg(0), getarg(1), getarg(2), 0);
}
function script if_then_else {
return (getarg(0) ? getarg(1) : getarg(2));
}
function script misceffect {
// or SELF + something
return specialeffect(getarg(0), AREA, getarg(1, strnpcinfo(0)));
}
function script selfeffect {
// or SELF + something
return specialeffect(getarg(0), SELF, getarg(1, strnpcinfo(0)));
}
function script fakenpcname {
if (getargcount() > 2)
setnpcdisplay(getarg(0), getarg(1), getarg(2));
else
setnpcdisplay(getarg(0), getarg(1));
return;
}
function script npcwarp {
if (getargcount() > 2)
.@id=getnpcid(getarg(3));
else
.@id=getnpcid();
getmapxy(.@m$, .@x, .@y, UNITTYPE_NPC, strnpcinfo(0, "", .@id));
unitwarp(.@id, .@m$, getarg(0), getarg(1));
return;
}
function script get {
return getvariableofnpc(getarg(0), getarg(1));
}
function script sc_check {
return getstatus(getarg(0), getarg(1, 0));
}
function script wgm {
charcommand("@request "+getarg(0));
return;
}
function script registercmd {
// Remove "@" from command start
.@cmd$=getarg(1);
if (charat(.@cmd$, 0) == "@")
delchar(.@cmd$, 0);
bindatcmd getarg(0), .@cmd$, getarg(2, 0);
return;
}
function script iscollision {
return checknpccell(getarg(0), getarg(1), getarg(2), cell_chkpass);
}
function script readparam2 {
return readbattleparam(getcharid(3), getarg(0));
}
function script updateskill {
skill getarg(0), getarg(1), 0;
return;
}
function script npctalk2 {
npctalk getarg(1), getarg(0);
return;
}
function script learnskill {
if (getskilllv(getarg(0)) < getarg(1, 1))
skill getarg(0), getarg(1, 1), 0;
return;
}
function script spawndummy {
// spawndummy(map, x, y, ID{, name{, event}})
.@m$=getarg(0);
.@x=getarg(1);
.@y=getarg(2);
.@id=getarg(3);
.@n$=getarg(4, strmobinfo(1, .@id));
.@e$=getarg(5, "");
// Create monster, with optional event
if (.@e$ == "")
.@u=monster(.@m$, .@x, .@y, .@n$, .@id, 1);
else {
.@u=monster(.@m$, .@x, .@y, .@n$, .@id, 1, .@e$);
debugmes "SPAWNDUMMY %s", .@e$;
}
// Reset unit data for script use
setunitdata(.@u, UDT_LEVEL, 1);
setunitdata(.@u, UDT_HP, 1);
setunitdata(.@u, UDT_MAXHP, 1);
setunitdata(.@u, UDT_SP, 1);
setunitdata(.@u, UDT_MAXSP, 1);
setunitdata(.@u, UDT_MODE, 0); // Stoic mode
setunitdata(.@u, UDT_ATKRANGE, 1);
setunitdata(.@u, UDT_ATKMIN, 1);
setunitdata(.@u, UDT_ATKMAX, 1);
setunitdata(.@u, UDT_MATKMIN, 1);
setunitdata(.@u, UDT_MATKMAX, 1);
setunitdata(.@u, UDT_DEF, 1);
setunitdata(.@u, UDT_MDEF, 1);
setunitdata(.@u, UDT_HIT, 1);
setunitdata(.@u, UDT_FLEE, 1);
setunitdata(.@u, UDT_CRIT, 1);
setunitdata(.@u, UDT_LOOKDIR, DOWN);
return .@u;
}