diff options
author | FlavioJS <FlavioJS@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2007-04-22 15:45:37 +0000 |
---|---|---|
committer | FlavioJS <FlavioJS@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2007-04-22 15:45:37 +0000 |
commit | e828c8642a637a3e3f63450b75ebc93f2bd4bce4 (patch) | |
tree | c21ac768b9b756ccdc36cf8f34d636d157cff337 | |
parent | b574d2412b1c882a1f7cc70e460662e1725ce97d (diff) | |
download | hercules-e828c8642a637a3e3f63450b75ebc93f2bd4bce4.tar.gz hercules-e828c8642a637a3e3f63450b75ebc93f2bd4bce4.tar.bz2 hercules-e828c8642a637a3e3f63450b75ebc93f2bd4bce4.tar.xz hercules-e828c8642a637a3e3f63450b75ebc93f2bd4bce4.zip |
* Extended the functionality of StringBuf - length and appending a string.
* menu/select/prompt script functions support grouped and empty options.
The selected option number is consistent with them.
* More work on ticket #41.
git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@10316 54d463be-8e91-2dee-dedb-b68131a5f0ec
-rw-r--r-- | Changelog-Trunk.txt | 5 | ||||
-rw-r--r-- | doc/script_commands.txt | 56 | ||||
-rw-r--r-- | src/common/utils.c | 25 | ||||
-rw-r--r-- | src/common/utils.h | 2 | ||||
-rw-r--r-- | src/map/clif.c | 2 | ||||
-rw-r--r-- | src/map/map.h | 2 | ||||
-rw-r--r-- | src/map/script.c | 576 |
7 files changed, 432 insertions, 236 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index c0a1a3c48..1b9ec0376 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -3,6 +3,11 @@ Date Added AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK. IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. +2007/04/23 + * Extended the functionality of StringBuf - length and appending a string. + * menu/select/prompt script functions support grouped and empty options. + The selected option number is consistent with them. + * More work on ticket #41. [FlavioJS] 2007/04/22 * Corrected crash if itemskill is used without an attached player. * Removed range checks for autospells as per UltraMage Aegis tests. diff --git a/doc/script_commands.txt b/doc/script_commands.txt index 4c90118da..15fad965a 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -9,7 +9,7 @@ //= Maeki Rika - A section on general concepts and lots of //= other updates and additions. //===== Version =========================================== -//= 3.04.20070317 +//= 3.05.20070423 //========================================================= //= 1.0 - First release, filled will as much info as I could //= remember or figure out, most likely there are errors, @@ -73,6 +73,9 @@ //= Adjusted the 'itemskill' description due to recent change [ultramage] //= 3.04.20070409 //= Fixed the incorrect order of parameters in 'makeitem' [ultramage] +//= 3.05.20070423 +//= menu/select/prompt produce consistent results for grouped and empty +//= options [FlavioJS] //===== Description ======================================= //= A reference manual for the eAthena scripting language, //= sorted out depending on their functionality. @@ -1116,7 +1119,7 @@ Note by FlavioJS: goto's are "evil" and should be avoided if possible (ò_ó) --------------------------------------- -*menu "<menu option>",<label>{,"<menu option>",<label>,...}; +*menu "<option_text>",<target_label>{,"<option_text>",<target_label>,...}; This command will create a selectable menu for the invoking character. Only one menu can be on screen at the same time. @@ -1125,25 +1128,40 @@ Depending on what the player picks from the menu, the script execution will continue from the corresponding label. (it's string-label pairs, not label- string) +Options can be grouped together, separated by the character ':'. + + menu "A:B",L_Wrong,"C",L_Right; + It also sets a special temporary character variable @menu, which contains the number of option the player picked. (Numbering of options starts at 1.) - - menu "I want to Start",L_Start,"I want to end",L_End; - L_Start: - //If they click "I want to Start" they will end up here - L_End: - //If they click "I want to end" they will end up here +This number is consistent with empty options and grouped options. + + menu "A::B",L_Wrong,"",L_Impossible,"C",L_Right; + L_Wrong: + // If they click "A" or "B" they will end up here + // @menu == 1 if "A" + // @menu == 2 will never happen because the option is empty + // @menu == 3 if "B" + L_Impossible: + // Empty options are not displayed and therefore can't be selected + // this label will never be reached from the menu command + L_Right: + // If they click "C" they will end up here + // @menu == 5 If a label is '-', the script execution will continue right after the menu command if that option is selected, this can be used to save you time, and optimize big scripts. - menu "I want to Start",-,"I want to end",L_End; - //If they click "I want to Start" they will end up here - L_End: - //If they click "I want to end" they will end up here + menu "A::B:",-,"C",L_Right; + // If they click "A" or "B" they will end up here + // @menu == 1 if "A" + // @menu == 3 if "B" + L_Right: + // If they click "C" they will end up here + // @menu == 5 -Both these examples will perform the same task. +Both these examples will perform the exact same task. If you give an empty string as a menu item, the item will not display. This can effectively be used to script dynamic menus by using empty string for @@ -1242,8 +1260,8 @@ perfectly equivalent. --------------------------------------- -*select("<option>"{,"<option>"..."<option>"}) -*prompt("<option>"{,"<option>"..."<option>"}) +*select("<option>"{,"<option>",...}) +*prompt("<option>"{,"<option>",...}) This function is a handy replacement for 'menu' for some specific cases where you don't want a complex label structure - like, for example, asking simple yes- @@ -1251,12 +1269,10 @@ no questions. It will return the number of menu option picked, starting with 1. Like 'menu', it will also set the variable @menu to contain the option the user picked. - if (select("Yes","No")==1) mes "You said yes, I know."; + if (select("Yes:No")==1) mes "You said yes, I know."; -And like 'menu', this command has a problem with empty strings - if some of the -option strings given to it are empty, you won't be able to tell which one the -user really picked. The number it returns will only make sense if all the empty -strings are last in the list of options. +And like 'menu', the selected option is consistent with grouped options +and empty options. prompt works almost the same as select, except that when a character clicks the Cancel button, this function will return 255 instead. diff --git a/src/common/utils.c b/src/common/utils.c index d6a017c95..3dc7fea16 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -123,6 +123,31 @@ int StringBuf_Append(struct StringBuf *buf1,const struct StringBuf *buf2) return (int)(buf1->ptr_ - buf1->buf_); } +// Appends str onto the end of buf +int StringBuf_AppendStr(struct StringBuf* sbuf, const char* str) +{ + int available = sbuf->max_ - (sbuf->ptr_ - sbuf->buf_); + int size = (int)strlen(str); + + if( size >= available ) + {// not enough space, expand the buffer (minimum expansion = 1024) + int off = (int)(sbuf->ptr_ - sbuf->buf_); + sbuf->max_ += max(size, 1024); + sbuf->buf_ = (char *) aRealloc(sbuf->buf_, sbuf->max_ + 1); + sbuf->ptr_ = sbuf->buf_ + off; + } + + memcpy(sbuf->ptr_, str, size); + sbuf->ptr_ += size; + return (int)(sbuf->ptr_ - sbuf->buf_); +} + +// Returns the length of the data in a Stringbuf +int StringBuf_Length(struct StringBuf *sbuf) +{ + return (int)(sbuf->ptr_ - sbuf->buf_); +} + // Destroy a StringBuf [MouseJstr] void StringBuf_Destroy(struct StringBuf *sbuf) { diff --git a/src/common/utils.h b/src/common/utils.h index 3ee419c6f..ec9cb5416 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -23,6 +23,8 @@ void StringBuf_Init(struct StringBuf *); int StringBuf_Vprintf(struct StringBuf *,const char *,va_list); int StringBuf_Printf(struct StringBuf *,const char *,...); int StringBuf_Append(struct StringBuf *,const struct StringBuf *); +int StringBuf_AppendStr(struct StringBuf* sbuf, const char* str); +int StringBuf_Length(struct StringBuf* sbuf); char * StringBuf_Value(struct StringBuf *); void StringBuf_Destroy(struct StringBuf *); void StringBuf_Free(struct StringBuf *); diff --git a/src/map/clif.c b/src/map/clif.c index 8b1dbc0a2..f3d18b702 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -10014,7 +10014,7 @@ void clif_parse_WeaponRefine(int fd, struct map_session_data *sd) { */ void clif_parse_NpcSelectMenu(int fd,struct map_session_data *sd) { - unsigned char select; + uint8 select; RFIFOHEAD(fd); select = RFIFOB(fd,6); diff --git a/src/map/map.h b/src/map/map.h index 0600729c3..7ce91c4c5 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -523,7 +523,7 @@ struct map_session_data { //status_calc_pc, while special_state is recalculated in each call. [Skotlex] struct { unsigned auth : 1; - unsigned menu_or_input : 1; + unsigned menu_or_input : 1;// if a script is waiting for feedback from the player unsigned dead_sit : 2; unsigned waitingdisconnect : 1; unsigned lr_flag : 2; diff --git a/src/map/script.c b/src/map/script.c index 0de86906c..56b7974c7 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -3876,11 +3876,15 @@ BUILDIN_FUNC(deletepset); // MouseJstr #endif struct script_function buildin_func[] = { + // NPC interaction BUILDIN_DEF(mes,"s"), BUILDIN_DEF(next,""), BUILDIN_DEF(close,""), BUILDIN_DEF(close2,""), - BUILDIN_DEF(menu,"*"), + BUILDIN_DEF(menu,"sl*"), + BUILDIN_DEF(select,"s*"), //for future jA script compatibility + BUILDIN_DEF(prompt,"s*"), + // BUILDIN_DEF(goto,"l"), BUILDIN_DEF(callsub,"i*"), BUILDIN_DEF(callfunc,"s*"), @@ -4130,8 +4134,6 @@ struct script_function buildin_func[] = { BUILDIN_DEF(getpetinfo,"i"), BUILDIN_DEF(checkequipedcard,"i"), BUILDIN_DEF(jump_zero,"ii"), //for future jA script compatibility - BUILDIN_DEF(select,"*"), //for future jA script compatibility - BUILDIN_DEF(prompt,"*"), BUILDIN_DEF(globalmes,"s*"), BUILDIN_DEF(getmapmobs,"s"), //end jA addition BUILDIN_DEF(unequip,"i"), // unequip command [Spectre] @@ -4209,36 +4211,373 @@ struct script_function buildin_func[] = { {NULL,NULL,NULL}, }; -/*========================================== - * - *------------------------------------------ - */ +///////////////////////////////////////////////////////////////////// +// NPC interaction +// + +/// Appends a message to the npc dialog. +/// If a dialog doesn't exist yet, one is created. +/// TODO does the client support dialogs with different oid's at the same time? +/// +/// mes "<message>"; BUILDIN_FUNC(mes) { - struct map_session_data *sd = script_rid2sd(st); - const char *mes = script_getstr(st, 2); - if (sd) - clif_scriptmes(sd, st->oid, mes); + TBL_PC* sd; + const char* msg; + + sd = script_rid2sd(st); + if( sd == NULL ) + return 1; + + msg = script_getstr(st, 2); + clif_scriptmes(sd, st->oid, msg); return 0; } -/*========================================== - * - *------------------------------------------ - */ -BUILDIN_FUNC(goto) +/// Displays the button 'next' in the npc dialog. +/// The dialog text is cleared and the script continues when the button is pressed. +/// +/// next; +BUILDIN_FUNC(next) { - int pos; + TBL_PC* sd; - if( !data_islabel(script_getdata(st,2))){ - ShowMessage("script: goto: not label!\n"); - st->state=END; + sd = script_rid2sd(st); + if( sd == NULL ) return 1; + + st->state = STOP; + clif_scriptnext(sd, st->oid); + return 0; +} + +/// Ends the script and displays the button 'close' on the npc dialog. +/// The dialog is closed when the button is pressed. +/// +/// close; +BUILDIN_FUNC(close) +{ + TBL_PC* sd; + + sd = script_rid2sd(st); + if( sd == NULL ) + return 1; + + st->state = END; + clif_scriptclose(sd, st->oid); + return 0; +} + +/// Displays the button 'close' on the npc dialog. +/// The dialog is closed and the script continues when the button is pressed. +/// +/// close2; +BUILDIN_FUNC(close2) +{ + TBL_PC* sd; + + sd = script_rid2sd(st); + if( sd == NULL ) + return 1; + + st->state = STOP; + clif_scriptclose(sd, st->oid); + return 0; +} + +/// Counts the number of valid and total number of options in 'str' +/// If max_count > 0 the counting stops when that valid option is reached +/// total is incremented for each option (NULL is supported) +static int menu_countoptions(const char* str, int max_count, int* total) +{ + int count = 0; + int bogus_total; + + if( total == NULL ) + total = &bogus_total; + ++(*total); + + // initial empty options + while( *str == ':' ) + { + ++str; + ++(*total); } + // count menu options + while( *str != '\0' ) + { + ++count; + --max_count; + if( max_count == 0 ) + break; + while( *str != ':' && *str != '\0' ) + ++str; + while( *str == ':' ) + { + ++str; + ++(*total); + } + } + return count; +} - pos=script_getnum(st,2); - st->pos=pos; - st->state=GOTO; +/// Displays a menu with options and goes to the target label. +/// The script is stopped if cancel is pressed. +/// Options with no text are not displayed in the client. +/// +/// Options can be grouped together, separated by the character ':' in the text: +/// ex: menu "A:B:C",L_target; +/// All these options go to the specified target label. +/// +/// The index of the selected option is put in the variable @menu. +/// Indexes start with 1 and are consistent with grouped and empty options. +/// ex: menu "A::B",-,"",L_Impossible,"C",-; +/// // displays "A", "B" and "C", corresponding to indexes 1, 3 and 5 +/// +/// NOTE: the client closes the npc dialog when cancel is pressed +/// +/// menu "<option_text>",<target_label>{,"<option_text>",<target_label>,...}; +BUILDIN_FUNC(menu) +{ + int i; + const char* text; + TBL_PC* sd; + + sd = script_rid2sd(st); + if( sd == NULL ) + return 1; + + // TODO detect multiple scripts waiting for input at the same time, and what to do when that happens + if( sd->state.menu_or_input == 0 ) + { + struct StringBuf* buf; + struct script_data* data; + + if( script_lastdata(st) % 2 == 0 ) + {// argument count is not even (1st argument is at index 2) + ShowError("script:menu: illegal number of arguments (%d).\n", (script_lastdata(st) - 1)); + st->state = END; + return 1; + } + buf = StringBuf_Malloc(); + for( i = 2, sd->npc_menu = 0; i < script_lastdata(st); i += 2 ) + { + // menu options + data = script_getdata(st, i); + get_val(st, data); + if( data_isstring(data) && data_isint(data) ) + {// not a string (or compatible) + StringBuf_Free(buf); + ShowError("script:menu: argument #%d (from 1) is not a string or compatible.\n", (i - 1)); + st->state = END; + return 1; + } + text = conv_str(st, data);// convert to string + + // target label + data = script_getdata(st, i+1); + if( !data_islabel(data) ) + {// not a label + StringBuf_Free(buf); + ShowError("script:menu: label argument of menu option #%d (from 1) is not a label.\n", (script_lastdata(st) - 1)); + st->state = END; + return 1; + } + + // append option(s) + if( text[0] == '\0' ) + continue;// empty string, ignore + if( sd->npc_menu > 0 ) + StringBuf_AppendStr(buf, ":"); + StringBuf_AppendStr(buf, text); + sd->npc_menu += menu_countoptions(text, 0, NULL); + } + st->state = RERUNLINE; + sd->state.menu_or_input = 1; + clif_scriptmenu(sd, st->oid, StringBuf_Value(buf)); + StringBuf_Free(buf); + //TODO what's the maximum number of options that can be displayed and/or received? -> give warning + } + else if( sd->npc_menu == 0xff ) + {// Cancel was pressed + sd->state.menu_or_input = 0; + st->state = END; + } + else + {// goto target label + int menu = 0; + + sd->state.menu_or_input = 0; + if( sd->npc_menu <= 0 ) + { + ShowDebug("script:menu: unexpected selection (%d)\n", sd->npc_menu); + st->state = END; + return 1; + } + + // get target label + for( i = 2; i < script_lastdata(st); i += 2 ) + { + text = script_getstr(st, i); + sd->npc_menu -= menu_countoptions(text, sd->npc_menu, &menu); + if( sd->npc_menu <= 0 ) + break;// entry found + } + if( sd->npc_menu > 0 ) + {// Invalid selection + ShowDebug("script:menu: selection is out of range, expected %d extra menu options\n", sd->npc_menu); + st->state = END; + return 1; + } + if( !data_islabel(script_getdata(st, i + 1)) ) + {// TODO remove this temporary crash-prevention code (fallback for multiple scripts requesting user input) + st->state = END; + return 0; + } + pc_setreg(sd, add_str("@menu"), menu); + st->pos = script_getnum(st, i + 1); + st->state = GOTO; + } + return 0; +} + +/// Displays a menu with options and returns the selected option. +/// Behaves like 'menu' without the target labels. +/// +/// select(<option_text>{,<option_text>,...}) -> <selected_option> +/// +/// @see menu +BUILDIN_FUNC(select) +{ + int i; + const char* text; + TBL_PC* sd; + + sd = script_rid2sd(st); + if( sd == NULL ) + return 1; + + if( sd->state.menu_or_input == 0 ) + { + struct StringBuf* buf; + + buf = StringBuf_Malloc(); + for( i = 2, sd->npc_menu = 0; i <= script_lastdata(st); ++i ) + { + text = script_getstr(st, i); + if( sd->npc_menu > 0 ) + StringBuf_AppendStr(buf, ":"); + StringBuf_AppendStr(buf, script_getstr(st, i)); + sd ->npc_menu += menu_countoptions(text, 0, NULL); + } + + st->state = RERUNLINE; + sd->state.menu_or_input = 1; + clif_scriptmenu(sd, st->oid, StringBuf_Value(buf)); + StringBuf_Free(buf); + } + else if( sd->npc_menu == 0xff ) + {// Cancel was pressed + sd->state.menu_or_input = 0; + st->state = END; + } + else + {// return selected option + int menu = 0; + + sd->state.menu_or_input = 0; + for( i = 2; i <= script_lastdata(st); ++i ) + { + text = script_getstr(st, i); + sd->npc_menu -= menu_countoptions(text, sd->npc_menu, &menu); + if( sd->npc_menu <= 0 ) + break;// entry found + } + pc_setreg(sd, add_str("@menu"), menu); + script_pushint(st, menu); + } + return 0; +} + +/// Displays a menu with options and returns the selected option. +/// Behaves like 'menu' without the target labels, except when cancel is +/// pressed. +/// When cancel is pressed, the script continues and 255 is returned. +/// +/// prompt(<option_text>{,<option_text>,...}) -> <selected_option> +/// +/// @see menu +BUILDIN_FUNC(prompt) +{ + int i; + const char *text; + TBL_PC* sd; + + sd = script_rid2sd(st); + if( sd == NULL ) + return 1; + + if( sd->state.menu_or_input == 0 ) + { + struct StringBuf* buf; + + buf = StringBuf_Malloc(); + for( i = 2, sd->npc_menu = 0; i <= script_lastdata(st); ++i ) + { + text = script_getstr(st, i); + if( sd->npc_menu > 0 ) + StringBuf_AppendStr(buf, ":"); + StringBuf_AppendStr(buf, script_getstr(st, i)); + sd ->npc_menu += menu_countoptions(text, 0, NULL); + } + + st->state = RERUNLINE; + sd->state.menu_or_input = 1; + clif_scriptmenu(sd, st->oid, StringBuf_Value(buf)); + StringBuf_Free(buf); + } + else if( sd->npc_menu == 0xff ) + {// Cancel was pressed + sd->state.menu_or_input = 0; + pc_setreg(sd, add_str("@menu"), 0xff); + script_pushint(st, 0xff); + } + else + {// return selected option + int menu = 0; + + sd->state.menu_or_input = 0; + for( i = 2; i <= script_lastdata(st); ++i ) + { + text = script_getstr(st, i); + sd->npc_menu -= menu_countoptions(text, sd->npc_menu, &menu); + if( sd->npc_menu <= 0 ) + break;// entry found + } + pc_setreg(sd, add_str("@menu"), menu); + script_pushint(st, menu); + } + return 0; +} + +///////////////////////////////////////////////////////////////////// +// ... +// + +/// Jumps to the target script label. +/// +/// goto <label>; +BUILDIN_FUNC(goto) +{ + if( !data_islabel(script_getdata(st,2)) ) + { + ShowError("script:goto: not label!\n"); + st->state = END; + return 1; + } + + st->pos = script_getnum(st,2); + st->state = GOTO; return 0; } @@ -4390,105 +4729,6 @@ BUILDIN_FUNC(return) return 0; } -/*========================================== - * - *------------------------------------------ - */ -BUILDIN_FUNC(next) -{ - st->state=STOP; - clif_scriptnext(script_rid2sd(st),st->oid); - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -BUILDIN_FUNC(close) -{ - st->state=END; - clif_scriptclose(script_rid2sd(st),st->oid); - return 0; -} -BUILDIN_FUNC(close2) -{ - st->state=STOP; - clif_scriptclose(script_rid2sd(st),st->oid); - return 0; -} - -/*========================================== - * - *------------------------------------------ - */ -BUILDIN_FUNC(menu) -{ - char *buf, *ptr; - int len,i; - struct map_session_data *sd = script_rid2sd(st); - - nullpo_retr(0, sd); - - if(sd->state.menu_or_input==0){ - st->state=RERUNLINE; - sd->state.menu_or_input=1; - if( (st->end - st->start - 2) % 2 == 1 ) { - // ˆø”‚Ì”‚ªŠï”‚Ȃ̂ŃGƒ‰[ˆµ‚¢ - ShowError("buildin_menu: illegal argument count(%d).\n", st->end - st->start - 2); - sd->state.menu_or_input=0; - st->state=END; - return 1; - } - for(i=st->start+2,len=0;i<st->end;i+=2){ - conv_str(st,& (st->stack->stack_data[i])); - len+=(int)strlen(st->stack->stack_data[i].u.str)+1; - } - buf=(char *)aMallocA((len+1)*sizeof(char)); - buf[0]=0; - for(i=st->start+2,len=0;i<st->end;i+=2){ - if( st->stack->stack_data[i].u.str[0] ) { - strcat(buf,st->stack->stack_data[i].u.str); - strcat(buf,":"); - } - } - - ptr = buf; - sd->npc_menu = 0; //Reuse to store max menu entries. Avoids the need of an extra variable. - while (ptr && (ptr = strchr(ptr, ':')) != NULL) - { sd->npc_menu++; ptr++; } - clif_scriptmenu(sd,st->oid,buf); - aFree(buf); - } else if(sd->npc_menu==0xff){ // cancel - sd->state.menu_or_input=0; - st->state=END; - } else { // goto“®ì - sd->state.menu_or_input=0; - if(sd->npc_menu>0){ - //Skip empty menu entries which weren't displayed on the client (blackhole89) - for(i=st->start+2;i<=(st->start+sd->npc_menu*2) && sd->npc_menu<(st->end-st->start)/2;i+=2) { - conv_str(st,& (st->stack->stack_data[i])); // we should convert variables to strings before access it [jA1983] [EoE] - if((int)strlen(st->stack->stack_data[i].u.str) < 1) - sd->npc_menu++; //Empty selection which wasn't displayed on the client. - } - if(sd->npc_menu >= (st->end-st->start)/2) { - //Invalid selection. - st->state=END; - return 0; - } - if( !data_islabel(script_getdata(st, sd->npc_menu*2+1)) ){ - ShowError("script: menu: not label !\n"); - st->state=END; - return 1; - } - pc_setreg(sd,add_str("@menu"),sd->npc_menu); - st->pos=script_getnum(st,sd->npc_menu*2+1); - st->state=GOTO; - } - } - return 0; -} - /// Returns a random number from 0 to <range>-1. /// Or returns a random number from <min> to <max>. /// If <min> is greater than <max>, their numbers are switched. @@ -10757,98 +10997,6 @@ BUILDIN_FUNC(jump_zero) return 0; } -BUILDIN_FUNC(select) -{ - char *buf, *ptr; - int len,i; - struct map_session_data *sd; - - sd=script_rid2sd(st); - nullpo_retr(0, sd); - if(sd->state.menu_or_input==0){ - st->state=RERUNLINE; - sd->state.menu_or_input=1; - for(i=st->start+2,len=16;i<st->end;i++){ - conv_str(st,& (st->stack->stack_data[i])); - len+=(int)strlen(st->stack->stack_data[i].u.str)+1; - } - buf=(char *)aMalloc((len+1)*sizeof(char)); - buf[0]=0; - for(i=st->start+2,len=0;i<st->end;i++){ - strcat(buf,st->stack->stack_data[i].u.str); - strcat(buf,":"); - } - - ptr = buf; - sd->npc_menu = 0; //Reuse to store max menu entries. Avoids the need of an extra variable. - while (ptr && (ptr = strchr(ptr, ':')) != NULL) - { sd->npc_menu++; ptr++; } - - clif_scriptmenu(sd,st->oid,buf); - aFree(buf); - } else if(sd->npc_menu==0xff){ - sd->state.menu_or_input=0; - st->state=END; - } else { - //Skip empty menu entries which weren't displayed on the client (Skotlex) - for(i=st->start+2;i< (st->start+2+sd->npc_menu) && sd->npc_menu < (st->end-st->start-2);i++) { - conv_str(st,& (st->stack->stack_data[i])); // we should convert variables to strings before access it [jA1983] [EoE] - if((int)strlen(st->stack->stack_data[i].u.str) < 1) - sd->npc_menu++; //Empty selection which wasn't displayed on the client. - } - pc_setreg(sd,add_str("@menu"),sd->npc_menu); - sd->state.menu_or_input=0; - script_pushint(st,sd->npc_menu); - } - return 0; -} - -BUILDIN_FUNC(prompt) -{ - char *buf, *ptr; - int len,i; - struct map_session_data *sd; - - sd=script_rid2sd(st); - nullpo_retr(0, sd); - - if(sd->state.menu_or_input==0){ - st->state=RERUNLINE; - sd->state.menu_or_input=1; - for(i=st->start+2,len=16;i<st->end;i++){ - conv_str(st,& (st->stack->stack_data[i])); - len+=(int)strlen(st->stack->stack_data[i].u.str)+1; - } - buf=(char *)aMalloc((len+1)*sizeof(char)); - buf[0]=0; - for(i=st->start+2,len=0;i<st->end;i++){ - strcat(buf,st->stack->stack_data[i].u.str); - strcat(buf,":"); - } - - ptr = buf; - sd->npc_menu = 0; //Reuse to store max menu entries. Avoids the need of an extra variable. - while (ptr && (ptr = strchr(ptr, ':')) != NULL) - { sd->npc_menu++; ptr++; } - - clif_scriptmenu(sd,st->oid,buf); - aFree(buf); - } else { - if(sd->npc_menu != 0xff){ - //Skip empty menu entries which weren't displayed on the client (Skotlex) - for(i=st->start+2;i< (st->start+2+sd->npc_menu) && sd->npc_menu < (st->end-st->start-2);i++) { - conv_str(st,& (st->stack->stack_data[i])); // we should convert variables to strings before access it [jA1983] [EoE] - if((int)strlen(st->stack->stack_data[i].u.str) < 1) - sd->npc_menu++; //Empty selection which wasn't displayed on the client. - } - } - pc_setreg(sd,add_str("@menu"),sd->npc_menu); - sd->state.menu_or_input=0; - script_pushint(st,sd->npc_menu); - } - return 0; -} - /*========================================== * GetMapMobs returns mob counts on a set map: |