diff options
author | shennetsind <ind@henn.et> | 2014-01-11 14:02:59 -0200 |
---|---|---|
committer | shennetsind <ind@henn.et> | 2014-01-11 14:02:59 -0200 |
commit | 82b583b5ef4e729ad2c3c74b26adce16a145605a (patch) | |
tree | 5bb20b90edd899b06abe9853dba06383a9379c06 /src/map/script.c | |
parent | 56649bda4b2f62cf42847830546b5856234b3178 (diff) | |
download | hercules-82b583b5ef4e729ad2c3c74b26adce16a145605a.tar.gz hercules-82b583b5ef4e729ad2c3c74b26adce16a145605a.tar.bz2 hercules-82b583b5ef4e729ad2c3c74b26adce16a145605a.tar.xz hercules-82b583b5ef4e729ad2c3c74b26adce16a145605a.zip |
Hercules 1st 2014 MegaPatch
http://hercules.ws/board/topic/3886-hercules-1st-2014-megapatch/
Signed-off-by: shennetsind <ind@henn.et>
Diffstat (limited to 'src/map/script.c')
-rw-r--r-- | src/map/script.c | 835 |
1 files changed, 514 insertions, 321 deletions
diff --git a/src/map/script.c b/src/map/script.c index 8bd4bc028..21d4d289c 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -212,10 +212,7 @@ void script_reportdata(struct script_data* data) case C_NAME:// reference if( reference_tovariable(data) ) {// variable const char* name = reference_getname(data); - if( not_array_variable(*name) ) - ShowDebug("Data: variable name='%s'\n", name); - else - ShowDebug("Data: variable name='%s' index=%d\n", name, reference_getindex(data)); + ShowDebug("Data: variable name='%s' index=%d\n", name, reference_getindex(data)); } else if( reference_toconstant(data) ) {// constant ShowDebug("Data: constant name='%s' value=%d\n", reference_getname(data), reference_getconstant(data)); } else if( reference_toparam(data) ) {// param @@ -2501,9 +2498,9 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) { break; case '#': if( name[1] == '#' ) - data->u.str = pc_readaccountreg2str(sd, name);// global + data->u.str = pc_readaccountreg2str(sd, data->u.num);// global else - data->u.str = pc_readaccountregstr(sd, name);// local + data->u.str = pc_readaccountregstr(sd, data->u.num);// local break; case '.': { @@ -2512,21 +2509,21 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) { st->stack->var_function : // instance/scope variable st->script->script_vars; // npc variable if( n ) - data->u.str = (char*)idb_get(n,reference_getuid(data)); + data->u.str = (char*)i64db_get(n,reference_getuid(data)); else data->u.str = NULL; } break; case '\'': if ( st->instance_id >= 0 ) { - data->u.str = (char*)idb_get(instance->list[st->instance_id].vars,reference_getuid(data)); + data->u.str = (char*)i64db_get(instance->list[st->instance_id].vars,reference_getuid(data)); } else { ShowWarning("script_get_val: cannot access instance variable '%s', defaulting to \"\"\n", name); data->u.str = NULL; } break; default: - data->u.str = pc_readglobalreg_str(sd, name); + data->u.str = pc_readglobalreg_str(sd, data->u.num); break; } @@ -2556,9 +2553,9 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) { break; case '#': if( name[1] == '#' ) - data->u.num = pc_readaccountreg2(sd, name);// global + data->u.num = pc_readaccountreg2(sd, data->u.num);// global else - data->u.num = pc_readaccountreg(sd, name);// local + data->u.num = pc_readaccountreg(sd, data->u.num);// local break; case '.': { @@ -2567,21 +2564,21 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) { st->stack->var_function : // instance/scope variable st->script->script_vars; // npc variable if( n ) - data->u.num = (int)idb_iget(n,reference_getuid(data)); + data->u.num = (int)i64db_iget(n,reference_getuid(data)); else data->u.num = 0; } break; case '\'': if( st->instance_id >= 0 ) - data->u.num = (int)idb_iget(instance->list[st->instance_id].vars,reference_getuid(data)); + data->u.num = (int)i64db_iget(instance->list[st->instance_id].vars,reference_getuid(data)); else { ShowWarning("script_get_val: cannot access instance variable '%s', defaulting to 0\n", name); data->u.num = 0; } break; default: - data->u.num = pc_readglobalreg(sd, name); + data->u.num = pc_readglobalreg(sd, data->u.num); break; } @@ -2592,63 +2589,245 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) { /// Retrieves the value of a reference identified by uid (variable, constant, param) /// The value is left in the top of the stack and needs to be removed manually. -void* get_val2(struct script_state* st, int uid, struct DBMap** ref) { +void* get_val2(struct script_state* st, int64 uid, struct DBMap** ref) { struct script_data* data; script->push_val(st->stack, C_NAME, uid, ref); data = script_getdatatop(st, -1); script->get_val(st, data); return (data->type == C_INT ? (void*)__64BPTRSIZE(data->u.num) : (void*)__64BPTRSIZE(data->u.str)); } +/** + * Returns array size by ID + **/ +unsigned int script_array_size(struct script_state *st, struct map_session_data *sd, const char *name) { + struct script_array *sa = NULL; + struct DBMap *src = script->array_src(st, sd, name); + + if( src ) + sa = idb_get(src, script->search_str(name)); + + return sa ? sa->size : 0; +} +/** + * Returns array's highest key (for that awful getarraysize implementation that doesn't really gets the array size) + **/ +unsigned int script_array_highest_key(struct script_state *st, struct map_session_data *sd, const char *name) { + struct script_array *sa = NULL; + struct DBMap *src = script->array_src(st, sd, name); + + if( src && ( sa = idb_get(src, script->search_str(name)) ) ) { + unsigned int i, highest_key = 0; + + for(i = 0; i < sa->size; i++) { + if( sa->members[i] > highest_key ) + highest_key = sa->members[i]; + } + + return highest_key + 1; + } + + return 0; +} +int script_free_array_db(DBKey key, DBData *data, va_list ap) { + struct script_array *sa = DB->data2ptr(data); + aFree(sa->members); + ers_free(script->array_ers, sa); + return 0; +} +/** + * Clears script_array and removes it from script->array_db + **/ +void script_array_delete(struct DBMap *src, struct script_array *sa) { + aFree(sa->members); + idb_remove(src, sa->id); + ers_free(script->array_ers, sa); +} +/** + * Removes a member from a script_array list + * + * @param idx the index of the member in script_array struct list, not of the actual array member + **/ +void script_array_remove_member(struct DBMap *src,struct script_array *sa, unsigned int idx) { + unsigned int i, cursor; + + /* its the only member left, no need to do anything other than delete the array data */ + if( sa->size == 1 ) { + script->array_delete(src,sa); + return; + } + + sa->members[idx] = UINT_MAX; + + for(i = 0, cursor = 0; i < sa->size; i++) { + if( sa->members[i] == UINT_MAX ) + continue; + if( i != cursor ) + sa->members[cursor] = sa->members[i]; + cursor++; + } + + sa->size = cursor; +} +/** + * Appends a new array index to the list in script_array + * + * @param idx the index of the array member being inserted + **/ +void script_array_add_member(struct script_array *sa, unsigned int idx) { + + RECREATE(sa->members, unsigned int, ++sa->size); + + sa->members[sa->size - 1] = idx; +} +/** + * Obtains the source of the array database for this type and scenario + * Initializes such database when not yet initialised. + **/ +struct DBMap *script_array_src(struct script_state *st, struct map_session_data *sd, const char *name) { + struct DBMap **src = NULL; + + switch( name[0] ) { + /* from player */ + default: /* char reg */ + case '@':/* temp char reg */ + case '#':/* account reg */ + src = &sd->array_db; + break; + case '$':/* map reg */ + src = &mapreg->array_db; + break; + case '.':/* npc/script */ + src = (name[1] == '@') ? &st->stack->array_function_db : &st->script->script_arrays_db; + break; + case '\'':/* instance */ + if( st->instance_id >= 0 ) { + src = &instance->list[st->instance_id].array_db; + } + break; + } + + if( src ) { + if( !*src ) + *src = idb_alloc(DB_OPT_BASE); + return *src; + } + + return NULL; +} +/** + * Processes a array member modification, and update data accordingly + **/ +void script_array_update(struct DBMap **src, int64 num, bool empty) { + struct script_array *sa = NULL; + int id = script_getvarid(num); + unsigned int index = script_getvaridx(num); + + if( !*src ) { + *src = idb_alloc(DB_OPT_BASE); + } else { + sa = idb_get(*src, id); + } + + if( sa ) { + unsigned int i; + + /* search */ + for(i = 0; i < sa->size; i++) { + if( sa->members[i] == index ) + break; + } + + /* if existent */ + if( i != sa->size ) { + /* if empty, we gotta remove it */ + if( empty ) { + script->array_remove_member(*src,sa,i); + } + } else if( !empty ) { /* new entry */ + script->array_add_member(sa,index); + /* we do nothing if its empty, no point in modifying array data for a new empty member */ + } + } else if ( !empty ) {/* we only move to create if not empty */ + sa = ers_alloc(script->array_ers, struct script_array); + sa->id = id; + script->array_add_member(sa,index); + idb_put(*src, id, sa); + } +} /*========================================== * Stores the value of a script variable * Return value is 0 on fail, 1 on success. + * TODO: return values are screwed up, have been for some time (reaad: years), e.g. some functions return 1 failure and success. *------------------------------------------*/ -int set_reg(struct script_state* st, TBL_PC* sd, int num, const char* name, const void* value, struct DBMap** ref) -{ +int set_reg(struct script_state* st, TBL_PC* sd, int64 num, const char* name, const void* value, struct DBMap** ref) { char prefix = name[0]; + + if( is_string_variable(name) ) {// string variable + const char *str = (const char*)value; - if( is_string_variable(name) ) - {// string variable - const char* str = (const char*)value; switch (prefix) { - case '@': - return pc->setregstr(sd, num, str); - case '$': - return mapreg->setregstr(num, str); - case '#': - return (name[1] == '#') ? - pc_setaccountreg2str(sd, name, str) : - pc_setaccountregstr(sd, name, str); - case '.': - { - struct DBMap* n; - n = (ref) ? *ref : (name[1] == '@') ? st->stack->var_function : st->script->script_vars; - if( n ) { - idb_remove(n, num); - if (str[0]) idb_put(n, num, aStrdup(str)); + case '@': + pc->setregstr(sd, num, str); + return 1; + case '$': + return mapreg->setregstr(num, str); + case '#': + return (name[1] == '#') ? + pc_setaccountreg2str(sd, num, str) : + pc_setaccountregstr(sd, num, str); + case '.': + { + struct DBMap* n; + n = (ref) ? *ref : (name[1] == '@') ? st->stack->var_function : st->script->script_vars; + if( n ) { + if (str[0]) { + i64db_put(n, num, aStrdup(str)); + if( script_getvaridx(num) ) + script->array_update( + (name[1] == '@') ? + &st->stack->array_function_db : + &st->script->script_arrays_db, + num, + false); + } else { + i64db_remove(n, num); + if( script_getvaridx(num) ) + script->array_update( + (name[1] == '@') ? + &st->stack->array_function_db : + &st->script->script_arrays_db, + num, + true); + } + } } - } - return 1; - case '\'': - if( st->instance_id >= 0 ) { - idb_remove(instance->list[st->instance_id].vars, num); - if( str[0] ) idb_put(instance->list[st->instance_id].vars, num, aStrdup(str)); - } - return 1; - default: - return pc_setglobalreg_str(sd, name, str); + return 1; + case '\'': + if( st->instance_id >= 0 ) { + if( str[0] ) { + i64db_put(instance->list[st->instance_id].vars, num, aStrdup(str)); + if( script_getvaridx(num) ) + script->array_update(&instance->list[st->instance_id].array_db,num,false); + } else { + i64db_remove(instance->list[st->instance_id].vars, num); + if( script_getvaridx(num) ) + script->array_update(&instance->list[st->instance_id].array_db,num,true); + } + } else { + ShowError("script_set_reg: cannot write instance variable '%s', NPC not in a instance!\n", name); + script_reportsrc(st); + } + return 1; + default: + return pc_setglobalreg_str(sd, num, str); } - } - else - {// integer variable + } else {// integer variable int val = (int)__64BPTRSIZE(value); - if(script->str_data[num&0x00ffffff].type == C_PARAM) - { - if( pc->setparam(sd, script->str_data[num&0x00ffffff].val, val) == 0 ) - { - if( st != NULL ) - { + + if(script->str_data[script_getvarid(num)].type == C_PARAM) { + if( pc->setparam(sd, script->str_data[script_getvarid(num)].val, val) == 0 ) { + if( st != NULL ) { ShowError("script:set_reg: failed to set param '%s' to %d.\n", name, val); script->reportsrc(st); st->state = END; @@ -2659,34 +2838,60 @@ int set_reg(struct script_state* st, TBL_PC* sd, int num, const char* name, cons } switch (prefix) { - case '@': - return pc->setreg(sd, num, val); - case '$': - return mapreg->setreg(num, val); - case '#': - return (name[1] == '#') ? - pc_setaccountreg2(sd, name, val) : - pc_setaccountreg(sd, name, val); - case '.': - { - struct DBMap* n; - n = (ref) ? *ref : (name[1] == '@') ? st->stack->var_function : st->script->script_vars; - if( n ) { - idb_remove(n, num); - if( val != 0 ) - idb_iput(n, num, val); + case '@': + pc->setreg(sd, num, val); + return 1; + case '$': + return mapreg->setreg(num, val); + case '#': + return (name[1] == '#') ? + pc_setaccountreg2(sd, num, val) : + pc_setaccountreg(sd, num, val); + case '.': + { + struct DBMap* n; + n = (ref) ? *ref : (name[1] == '@') ? st->stack->var_function : st->script->script_vars; + if( n ) { + if( val != 0 ) { + i64db_iput(n, num, val); + if( script_getvaridx(num) ) + script->array_update( + (name[1] == '@') ? + &st->stack->array_function_db : + &st->script->script_arrays_db, + num, + false); + } else { + i64db_remove(n, num); + if( script_getvaridx(num) ) + script->array_update( + (name[1] == '@') ? + &st->stack->array_function_db : + &st->script->script_arrays_db, + num, + true); + } + } } - } - return 1; - case '\'': - if( st->instance_id >= 0 ) { - idb_remove(instance->list[st->instance_id].vars, num); - if( val != 0 ) - idb_iput(instance->list[st->instance_id].vars, num, val); - } - return 1; - default: - return pc_setglobalreg(sd, name, val); + return 1; + case '\'': + if( st->instance_id >= 0 ) { + if( val != 0 ) { + i64db_iput(instance->list[st->instance_id].vars, num, val); + if( script_getvaridx(num) ) + script->array_update(&instance->list[st->instance_id].array_db,num,false); + } else { + i64db_remove(instance->list[st->instance_id].vars, num); + if( script_getvaridx(num) ) + script->array_update(&instance->list[st->instance_id].array_db,num,true); + } + } else { + ShowError("script_set_reg: cannot write instance variable '%s', NPC not in a instance!\n", name); + script_reportsrc(st); + } + return 1; + default: + return pc_setglobalreg(sd, num, val); } } } @@ -2712,7 +2917,7 @@ const char* conv_str(struct script_state* st, struct script_data* data) else if( data_isint(data) ) {// int -> string CREATE(p, char, ITEM_NAME_LENGTH); - snprintf(p, ITEM_NAME_LENGTH, "%d", data->u.num); + snprintf(p, ITEM_NAME_LENGTH, "%lld", data->u.num); p[ITEM_NAME_LENGTH-1] = '\0'; data->type = C_STR; data->u.str = p; @@ -2786,7 +2991,7 @@ int conv_num(struct script_state* st, struct script_data* data) { data->u.num = 0; } #endif - return data->u.num; + return (int)data->u.num; } // @@ -2803,7 +3008,7 @@ void stack_expand(struct script_stack* stack) { } /// Pushes a value into the stack (with reference) -struct script_data* push_val(struct script_stack* stack, enum c_op type, int val, struct DBMap** ref) { +struct script_data* push_val(struct script_stack* stack, enum c_op type, int64 val, struct DBMap** ref) { if( stack->sp >= stack->sp_max ) script->stack_expand(stack); stack->stack_data[stack->sp].type = type; @@ -2932,6 +3137,8 @@ void script_free_vars(struct DBMap* var_storage) { void script_free_code(struct script_code* code) { script->free_vars( code->script_vars ); + if( code->script_arrays_db ) + code->script_arrays_db->destroy(code->script_arrays_db,script->array_free_db); aFree( code->script_buf ); aFree( code ); } @@ -2952,7 +3159,8 @@ struct script_state* script_alloc_state(struct script_code* rootscript, int pos, st->stack->sp_max = 64; CREATE(st->stack->stack_data, struct script_data, st->stack->sp_max); st->stack->defsp = st->stack->sp; - st->stack->var_function = idb_alloc(DB_OPT_RELEASE_DATA); + st->stack->var_function = i64db_alloc(DB_OPT_RELEASE_DATA); + st->stack->array_function_db = NULL; st->state = RUN; st->script = rootscript; st->pos = pos; @@ -2962,7 +3170,7 @@ struct script_state* script_alloc_state(struct script_code* rootscript, int pos, st->npc_item_flag = battle_config.item_enabled_npc; if( !st->script->script_vars ) - st->script->script_vars = idb_alloc(DB_OPT_RELEASE_DATA); + st->script->script_vars = i64db_alloc(DB_OPT_RELEASE_DATA); st->id = script->next_id++; script->active_scripts++; @@ -2985,14 +3193,22 @@ void script_free_state(struct script_state* st) { timer->delete(st->sleep.timer, script->run_timer); if( st->stack ) { script->free_vars(st->stack->var_function); + if( st->stack->array_function_db ) + st->stack->array_function_db->destroy(st->stack->array_function_db,script->array_free_db); script->pop_stack(st, 0, st->stack->sp); aFree(st->stack->stack_data); ers_free(script->stack_ers, st->stack); st->stack = NULL; } - if( st->script && st->script->script_vars && !db_size(st->script->script_vars) ) { - script->free_vars(st->script->script_vars); - st->script->script_vars = NULL; + if( st->script ) { + if( st->script->script_vars && !db_size(st->script->script_vars) ) { + script->free_vars(st->script->script_vars); + st->script->script_vars = NULL; + } + if( st->script->script_arrays_db && !db_size(st->script->script_arrays_db) ) { + script->free_vars(st->script->script_arrays_db); + st->script->script_arrays_db = NULL; + } } st->pos = -1; idb_remove(script->st_db, st->id); @@ -3037,20 +3253,6 @@ int get_num(unsigned char *scriptbuf,int *pos) return i+((scriptbuf[(*pos)++]&0x7f)<<j); } -/*========================================== - * Remove the value from the stack - *------------------------------------------*/ -int pop_val(struct script_state* st) -{ - if(st->stack->sp<=0) - return 0; - st->stack->sp--; - script->get_val(st,&(st->stack->stack_data[st->stack->sp])); - if(st->stack->stack_data[st->stack->sp].type==C_INT) - return st->stack->stack_data[st->stack->sp].u.num; - return 0; -} - /// Ternary operators /// test ? if_true : if_false void op_3(struct script_state* st, int op) @@ -3064,7 +3266,7 @@ void op_3(struct script_state* st, int op) if( data_isstring(data) ) flag = data->u.str[0];// "" -> false else if( data_isint(data) ) - flag = data->u.num;// 0 -> false + flag = data->u.num == 0 ? 0 : 1;// 0 -> false else { ShowError("script:op_3: invalid data for the ternary operator test\n"); @@ -3234,8 +3436,8 @@ void op_2(struct script_state *st, int op) } else if( data_isint(left) && data_isint(right) ) {// ii => op_2num - int i1 = left->u.num; - int i2 = right->u.num; + int i1 = (int)left->u.num; + int i2 = (int)right->u.num; script_removetop(st, leftref.type == C_NOP ? -2 : -1, 0); script->op_2num(st, op, i1, i2); @@ -3277,19 +3479,18 @@ void op_1(struct script_state* st, int op) return; } - i1 = data->u.num; + i1 = (int)data->u.num; script_removetop(st, -1, 0); - switch( op ) - { - case C_NEG: i1 = -i1; break; - case C_NOT: i1 = ~i1; break; - case C_LNOT: i1 = !i1; break; - default: - ShowError("script:op_1: unexpected operator %s i1=%d\n", script->op2name(op), i1); - script->reportsrc(st); - script_pushnil(st); - st->state = END; - return; + switch( op ) { + case C_NEG: i1 = -i1; break; + case C_NOT: i1 = ~i1; break; + case C_LNOT: i1 = !i1; break; + default: + ShowError("script:op_1: unexpected operator %s i1=%d\n", script->op2name(op), i1); + script->reportsrc(st); + script_pushnil(st); + st->state = END; + return; } script_pushint(st, i1); } @@ -3400,7 +3601,7 @@ int run_func(struct script_state *st) data = &st->stack->stack_data[st->start]; if( data->type == C_NAME && script->str_data[data->u.num].type == C_FUNC ) - func = data->u.num; + func = (int)data->u.num; else { ShowError("script:run_func: not a buildin command.\n"); @@ -3418,7 +3619,7 @@ int run_func(struct script_state *st) if (!(script->str_data[func].func(st))) //Report error script->reportsrc(st); } else { - ShowError("script:run_func: '%s' (id=%d type=%s) has no C function. please report this!!!\n", script->get_str(func), func, script->op2name(script->str_data[func].type)); + ShowError("script:run_func: '%s' (id=%lld type=%s) has no C function. please report this!!!\n", script->get_str(func), func, script->op2name(script->str_data[func].type)); script->reportsrc(st); st->state = END; } @@ -3723,10 +3924,8 @@ void run_script_main(struct script_state *st) { } //Restore previous script if any. script->detach_state(st, true); - if (sd->state.reg_dirty&2) - intif->saveregistry(sd,2); - if (sd->state.reg_dirty&1) - intif->saveregistry(sd,1); + if (sd->vars_dirty) + intif->saveregistry(sd); } script->free_state(st); st = NULL; @@ -3813,70 +4012,99 @@ void script_add_autobonus(const char *autobonus) /// resets a temporary character array variable to given value -void script_cleararray_pc(struct map_session_data* sd, const char* varname, void* value) -{ +void script_cleararray_pc(struct map_session_data* sd, const char* varname, void* value) { + struct script_array *sa = NULL; + struct DBMap *src = NULL; + unsigned int i, *list = NULL, size = 0; int key; - uint8 idx; - - if( not_array_variable(varname[0]) || !not_server_variable(varname[0]) ) - { - ShowError("script_cleararray_pc: Variable '%s' has invalid scope (char_id=%d).\n", varname, sd->status.char_id); - return; - } key = script->add_str(varname); - - if( is_string_variable(varname) ) - { - for( idx = 0; idx < SCRIPT_MAX_ARRAYSIZE; idx++ ) - { - pc->setregstr(sd, reference_uid(key, idx), (const char*)value); - } - } - else - { - for( idx = 0; idx < SCRIPT_MAX_ARRAYSIZE; idx++ ) - { - pc->setreg(sd, reference_uid(key, idx), (int)__64BPTRSIZE(value)); - } + + if( !(src = script->array_src(NULL,sd,varname) ) ) + return; + + if( !(sa = idb_get(src, key)) ) /* non-existent array, nothing to empty */ + return; + + size = sa->size; + list = script->array_cpy_list(sa); + + for(i = 0; i < size; i++) { + script->set_reg(NULL,sd,reference_uid(key, list[i]),varname,value,NULL); } } /// sets a temporary character array variable element idx to given value /// @param refcache Pointer to an int variable, which keeps a copy of the reference to varname and must be initialized to 0. Can be NULL if only one element is set. -void script_setarray_pc(struct map_session_data* sd, const char* varname, uint8 idx, void* value, int* refcache) -{ +void script_setarray_pc(struct map_session_data* sd, const char* varname, uint32 idx, void* value, int* refcache) { int key; - - if( not_array_variable(varname[0]) || !not_server_variable(varname[0]) ) - { - ShowError("script_setarray_pc: Variable '%s' has invalid scope (char_id=%d).\n", varname, sd->status.char_id); - return; - } - - if( idx >= SCRIPT_MAX_ARRAYSIZE ) - { - ShowError("script_setarray_pc: Variable '%s' has invalid index '%d' (char_id=%d).\n", varname, (int)idx, sd->status.char_id); + + if( idx >= SCRIPT_MAX_ARRAYSIZE ) { + ShowError("script_setarray_pc: Variable '%s' has invalid index '%u' (char_id=%d).\n", varname, idx, sd->status.char_id); return; } key = ( refcache && refcache[0] ) ? refcache[0] : script->add_str(varname); - - if( is_string_variable(varname) ) - { - pc->setregstr(sd, reference_uid(key, idx), (const char*)value); - } - else - { - pc->setreg(sd, reference_uid(key, idx), (int)__64BPTRSIZE(value)); - } - + + script->set_reg(NULL,sd,reference_uid(key, idx),varname,value,NULL); + if( refcache ) {// save to avoid repeated script->add_str calls refcache[0] = key; } } +/** + * Clears persistent variables from memory + **/ +int script_reg_destroy(DBKey key, DBData *data, va_list ap) { + void *src; + + if( data->type != DB_DATA_PTR )/* got no need for those! */ + return 0; + + src = DB->data2ptr(data); + + if( ((struct script_reg_state*)src)->type ) { + struct script_reg_str *p = src; + + if( p->value ) + aFree(p->value); + + ers_free(pc->str_reg_ers,p); + } else { + ers_free(pc->num_reg_ers,(struct script_reg_num*)src); + } + + return 0; +} +/** + * Clears a single persistent variable + **/ +void script_reg_destroy_single(struct map_session_data *sd, int64 reg, struct script_reg_state *data) { + i64db_remove(sd->var_db, reg); + + if( data->type ) { + struct script_reg_str *p = (struct script_reg_str*)data; + + if( p->value ) + aFree(p->value); + + ers_free(pc->str_reg_ers,p); + } else { + ers_free(pc->num_reg_ers,(struct script_reg_num*)data); + } +} +unsigned int *script_array_cpy_list(struct script_array *sa) { + if( sa->size > script->generic_ui_array_size ) + script->generic_ui_array_expand(sa->size); + memcpy(script->generic_ui_array, sa->members, sizeof(unsigned int)*sa->size); + return script->generic_ui_array; +} +void script_generic_ui_array_expand (unsigned int plus) { + script->generic_ui_array_size += plus + 100; + RECREATE(script->generic_ui_array, unsigned int, script->generic_ui_array_size); +} /*========================================== * Destructor *------------------------------------------*/ @@ -4005,6 +4233,11 @@ void do_final_script(void) { if( script->labels != NULL ) aFree(script->labels); + + ers_destroy(script->array_ers); + + if( script->generic_ui_array ) + aFree(script->generic_ui_array); } /*========================================== * Initialization @@ -4016,6 +4249,7 @@ void do_init_script(bool minimal) { script->st_ers = ers_new(sizeof(struct script_state), "script.c::st_ers", ERS_OPT_CLEAN); script->stack_ers = ers_new(sizeof(struct script_stack), "script.c::script_stack", ERS_OPT_NONE); + script->array_ers = ers_new(sizeof(struct script_array), "script.c::array_ers", ERS_OPT_CLEAN|ERS_OPT_CLEAR); ers_chunk_size(script->st_ers, 10); ers_chunk_size(script->stack_ers, 10); @@ -4073,7 +4307,7 @@ const char *script_getfuncname(struct script_state *st) { data = &st->stack->stack_data[st->start]; if( data->type == C_NAME && script->str_data[data->u.num].type == C_FUNC ) - return script->get_str(data->u.num); + return script->get_str(script_getvarid(data->u.num)); return NULL; } @@ -4568,7 +4802,7 @@ BUILDIN(callfunc) st->script = scr; st->stack->defsp = st->stack->sp; st->state = GOTO; - st->stack->var_function = idb_alloc(DB_OPT_RELEASE_DATA); + st->stack->var_function = i64db_alloc(DB_OPT_RELEASE_DATA); return true; } @@ -4617,7 +4851,7 @@ BUILDIN(callsub) st->pos = pos; st->stack->defsp = st->stack->sp; st->state = GOTO; - st->stack->var_function = idb_alloc(DB_OPT_RELEASE_DATA); + st->stack->var_function = i64db_alloc(DB_OPT_RELEASE_DATA); return true; } @@ -5150,7 +5384,7 @@ BUILDIN(input) { TBL_PC* sd; struct script_data* data; - int uid; + int64 uid; const char* name; int min; int max; @@ -5214,7 +5448,7 @@ BUILDIN(setr) { TBL_PC* sd = NULL; struct script_data* data; //struct script_data* datavalue; - int num; + int64 num; const char* name; char prefix; @@ -5292,34 +5526,6 @@ BUILDIN(setr) { /// Array variables /// -/// Returns the size of the specified array -int32 getarraysize(struct script_state* st, int32 id, int32 idx, int isstring, struct DBMap** ref) -{ - int32 ret = idx; - - if( isstring ) - { - for( ; idx < SCRIPT_MAX_ARRAYSIZE; ++idx ) - { - char* str = (char*)script->get_val2(st, reference_uid(id, idx), ref); - if( str && *str ) - ret = idx + 1; - script_removetop(st, -1, 0); - } - } - else - { - for( ; idx < SCRIPT_MAX_ARRAYSIZE; ++idx ) - { - int32 num = (int32)__64BPTRSIZE(script->get_val2(st, reference_uid(id, idx), ref)); - if( num ) - ret = idx + 1; - script_removetop(st, -1, 0); - } - } - return ret; -} - /// Sets values of an array, from the starting index. /// ex: setarray arr[1],1,2,3; /// @@ -5346,13 +5552,6 @@ BUILDIN(setarray) id = reference_getid(data); start = reference_getindex(data); name = reference_getname(data); - if( not_array_variable(*name) ) - { - ShowError("script:setarray: illegal scope\n"); - script->reportdata(data); - st->state = END; - return false;// not supported - } if( not_server_variable(*name) ) { @@ -5404,13 +5603,6 @@ BUILDIN(cleararray) id = reference_getid(data); start = reference_getindex(data); name = reference_getname(data); - if( not_array_variable(*name) ) - { - ShowError("script:cleararray: illegal scope\n"); - script->reportdata(data); - st->state = END; - return false;// not supported - } if( not_server_variable(*name) ) { @@ -5469,14 +5661,6 @@ BUILDIN(copyarray) idx2 = reference_getindex(data2); name1 = reference_getname(data1); name2 = reference_getname(data2); - if( not_array_variable(*name1) || not_array_variable(*name2) ) - { - ShowError("script:copyarray: illegal scope\n"); - script->reportdata(data1); - script->reportdata(data2); - st->state = END; - return false;// not supported - } if( is_string_variable(name1) != is_string_variable(name2) ) { @@ -5534,7 +5718,6 @@ BUILDIN(copyarray) BUILDIN(getarraysize) { struct script_data* data; - const char* name; data = script_getdata(st, 2); if( !data_isreference(data) ) @@ -5546,19 +5729,12 @@ BUILDIN(getarraysize) return false;// not a variable } - name = reference_getname(data); - if( not_array_variable(*name) ) - { - ShowError("script:getarraysize: illegal scope\n"); - script->reportdata(data); - script_pushnil(st); - st->state = END; - return false;// not supported - } - - script_pushint(st, script->getarraysize(st, reference_getid(data), reference_getindex(data), is_string_variable(name), reference_getref(data))); + script_pushint(st, script->array_highest_key(st,st->rid ? script->rid2sd(st) : NULL,reference_getname(data))); return true; } +int script_array_index_cmp(const void *a, const void *b) { + return ( *(unsigned int*)a - *(unsigned int*)b ); +} /// Deletes count or all the elements in an array, from the starting index. /// ex: deletearray arr[4],2; @@ -5569,10 +5745,12 @@ BUILDIN(deletearray) { struct script_data* data; const char* name; - int start; - int end; + unsigned int start, end, i; int id; TBL_PC *sd = NULL; + struct script_array *sa = NULL; + struct DBMap *src = NULL; + void *value; data = script_getdata(st, 2); if( !data_isreference(data) ) @@ -5586,13 +5764,6 @@ BUILDIN(deletearray) id = reference_getid(data); start = reference_getindex(data); name = reference_getname(data); - if( not_array_variable(*name) ) - { - ShowError("script:deletearray: illegal scope\n"); - script->reportdata(data); - st->state = END; - return false;// not supported - } if( not_server_variable(*name) ) { @@ -5601,39 +5772,81 @@ BUILDIN(deletearray) return true;// no player attached } - end = SCRIPT_MAX_ARRAYSIZE; + if( !(src = script->array_src(st,sd,name) ) ) { + ShowError("script:deletearray: not a array\n"); + script->reportdata(data); + st->state = END; + return false;// not a variable + } else if ( !(sa = idb_get(src, id)) ) { /* non-existent array, nothing to empty */ + ShowError("script:deletearray: unknown array\n"); + script->reportdata(data); + st->state = END; + return false;// not a variable + } + end = script->array_highest_key(st,sd,name); + if( start >= end ) return true;// nothing to free - if( script_hasdata(st,3) ) - { - int count = script_getnum(st, 3); + if( is_string_variable(name) ) + value = (void *)""; + else + value = (void *)0; + + if( script_hasdata(st,3) ) { + unsigned int count = script_getnum(st, 3); if( count > end - start ) count = end - start; if( count <= 0 ) return true;// nothing to free - // move rest of the elements backward - for( ; start + count < end; ++start ) - { - void* v = script->get_val2(st, reference_uid(id, start + count), reference_getref(data)); - script->set_reg(st, sd, reference_uid(id, start), name, v, reference_getref(data)); - script_removetop(st, -1, 0); + if( end - start < sa->size ) { + // Better to iterate directly on the array, no speed-up from using sa + for( ; start + count < end; ++start ) { + // Compact and overwrite + void* v = script->get_val2(st, reference_uid(id, start + count), reference_getref(data)); + script->set_reg(st, sd, reference_uid(id, start), name, v, reference_getref(data)); + script_removetop(st, -1, 0); + } + for( ; start < end; start++ ) { + // Clean up any leftovers that weren't overwritten + script->set_reg(st, sd, reference_uid(id, start), name, value, reference_getref(data)); + } + } else { + // using sa to speed up + unsigned int *list = NULL, size = 0; + list = script->array_cpy_list(sa); + size = sa->size; + qsort(list, size, sizeof(unsigned int), script_array_index_cmp); + + ARR_FIND(0, size, i, list[i] >= start); + + for( ; i < size && list[i] < start + count; i++ ) { + // Clear any entries between start and start+count, if they exist + script->set_reg(st, sd, reference_uid(id, list[i]), name, value, reference_getref(data)); + } + + for( ; i < size && list[i] < end; i++ ) { + // Move back count positions any entries between start+count to fill the gaps + void* v = script->get_val2(st, reference_uid(id, list[i]), reference_getref(data)); + script->set_reg(st, sd, reference_uid(id, list[i]-count), name, v, reference_getref(data)); + script_removetop(st, -1, 0); + // Clear their originals + script->set_reg(st, sd, reference_uid(id, list[i]), name, value, reference_getref(data)); + } + } + } else { + unsigned int *list = NULL, size = 0; + list = script->array_cpy_list(sa); + size = sa->size; + + for(i = 0; i < size; i++) { + if( list[i] >= start ) // Less expensive than sorting it, most likely + script->set_reg(st, sd, reference_uid(id, list[i]), name, value, reference_getref(data)); } } - // clear the rest of the array - if( is_string_variable(name) ) - { - for( ; start < end; ++start ) - script->set_reg(st, sd, reference_uid(id, start), name, (void *)"", reference_getref(data)); - } - else - { - for( ; start < end; ++start ) - script->set_reg(st, sd, reference_uid(id, start), name, (void*)0, reference_getref(data)); - } return true; } @@ -5646,7 +5859,7 @@ BUILDIN(getelementofarray) struct script_data* data; const char* name; int32 id; - int i; + int64 i; data = script_getdata(st, 2); if( !data_isreference(data) ) @@ -5659,27 +5872,18 @@ BUILDIN(getelementofarray) } id = reference_getid(data); - name = reference_getname(data); - if( not_array_variable(*name) ) - { - ShowError("script:getelementofarray: illegal scope\n"); - script->reportdata(data); - script_pushnil(st); - st->state = END; - return false;// not supported - } i = script_getnum(st, 3); if( i < 0 || i >= SCRIPT_MAX_ARRAYSIZE ) { - ShowWarning("script:getelementofarray: index out of range (%d)\n", i); + ShowWarning("script:getelementofarray: index out of range (%lld)\n", i); script->reportdata(data); script_pushnil(st); st->state = END; return false;// out of range } - script->push_val(st->stack, C_NAME, reference_uid(id, i), reference_getref(data)); + script->push_val(st->stack, C_NAME, reference_uid(id, (unsigned int)i), reference_getref(data)); return true; } @@ -5976,19 +6180,13 @@ BUILDIN(checkweight2) name_it = reference_getname(data_it); name_nb = reference_getname(data_nb); - if( not_array_variable(*name_it) || not_array_variable(*name_nb)) - { - ShowError("script:checkweight2: illegal scope\n"); - script_pushint(st,0); - return false;// not supported - } if(is_string_variable(name_it) || is_string_variable(name_nb)) { ShowError("script:checkweight2: illegal type, need int\n"); script_pushint(st,0); return false;// not supported } - nb_it = script->getarraysize(st, id_it, idx_it, 0, reference_getref(data_it)); - nb_nb = script->getarraysize(st, id_nb, idx_nb, 0, reference_getref(data_nb)); + nb_it = script->array_highest_key(st,sd,reference_getname(data_it)); + nb_nb = script->array_highest_key(st,sd,reference_getname(data_nb)); if(nb_it != nb_nb) { ShowError("Size mistmatch: nb_it=%d, nb_nb=%d\n",nb_it,nb_nb); fail = 1; @@ -12810,7 +13008,7 @@ BUILDIN(getmapxy) struct block_list *bl = NULL; TBL_PC *sd=NULL; - int num; + int64 num; const char *name; char prefix; @@ -12910,7 +13108,7 @@ BUILDIN(getmapxy) //Set MapName$ num=st->stack->stack_data[st->start+2].u.num; - name=script->get_str(num&0x00ffffff); + name=script->get_str(script_getvarid(num)); prefix=*name; if(not_server_variable(prefix)) @@ -12921,7 +13119,7 @@ BUILDIN(getmapxy) //Set MapX num=st->stack->stack_data[st->start+3].u.num; - name=script->get_str(num&0x00ffffff); + name=script->get_str(script_getvarid(num)); prefix=*name; if(not_server_variable(prefix)) @@ -12932,7 +13130,7 @@ BUILDIN(getmapxy) //Set MapY num=st->stack->stack_data[st->start+4].u.num; - name=script->get_str(num&0x00ffffff); + name=script->get_str(script_getvarid(num)); prefix=*name; if(not_server_variable(prefix)) @@ -13537,14 +13735,6 @@ BUILDIN(explode) start = reference_getindex(data); name = reference_getname(data); - if( not_array_variable(*name) ) - { - ShowError("script:explode: illegal scope\n"); - script->reportdata(data); - st->state = END; - return false;// not supported - } - if( !is_string_variable(name) ) { ShowError("script:explode: not string array\n"); @@ -13586,7 +13776,7 @@ BUILDIN(implode) { struct script_data* data = script_getdata(st, 2); const char *glue = NULL, *name, *temp; - int32 array_size, id; + uint32 array_size, id; size_t len = 0, glue_len = 0, k = 0; int i; @@ -13605,14 +13795,6 @@ BUILDIN(implode) id = reference_getid(data); name = reference_getname(data); - if( not_array_variable(*name) ) - { - ShowError("script:implode: illegal scope\n"); - script->reportdata(data); - st->state = END; - return false;// not supported - } - if( !is_string_variable(name) ) { ShowError("script:implode: not string array\n"); @@ -13629,7 +13811,7 @@ BUILDIN(implode) } //count chars - array_size = script->getarraysize(st, id, reference_getindex(data), is_string_variable(name), reference_getref(data)) - 1; + array_size = script->array_highest_key(st,sd,name) - 1; if(array_size == -1) { //empty array check (AmsTaff) @@ -14270,8 +14452,6 @@ int buildin_query_sql_sub(struct script_state* st, Sql* handle) return false; } } - if( not_array_variable(*name) ) - max_rows = 1;// not an array, limit to one row } else { ShowError("script:query_sql: not a variable\n"); script->reportdata(data); @@ -14857,13 +15037,6 @@ BUILDIN(searchitem) id = reference_getid(data); start = reference_getindex(data); name = reference_getname(data); - if( not_array_variable(*name) ) - { - ShowError("script:searchitem: illegal scope\n"); - script->reportdata(data); - st->state = END; - return false;// not supported - } if( not_server_variable(*name) ) { @@ -18811,11 +18984,11 @@ void script_defaults(void) { script->next_id = 0; script->st_ers = NULL; script->stack_ers = NULL; - + script->array_ers = NULL; + script->hq = NULL; script->hqi = NULL; script->hqs = script->hqis = 0; - memset(&script->hqe, 0, sizeof(script->hqe)); script->buildin = NULL; script->buildin_count = 0; @@ -18868,6 +19041,9 @@ void script_defaults(void) { script->potion_flag = script->potion_hp = script->potion_per_hp = script->potion_sp = script->potion_per_sp = script->potion_target = 0; + script->generic_ui_array = NULL; + script->generic_ui_array_size = 0; + /* */ script->init = do_init_script; script->final = do_final_script; script->reload = script_reload; @@ -18955,7 +19131,6 @@ void script_defaults(void) { script->set_reg = set_reg; script->stack_expand = stack_expand; script->push_retinfo = push_retinfo; - script->pop_val = pop_val; script->op_3 = op_3; script->op_2str = op_2str; script->op_2num = op_2num; @@ -18968,7 +19143,6 @@ void script_defaults(void) { script->menu_countoptions = menu_countoptions; script->buildin_areawarp_sub = buildin_areawarp_sub; script->buildin_areapercentheal_sub = buildin_areapercentheal_sub; - script->getarraysize = getarraysize; script->buildin_delitem_delete = buildin_delitem_delete; script->buildin_delitem_search = buildin_delitem_search; script->buildin_killmonster_sub_strip = buildin_killmonster_sub_strip; @@ -19033,4 +19207,23 @@ void script_defaults(void) { script->global_casecheck.str_pos = 0; memset(script->global_casecheck.str_hash, 0, sizeof(script->global_casecheck.str_hash)); // end ENABLE_CASE_CHECK + + /** + * Array Handling + **/ + script->array_src = script_array_src; + script->array_update = script_array_update; + script->array_add_member = script_array_add_member; + script->array_remove_member = script_array_remove_member; + script->array_delete = script_array_delete; + script->array_size = script_array_size; + script->array_free_db = script_free_array_db; + script->array_highest_key = script_array_highest_key; + /* */ + script->reg_destroy_single = script_reg_destroy_single; + script->reg_destroy = script_reg_destroy; + /* */ + script->generic_ui_array_expand = script_generic_ui_array_expand; + script->array_cpy_list = script_array_cpy_list; + } |