diff options
Diffstat (limited to 'npc/functions')
-rw-r--r-- | npc/functions/array.txt | 464 | ||||
-rw-r--r-- | npc/functions/asklanguage.txt | 72 | ||||
-rw-r--r-- | npc/functions/filters.txt | 126 | ||||
-rw-r--r-- | npc/functions/goodbye.txt | 152 | ||||
-rw-r--r-- | npc/functions/inc_sc_bonus.txt | 72 | ||||
-rw-r--r-- | npc/functions/input.txt | 110 | ||||
-rw-r--r-- | npc/functions/inventoryplace.txt | 36 | ||||
-rw-r--r-- | npc/functions/main.txt | 37 | ||||
-rw-r--r-- | npc/functions/math.txt | 123 | ||||
-rw-r--r-- | npc/functions/npcmove.txt | 142 | ||||
-rw-r--r-- | npc/functions/npcmovegraph.txt | 489 | ||||
-rw-r--r-- | npc/functions/permissions.txt | 35 | ||||
-rw-r--r-- | npc/functions/random-talk.txt | 207 | ||||
-rw-r--r-- | npc/functions/string.txt | 211 | ||||
-rwxr-xr-x | npc/functions/time.txt | 256 | ||||
-rw-r--r-- | npc/functions/timer.txt | 89 |
16 files changed, 2444 insertions, 177 deletions
diff --git a/npc/functions/array.txt b/npc/functions/array.txt new file mode 100644 index 00000000..d433abd7 --- /dev/null +++ b/npc/functions/array.txt @@ -0,0 +1,464 @@ +// Evol Script +// Author: Gumi + +// array_pad(<array>, <size>, <value>) +// prepend or append <value> until the array is of <size> size +// returns the amount added on success, or false (0) if nothing changed + +function script array_pad { + .@index = getarrayindex(getarg(0)); // passed index + .@count = getarraysize(getarg(0)) - .@index; // actual size + .@size = getarg(1); // desired size + .@absolute = (.@size >= 0 ? .@size : -(.@size)); // |size| + .@delta = .@absolute - .@count; // amount to fill + + if (.@absolute <= .@count) { + return false; // nothing to do + } + + if (.@size < 0) { + copyarray(getelementofarray(getarg(0), .@index + .@delta), getarg(0), .@count); // shift to the right + cleararray(getarg(0), getarg(2), .@delta); // prepend + } else { + cleararray(getelementofarray(getarg(0), .@index + .@count), getarg(2), .@delta); // append + } + + return .@delta; +} + + + +// array_replace(<array>, <needle>, <replace>{, <neq>}) +// replace every occurence of <needle> with <replace> +// returns the number of replaced elements + +function script array_replace { + .@size = getarraysize(getarg(0)); + .@neq = getarg(3, false); + freeloop(true); + + for (.@i = getarrayindex(getarg(0)); .@i < .@size; ++.@i) { + if ((.@neq && (getelementofarray(getarg(0), .@i) != getarg(1))) || + (!(.@neq) && (getelementofarray(getarg(0), .@i) == getarg(1)))) { + set(getelementofarray(getarg(0), .@i), getarg(2)); + ++.@count; + } + } + + freeloop(false); + return .@count; +} + + + +// array_find(<array>, <needle>{, <neq>}) +// return the index of the first occurence of <needle> in <array> +// if not found it returns -1 + +function script array_find { + .@size = getarraysize(getarg(0)); + .@neq = getarg(2, false); + freeloop(true); + + for (.@i = getarrayindex(getarg(0)); .@i < .@size; ++.@i) { + if ((.@neq && (getelementofarray(getarg(0), .@i) != getarg(1))) || + (!(.@neq) && (getelementofarray(getarg(0), .@i) == getarg(1)))) { + freeloop(false); + return .@i; + } + } + + freeloop(false); + return -1; +} + + + +// array_rfind(<array>, <needle>{, <neq>}) +// return the index of the last occurence of <needle> in <array> +// if not found it returns -1 + +function script array_rfind { + .@min = getarrayindex(getarg(0)); + .@neq = getarg(2, false); + freeloop(true); + + for (.@i = (getarraysize(getarg(0)) - 1); .@i >= .@min; --.@i) { + if ((.@neq && (getelementofarray(getarg(0), .@i) != getarg(1))) || + (!(.@neq) && (getelementofarray(getarg(0), .@i) == getarg(1)))) { + freeloop(false); + return .@i; + } + } + + freeloop(false); + return -1; +} + + + +// array_exists(<array>, <needle>{, <neq>}) +// return true or false accordingly if <needle> is found in <array> + +function script array_exists { + return array_find(getarg(0), getarg(1), getarg(2, false)) > -1; +} + + + +// array_count(<array>, <needle>{, <neq>}) +// counts the number of occurrence of <needle> in the <array> + +function script array_count { + .@size = getarraysize(getarg(0)); + .@neq = getarg(2, false); + freeloop(true); + + for (.@i = getarrayindex(getarg(0)); .@i < .@size; ++.@i) { + if ((.@neq && (getelementofarray(getarg(0), .@i) != getarg(1))) || + (!(.@neq) && (getelementofarray(getarg(0), .@i) == getarg(1)))) { + ++.@count; + } + } + + freeloop(false); + return .@count; +} + + + +// array_entries(<array>) +// returns the number of non-empty entries + +function script array_entries { + if (isstr(getarg(0)) == 1) { + return array_count(getarg(0), "", true); + } + return array_count(getarg(0), 0, true); +} + + + +// array_remove(<array>, <needle>{, <neq>}) +// removes every occurrence of <needle> in the <array> while shifting left + +function script array_remove { + .@size = getarraysize(getarg(0)); + .@neq = getarg(2, false); + freeloop(true); + + for (.@i = getarrayindex(getarg(0)); .@i < .@size; ++.@i) { + if ((.@neq && (getelementofarray(getarg(0), .@i) != getarg(1))) || + (!(.@neq) && (getelementofarray(getarg(0), .@i) == getarg(1)))) { + deletearray(getelementofarray(getarg(0), .@i), 1); // shift left + ++.@count; // increase the counter + --.@size; // reduce the size + --.@i; // step back + } + } + + freeloop(false); + return .@count; +} + + + +// array_reverse(<array>) +// reverses the array + +function script array_reverse { + .@index = getarrayindex(getarg(0)); + .@size = getarraysize(getarg(0)); + freeloop(true); + + for (.@i = .@index; .@i < ((.@size + .@index) / 2); ++.@i) { + swap(getelementofarray(getarg(0), .@i), getelementofarray(getarg(0), .@size + .@index - 1 - .@i)); // a <> b + } + + freeloop(false); + return true; +} + + + +// array_sum(<array>) +// return the sum of every element of the array + +function script array_sum { + .@size = getarraysize(getarg(0)); + freeloop(true); + + for (.@i = getarrayindex(getarg(0)); .@i < .@size; ++.@i) { + .@sum += getelementofarray(getarg(0), .@i); + } + + freeloop(false); + return .@sum; +} + + + +// array_difference(<array>) +// return the difference of every element of the array + +function script array_difference { + .@size = getarraysize(getarg(0)); + freeloop(true); + + for (.@i = getarrayindex(getarg(0)); .@i < .@size; ++.@i) { + .@diff -= getelementofarray(getarg(0), .@i); + } + + freeloop(false); + return .@diff; +} + + + +// array_shift(<array>) +// returns the first element of the array and removes it, while shifting left + +function script array_shift { + if (isstr(getarg(0)) == 1) { + .@val$ = getarg(0); + } else { + .@int = true; + .@val = getarg(0); + } + + deletearray(getarg(0), 1); // shift left + + return .@int ? .@val : .@val$; +} + + + +// array_unshift(<array>, <value>) +// adds <value> to the start of the array, while shifting right +// returns the new size + +function script array_unshift { + .@size = getarraysize(getarg(0)) + 1; + array_pad(getarg(0), -(.@size - getarrayindex(getarg(0))), getarg(1)); + return .@size; +} + + + +// array_pop(<array>) +// returns the last element of the array and removes it + +function script array_pop { + .@last = getarraysize(getarg(0)) - 1; + + if (isstr(getelementofarray(getarg(0), .@last)) == 1) { + .@val$ = getelementofarray(getarg(0), .@last); + } else { + .@int = true; + .@val = getelementofarray(getarg(0), .@last); + } + + deletearray(getelementofarray(getarg(0), .@last), 1); + + return .@int ? .@val : .@val$; +} + + + +// TODO: Rename to array_append >.< +// array_push(<array>, <value>) +// adds <value> to the end of the array +// returns the new size + +function script array_push { + .@size = getarraysize(getarg(0)); + set(getelementofarray(getarg(0), .@size), getarg(1)); + return .@size + 1; +} + + + +// array_shuffle(<array>) +// shuffles the array + +function script array_shuffle { + .@index = getarrayindex(getarg(0)); + .@size = getarraysize(getarg(0)) - .@index; + freeloop(true); + + if (isstr(getarg(0)) == 1) { + copyarray(.@tmp$[0], getarg(0), .@size); + for (; .@size >= 1; --.@size) { + set(getelementofarray(getarg(0), .@index + .@size - 1), array_shift(.@tmp$[rand(.@size)])); + } + } else { + copyarray(.@tmp[0], getarg(0), .@size); + for (; .@size >= 1; --.@size) { + set(getelementofarray(getarg(0), .@index + .@size - 1), array_shift(.@tmp[rand(.@size)])); + } + } + + freeloop(false); + return true; +} + + + +// array_unique(<array>{, <threshold>}) +// allows entries to appear up to <threshold> in the array + +function script array_unique { + .@size = getarraysize(getarg(0)); + .@max = getarg(1, 1); + freeloop(true); + + for (.@i = getarrayindex(getarg(0)); .@i < .@size; ++.@i) { + .@count = 1; + for (.@e = .@i + 1; .@e < .@size; ++.@e) { + if (getelementofarray(getarg(0), .@i) == getelementofarray(getarg(0), .@e)) { + if (++.@count >= .@max) { + deletearray(getelementofarray(getarg(0), .@e), 1); + ++.@removed; // increase counter + --.@size; // reduce size + --.@e; // step back + } + } + } + } + + freeloop(false); + return .@removed; +} + + + +// array_diff(<array1>, <array2>{, <array>...}, <array>) +// compares array1 against one or more other arrays and fills the last array +// with the values in array1 that are not present in any of the other arrays +// returns the number of entries not matching + +function script array_diff { + .@size = getarraysize(getarg(0)); + .@index = getarrayindex(getarg(0)); + freeloop(true); + + for (.@a = 1; .@a < (getargcount() - 1); ++.@a) { + for (.@i = .@index; .@i < .@size; ++.@i) { + if (!array_exists(getarg(.@a), getelementofarray(getarg(0), .@i))) { + array_push(getarg(getargcount() - 1), getelementofarray(getarg(0), .@i)); + ++.@count; + } + } + } + + freeloop(false); + return .@count; +} + + + +// array_filter(<array>, "<function>") +// filters the array using a callback function + +function script array_filter { + .@size = getarraysize(getarg(0)); + .@neq = getarg(2, false); + freeloop(true); + + for (.@i = getarrayindex(getarg(0)); .@i < .@size; ++.@i) { + .@eq = callfunc(getarg(1), getelementofarray(getarg(0), .@i)) != false; + if ((.@neq && .@eq) || (!(.@neq) && !(.@eq))) { + deletearray(getelementofarray(getarg(0), .@i), 1); // shift left + ++.@count; // increase the counter + --.@size; // reduce the size + --.@i; // step back + } + } + + freeloop(false); + return .@count; +} + +// array_highest(<array>) +// Returns the index of the highest value in <array> +// NOTE: Array must be an INT array! + +function script array_highest { + .@size = getarraysize(getarg(0)); + .@win=0; + .@idx=0; + .@dw=false; + freeloop(true); + + for (.@i = getarrayindex(getarg(0)); .@i < .@size; ++.@i) { + if (getelementofarray(getarg(0), .@i) > .@win) { + .@win=getelementofarray(getarg(0), .@i); + .@idx=.@i; + if (.@dw) { + deletearray .@draw; + .@dw=false; + } + } else if (getelementofarray(getarg(0), .@i) == .@win) { + if (!.@dw) + array_push(.@draw, .@idx); + array_push(.@draw, .@i); + .@dw=true; + } + } + + // Will we return .@idx or do we need to draw a loot? + freeloop(false); + if (.@dw) + return any_of(.@draw); + else + return .@idx; +} + +// relative_array_random(<array: 0, {[value, probability]..}>) +// returns a random entry from the array, by relative probability +// the first key of the array should be 0 and every entries are a tuple +// of [value, probability] + +function script relative_array_random { + .@is_str = getdatatype(getarg(0)) & DATATYPE_STR; + .@total_prob = getelementofarray(getarg(0), 0); + .@initial_index = getarrayindex(getarg(0)); + .@initial_index = .@initial_index ? .@initial_index : 1; + freeloop(true); + + if (.@total_prob < 1 || getarg(1, false)) + { + // first calculation, or forced re-calculation + .@total_prob = 0; + .@size = getarraysize(getarg(0)); + + for (.@i = .@initial_index + 1; .@i < .@size; .@i += 2) { + if (.@is_str) { + .@total_prob += max(1, atoi(getelementofarray(getarg(0), .@i))); + } else { + .@total_prob += max(1, getelementofarray(getarg(0), .@i)); + } + } + + // we cache on the first key + set(getelementofarray(getarg(0), 0), .@total_prob); + } + + .@target_sum = rand(0, .@total_prob); + + for (.@i = .@initial_index; .@sum < .@target_sum; .@i += 2) { + if (.@is_str) { + .@sum += atoi(getelementofarray(getarg(0), .@i + 1)); + } else { + .@sum += getelementofarray(getarg(0), .@i + 1); + } + + if (.@sum >= .@target_sum) { + break; + } + } + + freeloop(false); + return getelementofarray(getarg(0), .@i); +} + diff --git a/npc/functions/asklanguage.txt b/npc/functions/asklanguage.txt new file mode 100644 index 00000000..32e0f7bc --- /dev/null +++ b/npc/functions/asklanguage.txt @@ -0,0 +1,72 @@ +// TMW2 script +// Evol functions. +// Author: +// Reid, Jesusalva +// Description: +// Function setting the player language + +function script languagecode { + switch (Lang) { + case LANG_PTBR: + return "pt_BR"; + case LANG_FR: + return "fr"; + case LANG_DE: + return "de"; + case LANG_ES: + return "es"; + default: + return "en"; + } +} + +function script asklanguage { + + dispbottom col("We need help with translations. [@@help://translate|Learn more@@]", 1); + switch (getarg(0, LANG_IN_SHIP)) + { + case LANG_ON_SEA: + setarray .@messages$[0], "I hear you... (English)", // English + "Eu te ouço... (Português)", // Portuguese + "Je vous entends... (Français)", // French + "Ich höre euch... (Deutsch)", // German + "Te oigo... (Español)"; // Spanish + break; + case LANG_IN_SHIP: + setarray .@messages$[0], "I speak English.", // English + "Eu falo Português.", // Portuguese + "Je parle français.", // French + "Ich spreche Deutsch.", // German + "Hablo Español."; // Spanish + break; + default: + return; + } + + setarray .@flags$[0], "flags/en", + "flags/pt_BR", + "flags/fr", + "flags/de", + "flags/es"; + + .@menustr$ = ""; + .@separator$ = ":"; + + for (.@i = 0; .@i <= MAX_LANG; .@i++) + { + if (.@i == MAX_LANG) { + .@separator$ = ""; + } + .@menustr$ = .@menustr$ + .@flags$[.@i] + "|" + .@messages$[.@i] + .@separator$; + } + + select(.@menustr$); + + .@lang = @menu - 1; + + if (.@lang >= 0 || .@lang <= MAX_LANG) { + Lang = .@lang; + } + + return; +} diff --git a/npc/functions/filters.txt b/npc/functions/filters.txt new file mode 100644 index 00000000..01e3a856 --- /dev/null +++ b/npc/functions/filters.txt @@ -0,0 +1,126 @@ +// TMW2 scripts. +// Authors: +// Jesusalva +// Description: +// Several filters + +// filter_always( id ) +function script filter_always { + return true; +} + +// filter_onlyme( id ) +function script filter_onlyme { + return (getarg(0) == getcharid(3)); +} + +// filter_notme( id ) +function script filter_notme { + return (getarg(0) != getcharid(3)); +} + +// filter_sameguild( id ) +function script filter_sameguild { + if (getcharid(2) < 1) + return false; + return (strcharinfo(2, "~!<mk>@tmw2.org", getarg(0)) == strcharinfo(2)); +} + +// filter_sameguildnotyou( id ) +function script filter_sameguildnotyou { + if (getcharid(2) < 1) + return false; + if (getarg(0) == getcharid(3)) + return false; + return (strcharinfo(2, "~!<mk>@tmw2.org", getarg(0)) == strcharinfo(2)); +} + +// filter_sameparty( id ) +function script filter_sameparty { + if (getcharid(1) < 1 && getarg(0) != getcharid(3)) + return false; + return (strcharinfo(1, "~!<mk>@tmw2.org", getarg(0)) == strcharinfo(1)); +} + +// filter_sameguildorparty( id ) +function script filter_sameguildorparty { + if (getcharid(2) < 1 && getcharid(1) < 1) + return false; + .@party=(strcharinfo(1, "~!<mk>@tmw2.org", getarg(0)) == strcharinfo(1)); + .@guild=(strcharinfo(2, "~!<mk>@tmw2.org", getarg(0)) == strcharinfo(2)); + return ((getcharid(1) > 0 && .@party) || (getcharid(2) > 0 && .@guild)); +} + +// filter_sameguildorpartynotyou( id ) +function script filter_sameguildorpartynotyou { + if (getarg(0) == getcharid(3)) + return false; + if (getcharid(2) < 1 && getcharid(1) < 1) + return false; + .@party=(strcharinfo(1, "~!<mk>@tmw2.org", getarg(0)) == strcharinfo(1)); + .@guild=(strcharinfo(2, "~!<mk>@tmw2.org", getarg(0)) == strcharinfo(2)); + return ((getcharid(1) > 0 && .@party) || (getcharid(2) > 0 && .@guild)); +} + +// filter_hostile( id ) +function script filter_hostile { + //.@type=getunitdata(getarg(0), UDT_TYPE); + .@type=getunittype(getarg(0)); + .@chkid=getarg(0); + + // Players outside PVP + if (.@type == UNITTYPE_PC) { + getmapxy(.@m$, .@x, .@y, .@type, .@chkid); + if (!ispvpmap(.@m$)) + return false; + // FIXME: We already have !(filter_sameguildorparty()) + // We might be over-processing this + // Honor party flag + if (!getmapflag(.@mapa$, mf_pvp_noparty) && + getcharid(1) == getcharid(1, strcharinfo(0, "", .@chkid))) + return false; + // Honor guild flag + if (!getmapflag(.@mapa$, mf_pvp_noguild) && + getcharid(2) == getcharid(2, strcharinfo(0, "", .@chkid))) + return false; + } + + // Monsters + if (.@type == UNITTYPE_MOB) + return true; + + // NPCs + if (.@type == UNITTYPE_NPC) + return false; + + // Homunculus + if (.@type == UNITTYPE_HOM) + .@chkid=charid2rid(getunitdata(getarg(0), UDT_MASTERCID)); + + // Pets + if (.@type == UNITTYPE_PET) + .@chkid=getunitdata(getarg(0), UDT_MASTERAID); + + // Mercenaries + if (.@type == UNITTYPE_MER) + .@chkid=charid2rid(getunitdata(getarg(0), UDT_MASTERCID)); + + // Elementals + if (.@type == UNITTYPE_ELEM) + .@chkid=charid2rid(getunitdata(getarg(0), UDT_MASTERCID)); + + //debugmes "filter_hostile: Filtering %d (original %d) (BL %d)", .@chkid, getarg(0), .@type; + // Players (and slaves) + return !(filter_sameguildorparty(.@chkid)); +} + +// filter_friendly( id ) +function script filter_friendly { + return !(filter_hostile(getarg(0))); +} + +// filter_notboss( id ) +function script filter_notboss { + return (!(getunitdata(getarg(0), UDT_MODE) & MD_BOSS)); +} + diff --git a/npc/functions/goodbye.txt b/npc/functions/goodbye.txt new file mode 100644 index 00000000..b5214618 --- /dev/null +++ b/npc/functions/goodbye.txt @@ -0,0 +1,152 @@ +// Evol functions. +// Authors: +// gumi +// Reid +// Description: +// script terminator functions + + + +// goodbye_msg +// Tell a random goodbye sentence. +// Variables: +// .@rand = Random number between the number of "goodbye" choice. + +function script goodbye_msg { + setarray .byemsg$[0], + l("See you!"), + l("See you later!"), + l("See you soon!"), + l("Bye!"), + l("Farewell."), + l("Bye then!"), + l("Goodbye."), + l("Bye for now."), + l("Talk to you soon!"), + l("Talk to you later!"), + l("Have a good day!"), + l("Cheers!"), + l("Take care!"); + + return any_of(.byemsg$); +} + + + +// cwarp +// Closes the dialog, then warps the player. +// You almost always want to use this instead of `warp`. +// usage: +// cwarp; +// cwarp x, y; +// cwarp map, x, y; + +function script cwarp { + .@map$ = getarg(0, ""); + .@x = getarg(1, 0); + .@y = getarg(2, 0); + + if (getargcount() > 0 && getargcount() < 3) + { + .@npc$ = strnpcinfo(0); + .@map$ = getvariableofnpc(.map$, .@npc$); + .@x = getarg(0); + .@y = getarg(1); + } + + getmapxy .@pc_map$, .@pc_x, .@pc_y, UNITTYPE_PC; // get char location + + closedialog; // XXX: maybe send closeclientdialog in the future + + if (getargcount() < 1) + { + warp .@pc_map$, .@pc_x, .@pc_y; // no arguments, just refresh + close; + } + + if (.@map$ == .@pc_map$) + { + if (.@pc_x == .@x && .@pc_y == .@y) + { + close; // same location, don't move + } + + else + { + slide .@x, .@y; // same map, slide instead of full warp + close; + } + } + + warp .@map$, .@x, .@y; // different map, warp to given location + close; +} + + + +// cshop +// closes the dialog, then opens a shop +// if no npc is given, calls "#<npc> $" + +function script cshop { + closedialog; // XXX: maybe send closeclientdialog in the future + shop getarg(0, "#" + strnpcinfo(0) + " $"); + //close; => the shop buildin already sends close, and is a terminator itself +} + + + +// cstorage +// closes the dialog, then opens storage + +function script cstorage { + closedialog; // XXX: maybe send closeclientdialog in the future + openstorage; + close; +} + + + +// bye +// closes the dialog without waiting for the player to press close +// can also display an emote + +function script bye { + .@emote = getarg(0, -1); + closedialog; // XXX: maybe send closeclientdialog in the future + + if (.@emote >= 0) + emotion .@emote; + + close; +} + + + +// goodbye +// same as bye, but also displays a canned message +// can also display an emote + +function script goodbye { + npctalkonce(goodbye_msg()); + bye getarg(0, -1); +} + + + +// goodbye2 +// Waits for the player to press close, displays a canned message, +// ends execution. +// Can also display an emote + +function script goodbye2 { + .@emote = getarg(0, -1); + + close2; + npctalkonce(goodbye_msg()); + + if (.@emote >= 0) + emotion .@emote; + + end; +} diff --git a/npc/functions/inc_sc_bonus.txt b/npc/functions/inc_sc_bonus.txt new file mode 100644 index 00000000..8e6b6e5b --- /dev/null +++ b/npc/functions/inc_sc_bonus.txt @@ -0,0 +1,72 @@ +// TMW-2 Script. +// Author: +// Jesusalva +// Description: +// Applies effects for INC_* (STR doesn't exist) +// Valid values: INCAGI INCVIT INCINT INCDEX INCLUK INCHIT INCFLEE SC_FURY +// Doesn't works: SC_STRUP +// Works if .@min == .@max: INCMHP INCMHPRATE INCMSP INCMSPRATE +/// Untested Values: WALKSPEED (reverse logic) INVINCIBLE (broken) +// PS. SC_FURY causes crit rate to increase +// +// Variables: +// .@delay Second of buffing +// .@type SC_* +// .@min Min amount of type +// .@max Max amount of type (optional) + +// SC_Bonus(delay, SC, min{, max}) +function script SC_Bonus { + .@delay=getarg(0); + .@type=getarg(1); + .@min=getarg(2); + .@max=getarg(3, .@min); + if (.@delay <= 0) + return false; + + // Get the bonus value + if (.@min != .@max) + .@bonus=rand2(.@min, .@max); + else + .@bonus=.@min; + + // Remaining time and effect conversion + .@v=getstatus(.@type, 1); + .@t=getstatus(.@type, 5); + + // Convert remaining time to seconds, rounded down + if (.@t > 1000) + .@t=.@t/1000; + else + .@t=0; + + // If there was effect previously, get ponderate average + if (.@v > 0) + .@v=ponderate_avg(.@bonus, .@delay, .@v, .@t); + else + .@v=.@bonus; + + // Update time value to ms and to stack + .@t+=.@delay; + .@t*=1000; + + // Debug print if needed + if (debug || $@GM_OVERRIDE) + debugmes "Effect %d (+%d percent) for %d ms", .@type, .@bonus, .@t; + + // Restart the bonus + sc_end .@type; + sc_start .@type,.@t,.@v; + return true; +} + +- script inc_sc_bonus -1,{ +OnUse: + SC_Bonus(@delay, @type, @min, @max); + @delay=0; + @type=0; + @min=0; + @max=0; + end; +} + diff --git a/npc/functions/input.txt b/npc/functions/input.txt new file mode 100644 index 00000000..0a510b74 --- /dev/null +++ b/npc/functions/input.txt @@ -0,0 +1,110 @@ +// Evol functions. +// Author: +// 4144 +// Jesusalva +// Description: +// Input utility functions +// Variables: +// none + +function script menuint { + deletearray .@vals; + .@menustr$ = ""; + .@cnt = 0; + + for (.@f = 0; .@f < getargcount(); .@f = .@f + 2) + { + if (getarg(.@f) != "") + { + .@menustr$ = .@menustr$ + getarg(.@f) + ":"; + .@vals[.@cnt] = getarg(.@f + 1); + .@cnt ++; + } + } + + .@vals[.@cnt] = -1; + @menu = 255; + @menuret = -1; + select(.@menustr$); + if (@menu == 255) + return -1; + + @menu --; + if (@menu < 0 || @menu >= getarraysize(.@vals) - 1) + return -1; + + @menuret = .@vals[@menu]; + return @menuret; +} + +function script menustr { + deletearray .@vals$; + .@menustr$ = ""; + .@cnt = 0; + + for (.@f = 0; .@f < getargcount(); .@f = .@f + 2) + { + if (getarg(.@f) != "") + { + .@menustr$ = .@menustr$ + getarg(.@f) + ":"; + .@vals$[.@cnt] = getarg(.@f + 1); + .@cnt ++; + } + } + + @menu = 255; + @menuret = -1; + select(.@menustr$); + if (@menu == 255) + return ""; + + @menu --; + if (@menu < 0 || @menu >= getarraysize(.@vals$)) + return ""; + + @menuret$ = .@vals$[@menu]; + return @menuret$; +} + +// menuint2(<array>) +function script menuint2 { + .@menustr$=""; + + if (!(getdatatype(getarg(0)) & DATATYPE_VAR)) + Exception("Inadequate argument type - Must be var", RB_DEFAULT|RB_ISFATAL); + + copyarray(.@ar$, getarg(0), getarraysize(getarg(0))); + + if (getarraysize(.@ar$) % 2 != 0) + Exception("Invalid array size: "+getarraysize(.@ar$), RB_DEFAULT|RB_ISFATAL); + + freeloop(true); + for (.@f=0; .@f < getarraysize(.@ar$); .@f++) { + // String vs Int + if (.@f % 2 == 0) { + .@menustr$+=.@ar$[.@f]+":"; + } else { + array_push(.@vals, atoi(.@ar$[.@f])); + } + } + freeloop(false); + + // Do the request + // We have: .@vals and .@menustr$ + @menu = 255; + @menuret = -1; + select(.@menustr$); + //debugmes "Option %d", @menu; + //debugmes "Array size %d", getarraysize(.@vals); + + if (@menu == 255) + return -1; + + @menu-=1; + if (@menu < 0 || @menu > getarraysize(.@vals) - 1) + return -1; + + @menuret = .@vals[@menu]; + return @menuret; +} + diff --git a/npc/functions/inventoryplace.txt b/npc/functions/inventoryplace.txt new file mode 100644 index 00000000..76cdad21 --- /dev/null +++ b/npc/functions/inventoryplace.txt @@ -0,0 +1,36 @@ +// Evol functions. +// Authors: +// Qwerty Dragon +// Reid +// Description: +// Check if the player have enough place on his inventory to accept new items with arguments: +// getarg(even numbers) item ID, +// getarg(odd numbers) number of items, + +function script inventoryplace { + + .@argc = getargcount(); + + if (.@argc % 2 != 0) + { + Exception("inventoryplace: Wrong argument count.", RB_SPEECH|RB_ISFATAL|RB_PLEASEREPORT|RB_DEBUGMES); + } + + for (.@i = .@j = 0; .@i < .@argc; .@i += 2) + { + setarray .@item[.@j], getarg(.@i); + setarray .@amount[.@j], getarg(.@i + 1); + ++.@j; + } + + if (!checkweight2(.@item, .@amount)) + { + narrator S_FIRST_BLANK_LINE, + l("It looks like you can't carry anything else for now."), + l("You should come back when you have some free space."); + + close; + } + + return true; +} diff --git a/npc/functions/main.txt b/npc/functions/main.txt index a3e222e8..eac02526 100644 --- a/npc/functions/main.txt +++ b/npc/functions/main.txt @@ -307,6 +307,13 @@ function script die { 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 ///////////////////////////////////////////// @@ -602,33 +609,7 @@ function script registercmd { return; } -////////////////////////////////////////////////////////////////////// -// maptimer("<map>", <tick>, "<npc>::<event>") -function script maptimer { - .@c = getunits(BL_PC, .@players, false, getarg(0)); - for (.@i = 0; .@i < .@c; .@i++) { - addtimer(getarg(1), getarg(2), .@players[.@i]); - } - return .@i; -} - -// areatimer("<map>", <x1>, <y1>, <x2>, <y2>, <tick>, "<npc>::<event>") -function script areatimer { - // Legacy - if (getargcount() > 7) - .@ox=1; - // Variables - .@m$=getarg(.@ox); .@ox+=1; - .@x1=getarg(.@ox); .@ox+=1; - .@y1=getarg(.@ox); .@ox+=1; - .@x2=getarg(.@ox); .@ox+=1; - .@y2=getarg(.@ox); .@ox+=1; - .@tk=getarg(.@ox); .@ox+=1; - .@e$=getarg(.@ox); .@ox+=1; - .@c = getunits(BL_PC, .@players, false, .@m$, .@x1, .@y1, .@x2, .@y2); - for (.@i = 0; .@i < .@c; .@i++) { - addtimer(.@tk, .@e$, .@players[.@i]); - } - return .@i; +function script iscollision { + return checknpccell(getarg(0), getarg(1), getarg(2), cell_chkpass); } diff --git a/npc/functions/math.txt b/npc/functions/math.txt new file mode 100644 index 00000000..9c93fbb7 --- /dev/null +++ b/npc/functions/math.txt @@ -0,0 +1,123 @@ +// Evol functions. +// Authors: +// 4144 +// Reid +// Description: +// Math functions + + +// abs(<int>) +// returns the absolute value of the passed integer + +function script abs { + .@n = getarg(0); + return .@n >= 0 ? .@n : -.@n; +} + + + +// lognbaselvl({<multiplicator>{, <min value>}}) +// returns BaseLevel * logn (BaseLevel * alpha). + +function script lognbaselvl { + .@alpha = getarg(0, 1); + .@min = getarg(1, 1); + .@ret = 0; + .@pc_level = BaseLevel * .@alpha; + + while (.@pc_level >>= 1) + { + ++.@ret; + } + .@ret *= BaseLevel; + + if (.@ret <= .@min) + { + .@ret = .@min; + } + + return .@ret; +} + +// log2(<int>) +// returns the log base 2 of the passed integer, up to 20 (2**20=1.048.576) (round down always) + +function script log2 { + .@v=abs(getarg(0)); + .@ok=0; + .@i=0; + if (.@v < 1) + return -1; + + freeloop(true); + while (!.@ok) { + // exact match + if (2**.@i == .@v) { + .@ok=1; + // inexact match, or limit exceeded + } else if (2**.@i >= .@v || .@i > 20) { + .@ok=1; + .@i-=1; // round down + // not yet + } else { + .@i+=1; + } + } + freeloop(false); + + return .@i; +} + + +// result is: lower < target <= higher +// is_between ( lower, higher, target) +function script is_between { + .@val=getarg(2); + .@min=getarg(0); + .@max=getarg(1); + return (.@min < .@val && .@val <= .@max); +} + + +// forces the equation: lower <= target <= higher. +// Note it still works if higher and target values are swapped. +// limit ( lower, target, higher) +function script limit { + return max(getarg(0), min(getarg(1), getarg(2))); +} + + +// result is the ponderate average. +// ponderate_avg ( arg1, sub1, arg2, sub2) +function script ponderate_avg { + .@a1=getarg(0); + .@s1=getarg(1); + .@a2=getarg(2); + .@s2=getarg(3); + + .@h1=.@a1*.@s1; + .@h2=.@a2*.@s2; + .@dd=.@s1+.@s2; + + return (.@h1+.@h2)/.@dd; +} + +// bitmask_count(<int>) +// returns the number of bits set in <int> (max. 4096) + +function script bitmask_count { + .@n = getarg(0); // Number evaluated + .@p=0; // Bits set/unset + .@s=0; // Stack and Check + .@m=0; // Memory + + // Loop only as needed + while (.@s < .@n) { + .@s=2**.@m; + if (.@n & .@s) + .@p++; + .@m++; + } + return .@p; +} + diff --git a/npc/functions/npcmove.txt b/npc/functions/npcmove.txt new file mode 100644 index 00000000..612ab036 --- /dev/null +++ b/npc/functions/npcmove.txt @@ -0,0 +1,142 @@ +// Evol functions. +// Author: +// 4144 +// Description: +// Moving npc utility functions +// Variables: +// none + +function script initpath { + deletearray getvariableofnpc(.movepathcmd$, strnpcinfo(3)); + deletearray getvariableofnpc(.movepathy, strnpcinfo(3)); + deletearray getvariableofnpc(.movepathx, strnpcinfo(3)); + .@cnt = 0; + + for (.@f = 0; .@f < getargcount(); .@f = .@f + 3) + { + set getvariableofnpc(.movepathcmd$[.@cnt], strnpcinfo(3)), getarg(.@f); + set getvariableofnpc(.movepathx[.@cnt], strnpcinfo(3)), getarg(.@f + 1); + set getvariableofnpc(.movepathy[.@cnt], strnpcinfo(3)), getarg(.@f + 2); + .@cnt ++; + } + //debugmes "array size: " + str(getarraysize(getvariableofnpc(.movepath, strnpcinfo(3)))); + return; +} + +function script domoveaction { + //debugmes "domoveaction: " + str(getvariableofnpc(.movepos, strnpcinfo(3))); + .@pos = getvariableofnpc(.movepos, strnpcinfo(3)); + if (.@pos >= getarraysize(getvariableofnpc(.movepathx, strnpcinfo(3))) || .@pos < 0) + return; + //debugmes "walking"; + .@cmd$ = getvariableofnpc(.movepathcmd$[.@pos], strnpcinfo(3)); + //debugmes "cmd: " + .@cmd$; + + if (.@cmd$ == "move") + { + npcwalkto getvariableofnpc(.movepathx[.@pos], strnpcinfo(3)), getvariableofnpc(.movepathy[.@pos], strnpcinfo(3)); + } + else if (.@cmd$ == "dir") + { + setnpcdir getvariableofnpc(.movepathx[.@pos], strnpcinfo(3)); + return 2; + } + else if (.@cmd$ == "wait") + { + set getvariableofnpc(.waitticks, strnpcinfo(3)), getvariableofnpc(.movepathx[.@pos], strnpcinfo(3)); + } + else if (.@cmd$ == "emote") + { + unitemote getnpcid(), getvariableofnpc(.movepathx[.@pos], strnpcinfo(3)); + return 2; + } + else if (.@cmd$ == "class") + { + .class = getvariableofnpc(.movepathx[.@pos], strnpcinfo(3)); + return 2; + } + else if (.@cmd$ == "warp") + { + movenpc strnpcinfo(3), getvariableofnpc(.movepathx[.@pos], strnpcinfo(3)), getvariableofnpc(.movepathy[.@pos], strnpcinfo(3)); + } + else if (.@cmd$ == "goto") + { + set getvariableofnpc(.movepos, strnpcinfo(3)), getvariableofnpc(.movepathx[.@pos], strnpcinfo(3)); + return 0; + } + else if (.@cmd$ == "rmove") + { + getmapxy(.@mapName$, .@x, .@y, 1); + npcwalkto .@x + getvariableofnpc(.movepathx[.@pos], strnpcinfo(3)), .@y + getvariableofnpc(.movepathy[.@pos], strnpcinfo(3)); + } + else if (.@cmd$ == "speed") + { + .speed = getvariableofnpc(.movepathx[.@pos], strnpcinfo(3)); + return 2; + } + else if (.@cmd$ == "sit") + { + npcsit; + } + else if (.@cmd$ == "stand") + { + npcstand; + } + return 1; +} + +function script movetonextpos { + .@wait = getvariableofnpc(.waitticks, strnpcinfo(3)); + if (.@wait > 0) + { + .@wait --; + //debugmes "wait"; + set getvariableofnpc(.waitticks, strnpcinfo(3)), .@wait; + return; + } + .@true = 1; + while (.@true) + { + .@true = 0; + .@pos = getvariableofnpc(.movepos, strnpcinfo(3)); + //debugmes "movetonextpos: " + str(.@pos); + .@res = domoveaction(.@pos); + if (.@res == 1 || .@res == 2) + { + .@pos++; + if (.@pos >= getarraysize(getvariableofnpc(.movepathx, strnpcinfo(3)))) + .@pos = 0; + set getvariableofnpc(.movepos, strnpcinfo(3)), .@pos; + } + if (.@res == 0 || .@res == 2) + { + .@true = 1; + } + } + return; +} + +function script initialmove { + set getvariableofnpc(.movepos, strnpcinfo(3)), 0; + set getvariableofnpc(.waitticks, strnpcinfo(3)), -1; + movetonextpos; + return; +} + +function script getmovecmd { + .@pos = getvariableofnpc(.movepos, strnpcinfo(3)); + if (.@pos >= getarraysize(getvariableofnpc(.movepathx, strnpcinfo(3))) || .@pos < 0) + return ""; + return getvariableofnpc(.movepathcmd$[.@pos], strnpcinfo(3)); +} + +function script domovestep { + if (isunitwalking()) + { + initnpctimer; + end; + } + movetonextpos; + initnpctimer; + end; +} diff --git a/npc/functions/npcmovegraph.txt b/npc/functions/npcmovegraph.txt new file mode 100644 index 00000000..0877b748 --- /dev/null +++ b/npc/functions/npcmovegraph.txt @@ -0,0 +1,489 @@ +// Evol functions. +// Author: +// Travolta +// Description: +// Moving npc utility functions (graph-based) +// Variables: +// none + +function script initmovegraph { + deletearray getvariableofnpc(.movegraphcmd$, strnpcinfo(3)); + deletearray getvariableofnpc(.movegraphlabels$, strnpcinfo(3)); + deletearray getvariableofnpc(.movegraphweight, strnpcinfo(3)); + deletearray getvariableofnpc(.movegraphflags, strnpcinfo(3)); + deletearray getvariableofnpc(.movepos_y1, strnpcinfo(3)); + deletearray getvariableofnpc(.movepos_x1, strnpcinfo(3)); + deletearray getvariableofnpc(.movepos_x2, strnpcinfo(3)); + deletearray getvariableofnpc(.movepos_y2, strnpcinfo(3)); + .@cnt = 0; + + for (.@f = 0; .@f < getargcount();) + { + set getvariableofnpc(.movegraphlabels$[.@cnt], strnpcinfo(3)), getarg(.@f++); + set getvariableofnpc(.movepos_x1[.@cnt], strnpcinfo(3)), getarg(.@f++); + set getvariableofnpc(.movepos_y1[.@cnt], strnpcinfo(3)), getarg(.@f++); + if (!isstr(getarg(.@f, "label"))) + { + set getvariableofnpc(.movepos_x2[.@cnt], strnpcinfo(3)), getarg(.@f++); + set getvariableofnpc(.movepos_y2[.@cnt], strnpcinfo(3)), getarg(.@f++); + } + .@cnt ++; + } + return; +} + +function script findmovegraphlabel { + if (!getargcount()) + { + debugmes "findmovegraphlabel: no argument"; + return -1; + } + if (!isstr(getarg(0))) + { + debugmes "findmovegraphlabel: need string argument"; + return -1; + } + + .@arg$ = getarg(0); + for (.@i = 0; .@i < getarraysize(getvariableofnpc(.movegraphlabels$, strnpcinfo(3))); .@i++) + { + if (getvariableofnpc(.movegraphlabels$[.@i], strnpcinfo(3)) == .@arg$) + return .@i; + } + + npcdebug "findmovegraphlabel: label not found: " + getarg(0); + return -1; +} + +/* setmovegraphcmd(fromPositionLabel,toPositionLabel[,moveChanceWeight[,moveFlags]],postCommand, ...); + * This function manipulates NPC moving graph. Before calling it, make sure + * `initmovegraph' was called. The function accepts 3-5 parameters (many times): + * fromPositionLabel, toPositionLabel -- starting and ending position of NPC move + * moveChanceWeight -- positive integer, represents the chance of moving in given direction. (optional) + * moveFlags -- if .mg_flags & moveFlags != 0, move is possible. (optional) + * postCommand -- either "moveon" (start moving to next location straight after arriving from + * fromPositionLabel to toPositionLabel) or a semicolon-separated set of commands + * ("wait 3", "emote 5" etc, see `execmovecmd') that will be executed after arrival. + * The commands don't have to end with ";moveon", it's executed in the end by default. + */ +function script setmovegraphcmd { + .@size = getarraysize(getvariableofnpc(.movepos_x1, strnpcinfo(3))); + + for (.@f = 0; .@f < getargcount();) + { + .@from = findmovegraphlabel(getarg(.@f++)); + .@to = findmovegraphlabel(getarg(.@f++)); + .@weight = 1; + if (!isstr(getarg(.@f))) + .@weight = getarg(.@f++); + .@flags = 0xffff; + if (!isstr(getarg(.@f))) + .@flags = getarg(.@f++); + .@cmd$ = getarg(.@f++); + .@index = .@from * .@size + .@to; // emulation of 2d array + set getvariableofnpc(.movegraphcmd$[.@index], strnpcinfo(3)), .@cmd$; + set getvariableofnpc(.movegraphweight[.@index], strnpcinfo(3)), .@weight; + set getvariableofnpc(.movegraphflags[.@index], strnpcinfo(3)), .@flags; + } + return; +} + +function script execmovecmd { + + explode(.@cmd$, getarg(0), " "); + + if (.@cmd$[0] == "moveon") + { + return 0; + } + else if (.@cmd$[0] == "dir") + { + .dir = atoi(.@cmd$[1]); + } + else if (.@cmd$[0] == "sit") + { + npcsit; + } + else if (.@cmd$[0] == "stand") + { + npcstand; + } + else if (.@cmd$[0] == "wait") + { + set getvariableofnpc(.waitticks, strnpcinfo(3)), atoi(.@cmd$[1]); + return 1; + } + else if (.@cmd$[0] == "emote") + { + unitemote getnpcid(), atoi(.@cmd$[1]); + } + else if (.@cmd$[0] == "class") + { + .class = atoi(.@cmd$[1]); + } + else if (.@cmd$[0] == "warp") + { + .@pos = -1; + .@map$ = ""; + .@pos_idx = 1; + if (getarraysize(.@cmd$) == 3) + { + .@map$ = .@cmd$[1]; + .@pos_idx = 2; + } + .@pos = findmovegraphlabel(.@cmd$[.@pos_idx]); + if (.@pos != -1) + { + .@x = getvariableofnpc(.movepos_x1[.@pos], strnpcinfo(3)); + .@y = getvariableofnpc(.movepos_y1[.@pos], strnpcinfo(3)); + if (getstrlen(.@map$) > 0) + unitwarp getnpcid(), .@map$, .@x, .@y; + else + movenpc strnpcinfo(3), .@x, .@y; + set getvariableofnpc(.movepos, strnpcinfo(3)), .@pos; + } + else + { + debugmes "execmovecmd: unknown WARP destination label: " + .@cmd$[1]; + } + } + else if (.@cmd$[0] == "call") + { + switch (getarraysize(.@cmd$)) + { + case 1: + debugmes "execmovecmd: CALL command needs some parameters"; + return 0; + case 2: + return callfunc(.@cmd$[1]); + break; + case 3: + return callfunc(.@cmd$[1], .@cmd$[2]); + case 4: + default: + return callfunc(.@cmd$[1], .@cmd$[2], .@cmd$[3]); + } + } + else if (.@cmd$[0] == "speed") + { + .speed = atoi(.@cmd$[1]); + } + else if (.@cmd$[0] == "say") + { + deletearray .@cmd$[0], 1; + .@msg$=implode(.@cmd$, " "); + if (.@msg$ != "" && .@msg$ != " ") + npctalk .@msg$; + else + debugmes "Invalid message passed to execmovecmd/npctalk"; + } + else if (.@cmd$[0] == "debugmes") + { + deletearray .@cmd$[0], 1; + debugmes implode(.@cmd$, " "); + } + else if (.@cmd$[0] == "flags") + { + set getvariableofnpc(.mg_flags, strnpcinfo(3)), axtoi(.@cmd$[1]); + } + else if (.@cmd$[0] == "flags_0") + { + .@flags = getvariableofnpc(.mg_flags, strnpcinfo(3)); + .@flags &= ~axtoi(.@cmd$[1]); + set getvariableofnpc(.mg_flags, strnpcinfo(3)), .@flags; + } + else if (.@cmd$[0] == "flags_1") + { + .@flags = getvariableofnpc(.mg_flags, strnpcinfo(3)); + .@flags |= axtoi(.@cmd$[1]); + set getvariableofnpc(.mg_flags, strnpcinfo(3)), .@flags; + } + else + { + debugmes "Unknown move graph cmd: " + .@cmd$[0]; + } + return 0; +} + +function script getnextmovecmd { + .@cmds$ = getvariableofnpc(.nextcmd$, strnpcinfo(3)); + .@firstCmd$ = .@cmds$; + .@restCmd$ = "moveon"; + .@index = strpos(.@cmds$, ";"); + if (.@index >= 0) + { + .@firstCmd$ = substr(.@cmds$, 0, .@index - 1); + .@restCmd$ = substr(.@cmds$, .@index + 1, getstrlen(.@cmds$) - 1); + } + // npcdebug "firstCmd = " + .@firstCmd$ + " restCmd = " + .@restCmd$; + set getvariableofnpc(.nextcmd$, strnpcinfo(3)), .@restCmd$; + return strip(.@firstCmd$); +} + +// getrandompoint(x1,y1,x2,y2) +// -- Get a random walkable point within a map rectangle +// x1, y1 -- top-left corner of rectangle +// x2, y2 -- bottom-right corner of rectangle +// Returns 0 on success and -1 on error; +// Since we cannot return multiple values, the random +// coordinates are stored in NPC variables .move__rand_x, .move__rand_y +function script getrandompoint { + if (getargcount() < 4) + { + debugmes "error: getrandompoint(x1, y1, x2, y2) takes 4 arguments"; + return -1; + } + + .@max_pokes = 10; + .@x1 = getarg(0); + .@y1 = getarg(1); + .@x2 = getarg(2); + .@y2 = getarg(3); + .@rx = -1; .@ry = -1; + + getmapxy(.@map$, .@cx, .@cy, 1); // npc location + + // let's try max_pokes random cells + for (.@poke = 0; .@poke < .@max_pokes; .@poke++) + { + .@rx = rand(.@x1, .@x2); + .@ry = rand(.@y1, .@y2); + if (checknpccell(.@map$, .@rx, .@ry, cell_chkpass)) + goto L_Found; + } + + // we check each cell from random middle point to the end + for (;.@rx <= .@x2; .@rx++) + { + for (;.@ry <= .@y2; .@ry++) + if (checknpccell(.@map$, .@rx, .@ry, cell_chkpass)) + goto L_Found; + .@ry = .@y1; + } + + // we check the rectangle from beginning to end + for (.@rx = .@x1; .@rx <= .@x2; .@rx++) + for (.@ry = .@y1; .@ry <= .@y2; .@ry++) + if (checknpccell(.@map$, .@rx, .@ry, cell_chkpass)) + goto L_Found; + + // finally, if we don't find anything + debugmes "error: getrandompoint: cannot find walkable cell in rectangle [(" + .@x1 + "," + .@y1 + ") , (" + .@x2 + "," + .@y2 + ")]"; + return -1; + +L_Found: + set getvariableofnpc(.move__rand_x, strnpcinfo(3)), .@rx; + set getvariableofnpc(.move__rand_y, strnpcinfo(3)), .@ry; + return 0; +} + +// wrapper function for npcwalkto. It can accept 4 parameters. +// If #3 and #4 params are set, the walkto location is chosen +// from rectangle (x1,y1,x2,y2). +// It sets the npc variables .move_target_x, .move_target_y +// that are used to resume NPC walking +// Returns 1 if walking is possible, 0 otherwise; +function script mg_npcwalkto { + if (getargcount() < 2) + { + debugmes "usage: mg_npcwalkto(x1,y1[,x2,y2])"; + return -1; + } + + .@x = getarg(0); + .@y = getarg(1); + .@x2 = getarg(2); + .@y2 = getarg(3); + + if (getargcount() >= 4 && .@x2 > 0 && .@y2 > 0) + if (!getrandompoint(.@x, .@y, .@x2, .@y2)) + { + .@x = getvariableofnpc(.move__rand_x, strnpcinfo(3)); + .@y = getvariableofnpc(.move__rand_y, strnpcinfo(3)); + } + else + return 0; + + if (npcwalkto(.@x, .@y)) + { + set getvariableofnpc(.move_target_x, strnpcinfo(3)), .@x; + set getvariableofnpc(.move_target_y, strnpcinfo(3)), .@y; + return 1; + } + return 0; +} + +function script movetonextpoint { + .@wait = getvariableofnpc(.waitticks, strnpcinfo(3)); + if (.@wait > 0) + { + .@wait--; + set getvariableofnpc(.waitticks, strnpcinfo(3)), .@wait; + return; + } + + .@nextcmd$ = ""; + while (.@nextcmd$ != "moveon") + { + .@nextcmd$ = getnextmovecmd(); + npcdebug " " + .@nextcmd$; + if (execmovecmd(.@nextcmd$)) + return; + } + + // choose a random path from all possible paths + .@size = getarraysize(getvariableofnpc(.movepos_x1, strnpcinfo(3))); + .@pos = getvariableofnpc(.movepos, strnpcinfo(3)); + .@curr_flags = getvariableofnpc(.mg_flags, strnpcinfo(3)); + .@cur = 0; + .@weight_sum = 0; + // .@dbg$ = getvariableofnpc(.movegraphlabels$[.@pos], strnpcinfo(3)) + ": "; + + for (.@i = 0; .@i < .@size; .@i++) + { + .@index = .@pos * .@size + .@i; + .@cmd$ = getvariableofnpc(.movegraphcmd$[.@index], strnpcinfo(3)); + .@flags = getvariableofnpc(.movegraphflags[.@index], strnpcinfo(3)); + if (.@cmd$ != "" && + .@curr_flags & .@flags) + { + .@nextpos[.@cur] = .@i; + .@weights[.@cur] = getvariableofnpc(.movegraphweight[.@index], strnpcinfo(3)); + // .@dbg$ += getvariableofnpc(.movegraphlabels$[.@i], strnpcinfo(3)) + "=" + .@weights[.@cur] + " "; + .@weight_sum += .@weights[.@cur]; + .@cur++; + } + } + // npcdebug .@dbg$; + + if (!.@weight_sum) + { + npcdebug("error: cannot pick next walk point. flags=" + + getvariableofnpc(.mg_flags, strnpcinfo(3))); + return; + } + + .@pick_tries = 0; +L_TryPick: + // pick a random number based on weight_sum + .@rnd = rand(.@weight_sum); + .@k = -1; .@weight_sum = 0; + while (.@rnd >= .@weight_sum) + { + .@k++; + .@weight_sum += .@weights[.@k]; + } + + .@next_idx = .@nextpos[.@k]; + .@next_x1 = getvariableofnpc(.movepos_x1[.@next_idx], strnpcinfo(3)); + .@next_y1 = getvariableofnpc(.movepos_y1[.@next_idx], strnpcinfo(3)); + .@next_x2 = getvariableofnpc(.movepos_x2[.@next_idx], strnpcinfo(3)); + .@next_y2 = getvariableofnpc(.movepos_y2[.@next_idx], strnpcinfo(3)); + + if (!mg_npcwalkto(.@next_x1, .@next_y1, .@next_x2, .@next_y2)) + { + if (.@pick_tries < 10) + { + .@pick_tries++; + goto L_TryPick; + } + + // move to a nearby position + .@x1 = getvariableofnpc(.movepos_x1[.@pos], strnpcinfo(3)); + .@y1 = getvariableofnpc(.movepos_y1[.@pos], strnpcinfo(3)); + .@x2 = getvariableofnpc(.movepos_x2[.@pos], strnpcinfo(3)); + .@y2 = getvariableofnpc(.movepos_y2[.@pos], strnpcinfo(3)); + mg_npcwalkto(.@x1, .@y1, .@x2, .@y2); + set getvariableofnpc(.nextcmd$, strnpcinfo(3)), "wait 1"; + + return; + } + + if (getvariableofnpc(.debug, strnpcinfo(3))) + { + getmapxy(.@map$, .@cx, .@cy, 1); + .@dist = distance(.@cx, .@cy, .@next_x1, .@next_y1); + npcdebug("moving to " + getvariableofnpc(.movegraphlabels$[.@next_idx], strnpcinfo(3)) + + " ("+ getvariableofnpc(.move_target_x, strnpcinfo(3)) + + "," + getvariableofnpc(.move_target_y, strnpcinfo(3)) + + ") [distance=" + .@dist + + "] flags=" + getvariableofnpc(.mg_flags, strnpcinfo(3))); + } + + .@nextcmd$ = getvariableofnpc(.movegraphcmd$[.@pos * .@size + .@next_idx], strnpcinfo(3)); + set getvariableofnpc(.nextcmd$, strnpcinfo(3)), .@nextcmd$; + set getvariableofnpc(.movepos, strnpcinfo(3)), .@next_idx; + return; +} + +// initial actions for npc when using move graphs. +// function can accept 2 arguments: +// 1: action sequence, for example "speed 200; dir 4". Default is "moveon" +// 2: start point label. Default is #0 from move graph labels +function script firstmove { + .@nextcmd$ = getarg(0, "moveon"); + .@initpos = findmovegraphlabel(getarg(1, "")); + if (.@initpos < 0) .@initpos = 0; + + set getvariableofnpc(.movepos, strnpcinfo(3)), .@initpos; + movenpc strnpcinfo(3), getvariableofnpc(.movepos_x1[.@initpos], strnpcinfo(3)), + getvariableofnpc(.movepos_y1[.@initpos], strnpcinfo(3)); + set getvariableofnpc(.nextcmd$, strnpcinfo(3)), .@nextcmd$; + set getvariableofnpc(.waitticks, strnpcinfo(3)), -1; + set getvariableofnpc(.mg_flags, strnpcinfo(3)), 0xffff; + movetonextpoint; + return; +} + +function script npc_pausemove { + stopnpctimer; + .@move_after = 0; + + if (isunitwalking()) + { + .@move_after = 1; + npcwalkto .x, .y; + npcstop; + } + set getvariableofnpc(.move_after_pause, strnpcinfo(3)), .@move_after; + + return 0; +} + +function script npc_resumemove { + startnpctimer; + + if (getvariableofnpc(.move_after_pause, strnpcinfo(3))) + { + .@x = getvariableofnpc(.move_target_x, strnpcinfo(3)); + .@y = getvariableofnpc(.move_target_y, strnpcinfo(3)); + npcwalkto .@x, .@y; + } + + return 0; +} + +// npc_turntoxy(x,y) +// turn npc toward an object at position (x,y) +function script npc_turntoxy { + .@target_x = getarg(0); + .@target_y = getarg(1); + .@dx = abs(.@target_x - .x); + .@dy = abs(.@target_y - .y); + + if (.@dx > .@dy) + .dir = .@target_x >= .x ? 6 : 2; + else + .dir = .@target_y >= .y ? 0 : 4; + + return 0; +} + +function script dographmovestep { + if (!isunitwalking()) + { + movetonextpoint; + } + initnpctimer; + end; +} diff --git a/npc/functions/permissions.txt b/npc/functions/permissions.txt new file mode 100644 index 00000000..96e69fde --- /dev/null +++ b/npc/functions/permissions.txt @@ -0,0 +1,35 @@ +// Evol scripts. +// Author: +// gumi +// Description: +// checks player permissions +// ** admins are implicitly everything + +// administrator +function script is_admin { + return has_permission(PERM_USE_ALL_COMMANDS, getarg(0, getcharid(CHAR_ID_ACCOUNT))); +} + +// any staff member +function script is_trusted { + return is_admin(getarg(0, getcharid(CHAR_ID_ACCOUNT))) || + has_permission("show_client_version", getarg(0, getcharid(CHAR_ID_ACCOUNT))); +} + +// developer +function script is_dev { + return is_admin(getarg(0, getcharid(CHAR_ID_ACCOUNT))) || + has_permission(PERM_RECEIVE_REQUESTS, getarg(0, getcharid(CHAR_ID_ACCOUNT))); +} + +// event coordinator +function script is_evtc { + return is_admin(getarg(0, getcharid(CHAR_ID_ACCOUNT))) || + can_use_command("@monster", getarg(0, getcharid(CHAR_ID_ACCOUNT))); +} + +// game master +function script is_gm { + return is_admin(getarg(0, getcharid(CHAR_ID_ACCOUNT))) || + can_use_command("@jail", getarg(0, getcharid(CHAR_ID_ACCOUNT))); +} diff --git a/npc/functions/random-talk.txt b/npc/functions/random-talk.txt new file mode 100644 index 00000000..e6b6bee8 --- /dev/null +++ b/npc/functions/random-talk.txt @@ -0,0 +1,207 @@ +// TMW2 Script +// Author: +// Jesusalva +// Description: +// Random dialog for various random NPCs. + +// Functions: +// hello +// moubootalk +// villagertalk +// sailortalk +// legiontalk +// asleep + +// Evol authors (some strings and code): +// Reid +// Akko Teru +// Qwerty Dragon + +function script hello { + + switch (rand2(3)) { + case 0: + npctalkonce(l("Heya!")); + break; + case 1: + npctalkonce(l("Hi.")); + break; + case 2: + if ($EVENT$ == "Christmas") + npctalkonce(l("Merry Christmas!")); + else + npctalkonce(l("Nice day to you.")); + break; + } + + return; +} + +function script moubootalk { + switch (rand2(4)) { + case 0: + npctalkonce(l("Moooooo!")); + break; + case 1: + npctalkonce(l("Moo!")); + break; + case 2: + npctalkonce(l("Moooooooooooo!")); + break; + case 3: + npctalkonce(l("Moooo!")); + break; + } + return; +} + +function script sailortalk { + + .@rand = rand2(8); + if (.@rand == 0) goodbye; + if (.@rand == 1) npctalkonce(l("Arr, I'm bored!")); + if (.@rand == 2) npctalkonce(l("Hey! Good to hear from you!")); + if (.@rand == 3) npctalkonce(l("Yarr arr!")); + if (.@rand == 4) { + if ($EVENT$ == "Christmas") + npctalkonce(l("Merry Christmas, arr yarr!!")); + else { + speech( + l("A sunny and hot day,"), + l("a quiet place,"), + l("a ground!"), + l("What else do you need?")); + } + close; + } + if (.@rand == 5) npctalkonce(l("A-hoy matey!")); + if (.@rand == 6) npctalkonce(l("Arr!")); + if (.@rand == 7) npctalkonce(l("Howdy?")); + + // just to be sure + closedialog; + close; + end; +} + +function script villagertalk { + + function darn_or_smile { + .@darn = rand(42); + + if (.@darn < 26) { + emotion E_JOY; + hello; + } else if (.@darn > 26) { + emotion E_LOOKAWAY; + goodbye; + } else { + npctalkonce(l("Stop it!")); + } + return; + } + + switch (rand2(4)) { + case 0: + darn_or_smile(); + break; + case 1: + npctalkonce(l("It is a sunny day, don't you think?")); + break; + case 2: + npctalkonce(l("Go fly a kite.")); + break; + case 3: + npctalkonce(l("I just want to live my life in peace.")); + break; + default: + emotion E_HAPPY; + break; + } + + return; +} + +function script legiontalk { + switch (rand2(15)) { + case 0: + npctalkonce(l("Do I look like a tree? I feel like one.")); + //speech( + // l("Do you feel too weak even to do damage to this areas wishy-washy wildlife?"), + // l("Then concentrate your anger upon the trees hereabouts, you will gain experience whilst leveling your sword skill on them."), + // l("Oh, and a fruit may even fall for you if you are lucky! But stay alert to pick up your drops.")); + //close; + break; + case 1: + npctalkonce(l("I'm a little busy right now.")); + break; + case 2: + npctalkonce(l("Not in the mood to chat.")); + break; + case 3: + npctalkonce(l("My breath smells bad.")); + break; + case 4: + npctalkonce(l("Don't distract me, I have to stay alert.")); + break; + case 5: + npctalkonce(l("Give me some space.")); + break; + case 6: + if ($EVENT$ == "Christmas") + npctalkonce(l("Merry Christmas, adventurer.")); + else + npctalkonce(l("Can you please go away?")); + break; + case 7: + npctalkonce(l("Can't talk right now, I'm on patrol duty.")); + break; + case 8: + npctalkonce(l("What're you looking at?!")); + break; + case 9: + npctalkonce(l("I can't stay here and talk all day. I have a job to do.")); + break; + case 10: + npctalkonce(l("Keep moving pal.")); + break; + case 11: + npctalkonce(l("So you think you're tough? A warrior must also be loyal and patient.")); + break; + case 12: + emotion E_LOOKAWAY; + break; + case 13: + npctalkonce(l("Practice! There are no secrets to becoming a warrior.")); + break; + case 14: + npctalkonce(l("There is no honor in fighting a weak opponent.")); + break; + } + + return; +} + +function script asleep { + switch(rand2(5)) { + case 0: npctalkonce(l("Zzzzzzzzz...")); break; + case 1: npctalkonce(l("Rrrr... Pchhhh...")); break; + case 2: npctalkonce(l("Ggrmm... Grmmmm...")); break; + case 3: npctalkonce(l("Hm... Shhhh...")); break; + default: emotion(E_SLEEPY); + } + end; +} + +function script studenttalk { + switch(rand2(6)) { + case 0: npctalkonce(l("I want to sleep...")); break; + case 1: npctalkonce(l("I have homework to do...")); break; + case 2: npctalkonce(l("I need to finish studying for my test...")); break; + case 3: npctalkonce(l("Ah, the Professors will get mad at me again...")); break; + case 4: npctalkonce(l("I'm a little busy right now.")); break; + + default: emotion(E_SLEEPY); + } + end; +} diff --git a/npc/functions/string.txt b/npc/functions/string.txt new file mode 100644 index 00000000..2a38d90d --- /dev/null +++ b/npc/functions/string.txt @@ -0,0 +1,211 @@ +// Evol Script +// Author: Gumi + +// safe string manipulation functions +// ** does not require PCRE + + +// str(<int>) +// returns whatever is passed, converted to string + +function script str { + return "" + getarg(0); +} + + + +// startswith("<string>", "<search>") +// returns true if <string> begins with <search> + +function script startswith { + return substr(getarg(0), 0, getstrlen(getarg(1)) - 1) == getarg(1); +} + + + +// endswith("<string>", "<search>") +// returns true if <string> ends with <search> + +function script endswith { + .@t = getstrlen(getarg(0)); // total length + .@n = getstrlen(getarg(1)); // substring length + return substr(getarg(0), .@t - .@n, .@t - 1) == getarg(1); +} + + + +// capitalize("<string>") +// returns <string> with its first letter capitalized + +function script capitalize { + return setchar(getarg(0), strtoupper(charat(getarg(0), 0)), 0); +} + + + +// titlecase("<string>" {, "<delimiter>" {, <camel>}}) +// returns <string> with the first letter of each word capitalized +// if <camel> is true, the string is joined in a camelCase fashion + +function script titlecase { + .@delimiter$ = getarg(1, " "); + .@c = getarg(2, 0); + explode(.@words$, getarg(0), .@delimiter$); + + for (.@i = (.@c ? 1 : 0); .@i < 255; ++.@i) + { + if (.@words$[.@i] == "") + { + break; + } + + .@words$[.@i] = setchar(.@words$[.@i], strtoupper(charat(.@words$[.@i], 0)), 0); + } + + return implode(.@words$, (.@c ? "" : .@delimiter$)); +} + + + +// camelcase("<string" {, "<delimiter>"}) + +function script camelcase { + return titlecase(getarg(0), getarg(1, " "), true); +} + + + +// zfill("<string>" {, <width> {, "<padding>"}}) +// returns <string> padded to the left with <padding> up to width + +function script zfill { + .@str$ = getarg(0); + .@width = getarg(1, 8); + .@padding$ = getarg(2, "0"); + + for (.@s = getstrlen(.@str$); .@s < .@width; ++.@s) + { + .@str$ = .@padding$ + .@str$; + } + + return .@str$; +} + + + +// format_number(<integer> {, "<separator>"}) +// formats a number properly + +function script format_number { + .@number$ = str(getarg(0)); + .@len = getstrlen(.@number$); + .@separator$ = getarg(1, ","); + + if (getargcount() < 2 && playerattached()) { + // get from user language + switch (Lang) { + case LANG_FR: .@separator$ = " "; break; // French + case LANG_DE: .@separator$ = "."; break; // Germanic + case LANG_PTBR: .@separator$ = "."; break; // Brazilian + default: .@separator$ = ","; // English (default) + } + } + + for (.@i = .@len - 3; .@i > 0; .@i -= 3) { + .@number$ = insertchar(.@number$, .@separator$, .@i); + } + + return .@number$; +} + + + +// fnum(<integer>) +// alias for format_number + +function script fnum { + return format_number(getarg(0)); +} + + + +// strip("<string>") +// removes spaces at the start and end + +function script strip { + .@s$ = getarg(0); + if (.@s$ == "") { + return ""; + } + .@start = 0; + .@end = getstrlen(.@s$) - 1; + for (.@i = .@start; .@i < .@end; .@i++) + { + if (charat(.@s$, .@i) != " ") { + break; + } else { + .@start++; + } + } + for (.@i = .@end; .@i >= .@start; .@i--) + { + if (charat(.@s$, .@i) != " ") { + break; + } else { + .@end--; + } + } + //debugmes "STRIP.DEBUG MODE ENABLED BY JESUSALVA. PASSING SUBSTRING PARAMS"; + //debugmes "String \""+.@s$+"\" from "+str(.@start)+" to "+str(.@end); + return substr(.@s$, .@start, .@end); +} + + + +// reverse("<string>") +// returns <string> reversed + +function script reverse { + .@str$ = getarg(0); + .@len = getstrlen(.@str$); + + for (.@i = 0; .@i < (.@len / 2); ++.@i) { + .@tmp$ = charat(.@str$, .@i); + .@str$ = setchar(.@str$, charat(.@str$, (.@len - 1 - .@i)), .@i); // a <= b + .@str$ = setchar(.@str$, .@tmp$, (.@len - 1 - .@i)); // b <= a + } + + return .@str$; +} + + + +// repeat("<string>", <multiplier>) +// repeats <string> many times and returns it + +function script repeat { + .@mul = getarg(1); + + for (.@i = 0; .@i < .@mul; ++.@i) { + .@str$ += getarg(0); + } + + return .@str$; +} + + + +// shuffle("<string>") +// returns <string> shuffled + +function script shuffle { + .@str$ = getarg(0); + + for (.@len = getstrlen(.@str$); .@len > 0; --.@len) { + .@rnd = rand(.@len); + .@out$ += charat(.@str$, .@rnd); + .@str$ = delchar(.@str$, .@rnd); + } + + return .@out$; +} diff --git a/npc/functions/time.txt b/npc/functions/time.txt index 21b94ac5..e6e4c70a 100755 --- a/npc/functions/time.txt +++ b/npc/functions/time.txt @@ -1,159 +1,117 @@ +// Evol Script +// Authors: Gumi, Jesusalva +function script now { + return gettimetick(2); +} -function script time_stamp { - // local variables - // if there is reasonable demand, these might be exported - // (that is what the builtin is likely to do) - @ts_year = gettime(7); - @ts_month = gettime(6); - @ts_mday = gettime(5); - //set @ts_wday, gettime(4); - @ts_hour = gettime(3); - @ts_minute = gettime(2); - @ts_second = gettime(1); - - // locals used to generate leading zeroes - @ts_month_pad$ = ""; - @ts_mday_pad$ = ""; - @ts_hour_pad$ = ""; - @ts_minute_pad$ = ""; - @ts_second_pad$ = ""; - - if (@ts_month < 10) - @ts_month_pad$ = "0"; - if (@ts_mday < 10) - @ts_mday_pad$ = "0"; - if (@ts_hour < 10) - @ts_hour_pad$ = "0"; - if (@ts_minute < 10) - @ts_minute_pad$ = "0"; - if (@ts_second < 10) - @ts_second_pad$ = "0"; - - @ts_date$ = @ts_year + "-" + @ts_month_pad$ + @ts_month + "-" + @ts_mday_pad$ + @ts_mday; - @ts_time$ = @ts_hour_pad$ + @ts_hour + ":" + @ts_minute_pad$ + @ts_minute + ":" +@ts_second_pad$ + @ts_second; - - // cleanup - @ts_year = 0; - @ts_month = 0; - @ts_mday = 0; - @ts_hour = 0; - @ts_minute = 0; - @ts_second = 0; - @ts_month_pad$ = ""; - @ts_mday_pad$ = ""; - @ts_hour_pad$ = ""; - @ts_minute_pad$ = ""; - @ts_second_pad$ = ""; - - return; +// Returns current time. A SQL update superseeded this. +// santime( ) +function script santime { + return gettimetick(2); } +function script time_from_ms { + return now() + (getarg(0) / 1000); +} +function script time_from_seconds { + return now() + getarg(0); +} +function script time_from_minutes { + return now() + (getarg(0) * 60); +} +function script time_from_hours { + return now() + (getarg(0) * 3600); +} + +function script time_from_days { + return now() + (getarg(0) * 86400); +} -function script HumanTime { - @time$ = "now"; - if(@seconds) set @ms, @ms + (@seconds * 1000); - if(@minutes) set @ms, @ms + (@minutes * 60000); - if(@days) set @ms, @ms + (@days * 1440000); - if(@ms < 1000) goto L_Millis; // under 1 second we have nothing to count - @seconds = @ms / 1000; - @ms = @ms % 1000; - if(@seconds < 60) goto L_Seconds; - @minutes = @seconds / 60; - @seconds = @seconds % 60; - if(@minutes < 60) goto L_Minutes; - @hours = @minutes / 60; - @minutes = @minutes % 60; - if(@hours < 24) goto L_Hours; - @days = @hours / 24; - @hours = @hours % 24; - if(@days) goto L_Days; - goto L_Clean; - -L_Millis: - @time$ = @ms + "ms"; - return; - -L_Seconds: - @unit$ = "second"; - if(@seconds > 1) set @unit$, "seconds"; - @unit2$ = "millisecond"; - if(@ms > 1) set @unit2$, "milliseconds"; - @time$ = @seconds + " " + @unit$; - if(@ms) set @time$, @time$ + " and " + @ms + " " + @unit2$; - goto L_Clean; - -L_Minutes: - @unit$ = "minute"; - if(@minutes > 1) set @unit$, "minutes"; - @unit2$ = "second"; - if(@seconds > 1) set @unit2$, "seconds"; - @unit3$ = "millisecond"; - if(@ms > 1) set @unit3$, "milliseconds"; - @time$ = @minutes + " " + @unit$; - @separator$ = " and "; - if(@ms) set @separator$, ", "; - if(@seconds) set @time$, @time$ + @separator$ + @seconds + " " + @unit2$; - if(@ms) set @time$, @time$ + " and " + @ms + " " + @unit3$; - goto L_Clean; - -L_Hours: - @unit$ = "hour"; - if(@hours > 1) set @unit$, "hours"; - @unit2$ = "minute"; - if(@minutes > 1) set @unit2$, "minutes"; - @unit3$ = "second"; - if(@seconds > 1) set @unit3$, "seconds"; - @unit4$ = "millisecond"; - if(@ms > 1) set @unit4$, "milliseconds"; - @time$ = @hours + " " + @unit$; - @separator$ = " and "; - if(@seconds || @ms) set @separator$, ", "; - if(@minutes) set @time$, @time$ + @separator$ + @minutes + " " + @unit2$; - @separator$ = " and "; - if(@ms) set @separator$, ", "; - if(@seconds) set @time$, @time$ + @separator$ + @seconds + " " + @unit3$; - if(@ms) set @time$, @time$ + " and " + @ms + " " + @unit4$; - goto L_Clean; - -L_Days: - @unit$ = "day"; - if(@hours > 1) set @unit$, "days"; - @unit2$ = "hour"; - if(@hours > 1) set @unit2$, "hours"; - @unit3$ = "minute"; - if(@minutes > 1) set @unit3$, "minutes"; - @unit4$ = "second"; - if(@seconds > 1) set @unit4$, "seconds"; - @unit5$ = "millisecond"; - if(@ms > 1) set @unit5$, "milliseconds"; - @time$ = @days + " " + @unit$; - @separator$ = " and "; - if(@minutes || @seconds || @ms) set @separator$, ", "; - if(@hours) set @time$, @time$ + @separator$ + @hours + " " + @unit2$; - @separator$ = " and "; - if(@seconds || @ms) set @separator$, ", "; - if(@minutes) set @time$, @time$ + @separator$ + @minutes + " " + @unit3$; - @separator$ = " and "; - if(@ms) set @separator$, ", "; - if(@seconds) set @time$, @time$ + @separator$ + @seconds + " " + @unit3$; - if(@ms) set @time$, @time$ + " and " + @ms + " " + @unit4$; - goto L_Clean; - -L_Clean: - @unit$ = ""; - @unit2$ = ""; - @unit3$ = ""; - @unit4$ = ""; - @unit5$ = ""; - @seconds = 0; - @minutes = 0; - @hours = 0; - @days = 0; - @separator$ = ""; - return; +// FuzzyTime(<unix timestamp>{, <options>{, <precision>}}) +// gives time in a human-readable format +// +// <options> is bitmasked: +// 1 do not show "ago" when in past +// 2 do not show "in" when in the future +// 4 show "from now" instead of "in" when in the future +// +// <precision> is the number of units to show, +// by default uses two (eg. 2m30s or 1h20m). +// Use '99' for max precision + +function script FuzzyTime { + .@future = getarg(0, now()); + .@options = getarg(1, 3); + .@precision = getarg(2, 2); + .@diff = (.@future - now()); + + // check if in the past, or in the future + if (.@diff < 0) { + .@diff *= -1; + .@past = true; + } + + .@diff = max(1, .@diff); + + if (.@diff >= 31536000) { + .@years = (.@diff / 31536000); + .@diff = (++.@s == .@precision ? 0 : (.@diff % 31536000)); + .@ret$ += sprintf("%d %s", .@years, (.@years > 1 ? "years" : "year")); + } + + if (.@diff >= 86400) { + .@days = (.@diff / 86400); + .@diff = (++.@s == .@precision ? 0 : (.@diff % 86400)); + + if (.@s > 1) { + .@ret$ += (.@diff > 0 ? ", " : " and "); + } + + .@ret$ += sprintf("%d %s", .@days, (.@days > 1 ? "days" : "day")); + } + + if (.@diff >= 3600) { + .@hours = (.@diff / 3600); + .@diff = (++.@s == .@precision ? 0 : (.@diff % 3600)); + + if (.@s > 1) { + .@ret$ += (.@diff > 0 ? ", " : (.@s >= 3 ? ", " : " ") + "and "); + } + + .@ret$ += sprintf("%d %s", .@hours, (.@hours > 1 ? "hours" : "hour")); + } + + if (.@diff >= 60) { + .@minutes = (.@diff / 60); + .@diff = (++.@s == .@precision ? 0 : (.@diff % 60)); + + if (.@s > 1) { + .@ret$ += (.@diff > 0 ? ", " : (.@s >= 3 ? ", " : " ") + "and "); + } + + .@ret$ += sprintf("%d %s", .@minutes, (.@minutes > 1 ? "minutes" : "minute")); + } + + if (.@diff >= 1) { + if (++.@s > 1) { + .@ret$ += (.@s >= 3 ? ", " : " ") + "and "; + } + + .@ret$ += sprintf("%d %s", .@diff, (.@diff > 1 ? "seconds" : "second")); + } + + if (.@past && !(.@options & 1)) { + .@ret$ += " ago"; + } + + if (!(.@past) && !(.@options & 2)) { + .@ret$ = ((.@options & 4) ? sprintf("%s from now", .@ret$) : sprintf("in %s", .@ret$)); + } + + return .@ret$; } diff --git a/npc/functions/timer.txt b/npc/functions/timer.txt new file mode 100644 index 00000000..27e09f13 --- /dev/null +++ b/npc/functions/timer.txt @@ -0,0 +1,89 @@ +// Evol Script +// Authors: Gumi, Jesusalva + +// areatimer("<map>", <x1>, <y1>, <x2>, <y2>, <tick>, "<npc>::<event>") +function script areatimer { + // Legacy + if (getargcount() > 7) + .@ox=1; + // Variables + .@m$=getarg(.@ox); .@ox+=1; + .@x1=getarg(.@ox); .@ox+=1; + .@y1=getarg(.@ox); .@ox+=1; + .@x2=getarg(.@ox); .@ox+=1; + .@y2=getarg(.@ox); .@ox+=1; + .@tk=getarg(.@ox); .@ox+=1; + .@e$=getarg(.@ox); .@ox+=1; + .@c = getunits(BL_PC, .@players, false, .@m$, .@x1, .@y1, .@x2, .@y2); + for (.@i = 0; .@i < .@c; .@i++) { + addtimer(.@tk, .@e$, .@players[.@i]); + } + return .@i; +} + +// areadeltimer("<map>", <x1>, <y1>, <x2>, <y2>, "<npc>::<event>") +function script areadeltimer { + .@c = getunits(BL_PC, .@players, false, getarg(0), getarg(1), getarg(2), getarg(3), getarg(4)); + for (.@i = 0; .@i < .@c; .@i++) { + deltimer(getarg(5), .@players[.@i]); + } + return .@i; +} + +// areatimer2("<map>", <x1>, <y1>, <x2>, <y2>, <tick>, "<npc>::<event>") +function script areatimer2 { + .@c = getunits(BL_PC, .@players, false, getarg(0), getarg(1), getarg(2), getarg(3), getarg(4)); + for (.@i = 0; .@i < .@c; .@i++) { + deltimer(getarg(6), .@players[.@i]); + addtimer(getarg(5), getarg(6), .@players[.@i]); + } + return .@i; +} + +// addtimer2(<tick>, "<npc>::<event>") +function script addtimer2 { + deltimer(getarg(1)); + addtimer(getarg(0), getarg(1)); + return; +} + + +// maptimer("<map>", <tick>, "<npc>::<event>") +function script maptimer { + .@c = getunits(BL_PC, .@players, false, getarg(0)); + for (.@i = 0; .@i < .@c; .@i++) { + addtimer(getarg(1), getarg(2), .@players[.@i]); + } + return .@i; +} + +// Same as maptimer() but deletes any previously running timer +// maptimer2("<map>", <tick>, "<npc>::<event>") +function script maptimer2 { + .@c = getunits(BL_PC, .@players, false, getarg(0)); + for (.@i = 0; .@i < .@c; .@i++) { + deltimer(getarg(2), .@players[.@i]); + addtimer(getarg(1), getarg(2), .@players[.@i]); + } + return .@i; +} + +// mapdeltimer("<map>", "<npc>::<event>") +function script mapdeltimer { + .@c = getunits(BL_PC, .@players, false, getarg(0)); + for (.@i = 0; .@i < .@c; .@i++) { + deltimer(getarg(1), .@players[.@i]); + } + return .@i; +} + +// partytimer("<map>", <tick>, "<npc>::<event>", partyid) +function script partytimer { + .@c = getunits(BL_PC, .@players, false, getarg(0)); + for (.@i = 0; .@i < .@c; .@i++) { + if (getcharid(2, strcharinfo(0,"",.@players[.@i]) ) == getarg(3)) + addtimer(getarg(1), getarg(2), .@players[.@i]); + } + return .@i; +} + |