summaryrefslogblamecommitdiff
path: root/npc/functions/main.txt
blob: d072ff608dd2585b71644c1d5e91c45b6bc170b6 (plain) (tree)


















































































                                                                                       

                                   



                                         
























































































































































































































                                                                                                                              






                                                                                                                      




























































































































































                                                                                                                                                 









                                             
 







































                                                                                                                                                

 

































































                                                                                                                   




























                                                 




                                 

                                                                         


                     







































                                        
                          



                                 
                                                                            






                                                    



                                               

                                         








                                                                    

 














                                                                    



                                              




                                       
                                         




                                              


           

                                                                       

 
                                         
                                                    

 




                                         
                                         

                                             


           
// 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;
        percentheal -100, -100;
        //setparam(Hp, 1);
        //warp "000-1", 22, 22;
        //end; // MUST be end; to mimic official behavior
    } else {
        percentheal -100, -100;
    }
    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	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	learnskill	{
    if (getskilllv(getarg(0)) < getarg(1, 1))
        skill getarg(0), getarg(1, 1), 0;
    return;
}