Added "string_pos" function from 4.x

Added a check to PartyControl::OrderAttackPatch().
Updated function documents.
Updated scripting headers.
This commit is contained in:
NovaRain
2023-07-05 22:20:14 +08:00
parent 2941157174
commit 3a08488895
13 changed files with 154 additions and 92 deletions
@@ -170,9 +170,26 @@
#define self_elevation (elevation(self_obj))
#define self_pid (obj_pid(self_obj))
// team
#define self_team has_trait(TRAIT_OBJECT,self_obj,OBJECT_TEAM_NUM)
#define get_team(cr) has_trait(TRAIT_OBJECT,cr,OBJECT_TEAM_NUM)
#define set_team(cr,team) critter_add_trait(cr,TRAIT_OBJECT,OBJECT_TEAM_NUM,team)
#define set_self_team(team) set_team(self_obj,team)
// ai
#define self_ai has_trait(TRAIT_OBJECT,self_obj,OBJECT_AI_PACKET)
#define get_ai(cr) has_trait(TRAIT_OBJECT,cr,OBJECT_AI_PACKET)
#define set_ai(cr,ai) critter_add_trait(cr,TRAIT_OBJECT,OBJECT_AI_PACKET,ai)
#define set_self_ai(ai) set_ai(self_obj,ai)
// visibility
#define self_visible obj_is_visible_flag(self_obj)
#define set_obj_invisible(cr) set_obj_visibility(cr,true)
#define set_obj_visible(cr) set_obj_visibility(cr,false)
#define set_self_invisible set_obj_visibility(self_obj,true)
#define set_self_visible set_obj_visibility(self_obj,false)
#define is_visible(cr) has_trait(TRAIT_OBJECT,cr,OBJECT_VISIBILITY) // aka obj_is_visible_flag(x)
#define self_cur_hits (get_critter_stat(self_obj,STAT_current_hp))
#define self_max_hits (get_critter_stat(self_obj,STAT_max_hp))
+53 -12
View File
@@ -35,6 +35,9 @@ procedure array_keys(variable array);
// list of array values (useful for maps)
procedure array_values(variable array);
// makes given array permanent and returns it
procedure array_fixed(variable array);
// returns temp array containing a subarray starting from $index with $count elements
// negative $index means index from the end of array
// negative $count means leave this many elements from the end of array
@@ -91,6 +94,11 @@ procedure get_empty_array_index(variable array);
procedure add_array_set(variable array, variable item);
procedure remove_array_set(variable array, variable item);
// Creates a new array filled from a given array by transforming each value using given procedure name.
procedure array_transform(variable arr, variable valueFunc);
// Create a new temp array filled from a given array by transforming each key and value using given procedure name.
procedure array_transform_kv(variable arr, variable keyFunc, variable valueFunc);
@@ -223,6 +231,11 @@ procedure array_values(variable array) begin
return tmp;
end
procedure array_fixed(variable array) begin
fix_array(array);
return array;
end
procedure array_slice(variable array, variable index, variable count) begin
variable tmp, i, n;
n := len_array(array);
@@ -401,14 +414,25 @@ procedure remove_array_set(variable array, variable item) begin
end
end
// Transform every value in array using given callback
procedure array_map_func(variable arr, variable callback) begin
variable k, v;
foreach (k: v in arr)
arr[k] := callback(v);
return arr;
// Creates a new array filled from a given array by transforming each value using given procedure name.
procedure array_transform(variable arr, variable valueFunc) begin
variable k, v, retArr := temp_array_map if array_is_map(arr) else temp_array(len_array(arr), 0);
foreach (k: v in arr) begin
retArr[k] := valueFunc(v);
end
return retArr;
end
// Create a new temp array filled from a given array by transforming each key and value using given procedure name.
procedure array_transform_kv(variable arr, variable keyFunc, variable valueFunc) begin
variable k, v, retArr := temp_array_map;
foreach (k: v in arr) begin
retArr[keyFunc(k)] := valueFunc(v);
end
return retArr;
end
#define ARRAY_EMPTY_INDEX (-1)
/**
@@ -484,6 +508,7 @@ procedure array_append(variable arr1, variable arr2) begin
return arr1;
end
// Loads a "saved" array. If it doesn't exist, creates it (with a given size).
procedure load_create_array(variable name, variable size) begin
variable arr;
arr := load_array(name);
@@ -494,6 +519,7 @@ procedure load_create_array(variable name, variable size) begin
return arr;
end
// Creates and returns a new "saved" array. If array already existed with this name, frees it.
procedure get_saved_array_new(variable name, variable size) begin
variable arr;
arr := load_array(name);
@@ -584,30 +610,45 @@ end
Different utility functions...
*/
procedure debug_array_str(variable arr) begin
variable i := 0, k, s, len;
#define debug_array_str(arr) debug_array_str_deep(arr, 1)
procedure debug_array_str_deep(variable arr, variable levels) begin
#define _newline if (levels > 1) then s += "\n";
#define _indent string_repeat(" ", levels - 1)
#define _value(v) (v if (levels <= 1 or not array_exists(v)) else debug_array_str_deep(v, levels - 1))
variable i := 0, k, v, s, len;
len := len_array(arr);
if (array_is_map(arr)) then begin // print assoc array
s := "Map("+len+"): {";
while i < len do begin
_newline
k := array_key(arr, i);
s += k + ": "+ get_array(arr, k);
v := get_array(arr, k);
s += _indent + k + ": " + _value(v);
if i < (len - 1) then s += ", ";
i++;
end
if (strlen(s) > 254) then s := substr(s, 0, 251) + "...";
//if (strlen(s) > 254) then s := substr(s, 0, 251) + "...";
_newline
s += "}";
end else begin // print list
s := "List("+len+"): [";
_newline
while i < len do begin
s += arr[i];
_newline
v := get_array(arr, i);
s += _indent + _value(v);
if i < (len - 1) then s += ", ";
i++;
end
if (strlen(s) > 254) then s := substr(s, 0, 251) + "...";
//if (strlen(s) > 254) then s := substr(s, 0, 251) + "...";
_newline
s += "]";
end
return s;
#undef _newline
#undef _indent
#undef _value
end
procedure _PURGE_all_saved_arrays begin
+8 -5
View File
@@ -51,13 +51,15 @@ procedure remove_items_pid(variable invenObj, variable itemPid, variable quantit
variable begin
item;
toRemoveQty;
actualQty;
end
if (not(invenObj)) then return;
toRemoveQty := obj_is_carrying_obj_pid(invenObj, itemPid);
if (quantity < toRemoveQty and quantity != -1) then begin
toRemoveQty := quantity;
actualQty := obj_is_carrying_obj_pid(invenObj, itemPid);
if (quantity > actualQty or quantity < 0) then begin
quantity := actualQty;
end
while (toRemoveQty > 0) do begin
toRemoveQty := quantity;
while (quantity > 0) do begin
item := obj_carrying_pid_obj(invenObj, itemPid);
if (obj_type(invenObj) == OBJ_TYPE_CRITTER) then begin
if (critter_inven_obj(invenObj, INVEN_TYPE_WORN) == item) then begin
@@ -66,9 +68,10 @@ procedure remove_items_pid(variable invenObj, variable itemPid, variable quantit
inven_unwield(invenObj);
end
end
toRemoveQty -= rm_mult_objs_from_inven(invenObj, item, toRemoveQty);
quantity -= rm_mult_objs_from_inven(invenObj, item, quantity);
destroy_object(item);
end
return toRemoveQty;
end
procedure remove_item_obj(variable invenObj, variable item) begin
+3 -8
View File
@@ -5,13 +5,8 @@
Numbers...
*/
#define above(a, b) (unsigned_comp(a, b) > 0)
#define above_equal(a, b) (unsigned_comp(a, b) >= 0)
#define below(a, b) (unsigned_comp(a, b) < 0)
#define below_equal(a, b) (unsigned_comp(a, b) <= 0)
// for sfall 4.2.3/3.8.23
pure procedure unsigned_comp(variable a, variable b) begin
pure procedure unsigned_int_compare(variable a, variable b) begin
if ((a bwxor b) == 0) then return 0; // a == b
return 1 if ((b == 0) orElse a div b) else -1;
end
@@ -21,10 +16,10 @@ end
#define math_max(x, y) (x if x > y else y)
#define math_min(x, y) (x if x < y else y)
#define in_range(x, from, to) (x >= from and x <= to)
#define math_in_range(x, from, to) (x >= from and x <= to)
procedure get_clamped(variable val, variable a, variable b) begin
procedure math_clamp(variable val, variable a, variable b) begin
variable min, max;
if (a < b) then begin
min := a;
+21 -61
View File
@@ -13,17 +13,10 @@
#define is_in_string(str, sub) (string_pos(str, sub) != -1)
#define string_starts_with(str, sub) (substr(str, 0, strlen(sub)) == sub)
/**
* Returns position of first occurance of substr in str, or -1 if not found
*/
procedure string_pos(variable str, variable subst) begin
variable lst, n;
lst := string_split(str, subst);
if (len_array(lst) < 2) then
return -1;
return strlen(lst[0]);
end
#define string_format_array(fmt, arr) sprintf_array(fmt, arr)
// Replaces all occurances of substring in a string with another substring
#define string_replace(str, search, replace) (string_join(string_split(str, search), replace))
#define sprintf2(fmt, arg1, arg2) string_format2(fmt, arg1, arg2)
/**
* Join array of strings using delimeter
@@ -41,44 +34,6 @@ procedure string_join(variable array, variable join) begin
return str;
end
/**
* replaces all occurances of substring in a string with another substring
*/
#define string_replace(str, search, replace) (string_join(string_split(str, search), replace))
/**
* sprintf with two arguments
*/
procedure sprintf2(variable str, variable arg1, variable arg2) begin
variable split, len, i, j, arg;
split := string_split(str, "%");
len := len_array(split);
str := "";
if (len > 0) then begin
str := split[0];
j := 0;
for (i := 1; i < len; i++) begin
if (split[i] == "") then begin
if (i < len - 1) then begin
str += "%" + split[i+1];
i++;
end
end else begin
if (j == 0) then
arg := arg1;
else if (j == 1) then
arg := arg2;
else
arg := 0;
str += sprintf("%" + split[i], arg);
j++;
end
end
end
return str;
end
/**
* sprintf with unlimited number of arguments
*/
@@ -151,18 +106,6 @@ procedure string_repeat(variable str, variable count) begin
return out;
end
/**
* Workaround for string_split bug in sfall 3.3
* DEPRECATED as of sfall 3.4 (bug fixed)
*/
procedure string_split_safe(variable str, variable split) begin
variable lst;
str += split;
lst := string_split(str, split);
resize_array(lst, len_array(lst) - 1);
return lst;
end
/**
* The same as sfall string_split, but returns array of integers instead
* Useful in cunjunction with is_in_array()
@@ -186,8 +129,25 @@ procedure string_split_ints(variable str, variable split) begin
return result;
end
// atoi proc wrapper, for use as callback
procedure string_to_int(variable str) begin
return atoi(str);
end
// atof proc wrapper, for use as callback
procedure string_to_float(variable str) begin
return atof(str);
end
// converts any value to a string, for use as callback
procedure to_string(variable val) begin
return ""+val;
end
/**
DEPRECATED, use string_format instead!
String parse functions. Idea taken from KLIMaka on TeamX forums.
Placeholders in format %d% are replaced from string. d refers to variable index (starting from 1).
You can repeat one placeholder multiple times, or use placeholders in any order.
+6 -3
View File
@@ -149,7 +149,7 @@
// sort map in descending order by key value
#define sort_map_reverse(array) resize_array(array, -7)
// remove element from map or just replace value with 0 for list
#define unset_array(array, item) set_array(array, item, 0)
#define unset_array(array, key) set_array(array, key, 0)
// same as "key_pressed" but checks VK codes instead of DX codes
#define key_pressed_vk(key) (key_pressed(key bwor 0x80000000))
@@ -282,6 +282,8 @@
/* SFALL_FUNCX MACROS */
#define FUNC_SELECTOR_7(_1,_2,_3,_4,_5,_6,_7,FUNC,...) FUNC
#define add_extra_msg_file(name) sfall_func1("add_extra_msg_file", name)
#define add_global_timer_event(time, fixedParam) sfall_func2("add_g_timer_event", time, fixedParam)
#define add_iface_tag sfall_func0("add_iface_tag")
@@ -387,6 +389,8 @@
#define spatial_radius(obj) sfall_func1("spatial_radius", obj)
#define string_compare(str1, str2) sfall_func2("string_compare", str1, str2)
#define string_compare_locale(str1, str2, codePage) sfall_func3("string_compare", str1, str2, codePage)
#define string_pos(haystack, needle) sfall_func2("string_pos", haystack, needle)
#define string_pos_from(haystack, needle, pos) sfall_func3("string_pos", haystack, needle, pos)
#define string_format1(format, a1) sfall_func2("string_format", format, a1)
#define string_format2(format, a1, a2) sfall_func3("string_format", format, a1, a2)
#define string_format3(format, a1, a2, a3) sfall_func4("string_format", format, a1, a2, a3)
@@ -394,8 +398,7 @@
#define string_format5(format, a1, a2, a3, a4, a5) sfall_func6("string_format", format, a1, a2, a3, a4, a5)
#define string_format6(format, a1, a2, a3, a4, a5, a6) sfall_func7("string_format", format, a1, a2, a3, a4, a5, a6)
#define string_format7(format, a1, a2, a3, a4, a5, a6, a7) sfall_func8("string_format", format, a1, a2, a3, a4, a5, a6, a7)
#define string_format_MACRO(_0,_1,_2,_3,_4,_5,_6,FUNC,...) FUNC
#define string_format(...) string_format_MACRO(__VA_ARGS__, string_format6, string_format5, string_format4, string_format3, string_format2, string_format1)(__VA_ARGS__)
#define string_format(format, ...) FUNC_SELECTOR_7(__VA_ARGS__,string_format7,string_format6,string_format5,string_format4,string_format3,string_format2,string_format1)(format, __VA_ARGS__)
#define string_tolower(text) sfall_func2("string_to_case", text, 0)
#define string_toupper(text) sfall_func2("string_to_case", text, 1)
#define tile_by_position(x, y) sfall_func2("tile_by_position", x, y)
+14 -3
View File
@@ -327,11 +327,11 @@ FUNCTION REFERENCE
- You can use this to search for a substring in a string like this: `strlen(get_array(string_split(haystack, needle), 0))`
-----
##### `string substr(string text, start, length)`
##### `string substr(string text, int start, int length)`
- Cuts a substring from a string starting at `start` up to `length` characters. The first character position is 0 (zero).
- If `start` is negative - it indicates starting position from the end of the string (for example, `substr("test", -2, 2)` will return last 2 charactes: "st").
- If `start` is negative - it indicates a position starting from the end of the string (for example, `substr("test", -2, 2)` will return last 2 charactes: "st").
- If `length` is negative - it means so many characters will be omitted from the end of string (example: `substr("test", 0, -2)` will return string without last 2 characters: "te").
- If `length` is zero - it will return a string from the starting position to the end of the string (new behavior for sfall 4.2.2/3.8.22).
- If `length` is zero - it will return a string from the starting position to the end of the string (**new behavior** since sfall 4.2.2/3.8.22).
-----
##### `int strlen(string text)`
@@ -1084,6 +1084,7 @@ sfall_funcX metarule functions
- Allows changing "bonus move" points (yellow lights on the interface bar) that can only be used for movement, not attacking
- Can be called from `HOOK_COMBATTURN` at the start of the turn (will not work on `dude_obj`)
- Can be called from `HOOK_STDPROCEDURE` with `combat_proc` event (will work on both NPCs and `dude_obj`)
----
#### get_ini_config
`array sfall_func2("get_ini_config", string file, bool searchDB)`
@@ -1093,6 +1094,16 @@ sfall_funcX metarule functions
True - searches the file in database (DAT) files. If not found, then it will try the regular file system
- Subsequent calls for the same file will return the same array, unless it was disposed using `free_array`
----
#### string_pos
`int sfall_func2("string_pos", string haystack, string needle)`
`int sfall_func3("string_pos", string haystack, string needle, int pos)`
- Returns the position of the first occurrence of a `needle` string in a `haystack` string, or -1 if not found. The first character position is 0 (zero)
**Optional argument:**
- `pos`: the position at which to start the search. If negative, it indicates a position starting from the end of the string
****
_See other documentation files (arrays.md, hookscripts.md) for related functions reference._
+4
View File
@@ -680,12 +680,16 @@ static void __declspec(naked) combat_ai_hook_target() {
}
void PartyControl::OrderAttackPatch() {
static bool orderAttackPatch = false;
if (orderAttackPatch) return;
MakeCall(0x44C4A7, gmouse_handle_event_hack, 2);
HookCall(0x44C75F, gmouse_handle_event_hook);
HookCall(0x44C69A, gmouse_handle_event_hook_restore);
MakeCall(0x44B830, gmouse_bk_process_hack);
HookCall(0x42B235, combat_ai_hook_target);
orderAttackPatch = true;
}
static void NpcAutoLevelPatch() {
@@ -153,6 +153,7 @@ static const SfallMetarule metarules[] = {
{"show_window", mf_show_window, 0, 1, -1, {ARG_STRING}},
{"spatial_radius", mf_spatial_radius, 1, 1, 0, {ARG_OBJECT}},
{"string_compare", mf_string_compare, 2, 3, 0, {ARG_STRING, ARG_STRING, ARG_INT}},
{"string_pos", mf_string_pos, 2, 3, -1, {ARG_STRING, ARG_STRING, ARG_INT}},
{"string_format", mf_string_format, 2, 8, 0, {ARG_STRING, ARG_ANY, ARG_ANY, ARG_ANY, ARG_ANY, ARG_ANY, ARG_ANY, ARG_ANY}},
{"string_to_case", mf_string_to_case, 2, 2, -1, {ARG_STRING, ARG_INT}},
{"tile_by_position", mf_tile_by_position, 2, 2, -1, {ARG_INT, ARG_INT}},
@@ -198,6 +198,25 @@ void mf_string_compare(OpcodeContext& ctx) {
}
}
void mf_string_pos(OpcodeContext& ctx) {
const char* const haystack = ctx.arg(0).strValue();
int pos = 0;
if (ctx.numArgs() > 2) {
int len = strlen(haystack);
pos = ctx.arg(2).intValue();
if (pos >= len) {
ctx.setReturn(-1);
return;
} else if (pos < 0) {
pos += len;
}
}
const char* needle = strstr(haystack + pos, ctx.arg(1).strValue());
ctx.setReturn(
needle != nullptr ? (int)(needle - haystack) : -1
);
}
// A safer version of sprintf for using in user scripts.
static const char* sprintf_lite(OpcodeContext& ctx, const char* opcodeName) {
const char* format = ctx.arg(0).strValue();
+2
View File
@@ -37,6 +37,8 @@ void op_strlen(OpcodeContext&);
void mf_string_compare(OpcodeContext&);
void mf_string_pos(OpcodeContext&);
void op_sprintf(OpcodeContext&);
void mf_string_format(OpcodeContext&);
+4
View File
@@ -135,6 +135,10 @@ unsigned long ScriptValue::rawValue() const {
return _val.dw;
}
long ScriptValue::intValue() const {
return _val.i;
}
const char* ScriptValue::strValue() const {
return _val.str;
}
+2
View File
@@ -57,6 +57,8 @@ public:
unsigned long rawValue() const;
long intValue() const;
float floatValue() const;
const char* strValue() const;