diff options
-rw-r--r-- | doc/constants.md | 10 | ||||
-rw-r--r-- | doc/script_commands.txt | 52 | ||||
-rw-r--r-- | npc/dev/test.txt | 23 | ||||
-rw-r--r-- | src/map/date.c | 7 | ||||
-rw-r--r-- | src/map/date.h | 1 | ||||
-rw-r--r-- | src/map/pc.c | 3 | ||||
-rw-r--r-- | src/map/quest.c | 21 | ||||
-rw-r--r-- | src/map/quest.h | 2 | ||||
-rw-r--r-- | src/map/script.c | 170 | ||||
-rw-r--r-- | src/plugins/HPMHooking/HPMHooking.Defs.inc | 4 | ||||
-rw-r--r-- | src/plugins/HPMHooking/HPMHooking_map.Hooks.inc | 12 |
11 files changed, 278 insertions, 27 deletions
diff --git a/doc/constants.md b/doc/constants.md index 3f73182ae..40d9a2625 100644 --- a/doc/constants.md +++ b/doc/constants.md @@ -3984,6 +3984,16 @@ - `PERM_DISABLE_EXP`: 33554432 - `PERM_DISABLE_SKILL_USAGE`: 67108864 +### Data types + +- `DATATYPE_NIL`: 128 +- `DATATYPE_STR`: 256 +- `DATATYPE_INT`: 512 +- `DATATYPE_CONST`: 1024 +- `DATATYPE_PARAM`: 2048 +- `DATATYPE_VAR`: 4096 +- `DATATYPE_LABEL`: 8192 + ### Renewal - `RENEWAL`: 1 diff --git a/doc/script_commands.txt b/doc/script_commands.txt index e0e9646cd..9148e023c 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -3408,6 +3408,30 @@ Example : --------------------------------------- +*getcalendartime(<hour>, <minute>{, <day of month>{, <day of week>}}) + +This function returns the timestamp of the next ocurrence of given time. + +Day of Month specifies a day between 1 and 31 in the future, by default its value is -1 (don't use). +Day of Week specifies a day in the week and its valid values are: + 0 - SUNDAY + 1 - MONDAY + 2 - TUESDAY + 3 - WEDNESDAY + 4 - THURSDAY + 5 - FRIDAY + 6 - SATURDAY + +In order to use Day of Week, you must use Day of Month as -1. +If for some reason the command fails, it'll return -1. + +Examples : + getcalendartime(19, 00); // Next 7 pm + getcalendartime(19, 00, 6); // Next day 6 of the month, at 7pm + getcalendartime(19, 10, -1, 1); // Next Monday, at 7:10pm + +--------------------------------------- + *gettimestr(<format string>, <max length>) This function will return a string containing time data as specified by @@ -8337,6 +8361,30 @@ Example: --------------------------------------- +*getdatatype(<argument>) + +This command returns the raw type of the given <argument>. Unlike +isstr, this command does not evaluate the argument. The returned type +is bitmasked. + +types include: + + DATATYPE_NIL + DATATYPE_STR + DATATYPE_INT + DATATYPE_CONST + DATATYPE_PARAM + DATATYPE_VAR + DATATYPE_LABEL + +Example: + + getdatatype() // DATATYPE_NIL + getdatatype("foo") // DATATYPE_STR + getdatatype(@foo$) // (DATATYPE_VAR | DATATYPE_STR) + +--------------------------------------- + *charisalpha("<string>", <position>) This function will return true if the character number Position in the given @@ -9128,9 +9176,11 @@ Example --------------------------------------- -*setquest(<ID>) +*setquest(<ID>{, <Time Limit>}) Place quest of <ID> in the users quest log, the state of which is "active". +If Time Limit is given, this quest will have its expire time set to <Time Limit>, an UNIX epoch time, +ignoring quest_db setting. If questinfo() is set, and the same ID is specified here, the icon will be cleared when the quest is set. diff --git a/npc/dev/test.txt b/npc/dev/test.txt index b35beb8ed..a6f89f857 100644 --- a/npc/dev/test.txt +++ b/npc/dev/test.txt @@ -9,8 +9,8 @@ //= This file is part of Hercules. //= http://herc.ws - http://github.com/HerculesWS/Hercules //= -//= Copyright (C) 2013-2015 Hercules Dev Team -//= Copyright (C) 2013-2015 Haru +//= Copyright (C) 2013-2017 Hercules Dev Team +//= Copyright (C) 2013-2017 Haru //= //= Hercules is free software: you can redistribute it and/or modify //= it under the terms of the GNU General Public License as published by @@ -742,6 +742,19 @@ function script HerculesSelfTestHelper { callsub(OnCheckStr, "sprintf (positional)", sprintf("'%2$+05d'", 5, 6), "'+0006'"); callsub(OnCheckStr, "sprintf (positional)", sprintf("'%2$s' '%1$c'", "First", "Second"), "'Second' 'F'"); + callsub(OnCheck, "Getdatatype (integer)", getdatatype(5), DATATYPE_INT); + callsub(OnCheck, "Getdatatype (constant string)", getdatatype("foo"), DATATYPE_STR | DATATYPE_CONST); + callsub(OnCheck, "Getdatatype (parameter)", getdatatype(Hp), DATATYPE_INT | DATATYPE_PARAM); + callsub(OnCheck, "Getdatatype (numeric variable)", getdatatype(.@x), DATATYPE_INT | DATATYPE_VAR); + callsub(OnCheck, "Getdatatype (string variable)", getdatatype(.@x$), DATATYPE_STR | DATATYPE_VAR); + callsub(OnCheck, "Getdatatype (label)", getdatatype(OnTestGetdatatype), DATATYPE_LABEL); + //callsub(OnCheck, "Getdatatype (constant)", getdatatype(DATATYPE_CONST), DATATYPE_CONST); // FIXME + callsub(OnCheck, "Getdatatype (returned integer)", getdatatype(callsub(OnTestReturnValue, 5)), DATATYPE_INT); + callsub(OnCheck, "Getdatatype (returned string)", getdatatype(callsub(OnTestReturnValue, "foo")), DATATYPE_STR | DATATYPE_CONST); + callsub(OnCheck, "Getdatatype (getarg default value)", callsub(OnTestGetdatatypeDefault), DATATYPE_INT); + callsub(OnCheck, "Getdatatype (getarg integer value)", callsub(OnTestGetdatatype, 5), DATATYPE_INT); + callsub(OnCheck, "Getdatatype (getarg string)", callsub(OnTestGetdatatype, "foo"), DATATYPE_STR | DATATYPE_CONST); + if (.errors) { debugmes "Script engine self-test [ \033[0;31mFAILED\033[0m ]"; debugmes "**** The test was completed with " + .errors + " errors. ****"; @@ -786,6 +799,12 @@ OnTestScopeArrays: OnTestVarOfAnotherNPC: return getvariableofnpc(.x, getarg(0)); +OnTestGetdatatypeDefault: + return getdatatype(getarg(0, 0)); + +OnTestGetdatatype: + return getdatatype(getarg(0)); + OnReportError: .@msg$ = getarg(0,"Unknown Error"); .@val$ = getarg(1,""); diff --git a/src/map/date.c b/src/map/date.c index a20578e51..20ab9fe95 100644 --- a/src/map/date.c +++ b/src/map/date.c @@ -77,6 +77,13 @@ int date_get_sec(void) return lt->tm_sec; } +int date_get_dayofweek(void) +{ + time_t t = time(NULL); + struct tm *lt = localtime(&t); + return lt->tm_wday; +} + /*========================================== * Star gladiator related checks *------------------------------------------*/ diff --git a/src/map/date.h b/src/map/date.h index 3a109d1ad..ac0a3a7fa 100644 --- a/src/map/date.h +++ b/src/map/date.h @@ -31,6 +31,7 @@ int date_get_day(void); int date_get_hour(void); int date_get_min(void); int date_get_sec(void); +int date_get_dayofweek(void); bool is_day_of_sun(void); bool is_day_of_moon(void); diff --git a/src/map/pc.c b/src/map/pc.c index aedb029b6..a925b523c 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -5118,9 +5118,8 @@ int pc_useitem(struct map_session_data *sd,int n) { clif->msgtable_num(sd, MSG_SECONDS_UNTIL_USE, delay_tick + 1); // [%d] seconds left until you can use #else char delay_msg[100]; - clif->msgtable_num(sd, MSG_SECONDS_UNTIL_USE, delay_tick + 1); // [%d] seconds left until you can use sprintf(delay_msg, msg_sd(sd, 26), delay_tick + 1); - clif->messagecolor_self(sd->fd, COLOR_YELLOW, delay_msg); + clif->messagecolor_self(sd->fd, COLOR_YELLOW, delay_msg); // [%d] seconds left until you can use #endif return 0; // Delay has not expired yet } diff --git a/src/map/quest.c b/src/map/quest.c index ed8e5bd33..4e3362adb 100644 --- a/src/map/quest.c +++ b/src/map/quest.c @@ -103,22 +103,23 @@ int quest_pc_login(struct map_session_data *sd) * * New quest will be added as Q_ACTIVE. * - * @param sd Player's data - * @param quest_id ID of the quest to add. + * @param sd Player's data + * @param quest_id ID of the quest to add. + * @param time_limit Custom time, in UNIX epoch, for this quest * @return 0 in case of success, nonzero otherwise */ -int quest_add(struct map_session_data *sd, int quest_id) +int quest_add(struct map_session_data *sd, int quest_id, unsigned int time_limit) { int n; struct quest_db *qi = quest->db(quest_id); nullpo_retr(-1, sd); - if( qi == &quest->dummy ) { + if (qi == &quest->dummy) { ShowError("quest_add: quest %d not found in DB.\n", quest_id); return -1; } - if( quest->check(sd, quest_id, HAVEQUEST) >= 0 ) { + if (quest->check(sd, quest_id, HAVEQUEST) >= 0) { ShowError("quest_add: Character %d already has quest %d.\n", sd->status.char_id, quest_id); return -1; } @@ -130,7 +131,7 @@ int quest_add(struct map_session_data *sd, int quest_id) sd->avail_quests++; RECREATE(sd->quest_log, struct quest, sd->num_quests); - if( sd->avail_quests != sd->num_quests ) { + if (sd->avail_quests != sd->num_quests) { // The character has some completed quests, make room before them so that they will stay at the end of the array memmove(&sd->quest_log[n+1], &sd->quest_log[n], sizeof(struct quest)*(sd->num_quests-sd->avail_quests)); } @@ -138,7 +139,9 @@ int quest_add(struct map_session_data *sd, int quest_id) memset(&sd->quest_log[n], 0, sizeof(struct quest)); sd->quest_log[n].quest_id = qi->id; - if( qi->time ) + if (time_limit != 0) + sd->quest_log[n].time = time_limit; + else if (qi->time != 0) sd->quest_log[n].time = (unsigned int)(time(NULL) + qi->time); sd->quest_log[n].state = Q_ACTIVE; @@ -147,8 +150,8 @@ int quest_add(struct map_session_data *sd, int quest_id) clif->quest_add(sd, &sd->quest_log[n]); clif->quest_update_objective(sd, &sd->quest_log[n]); - if( map->save_settings&64 ) - chrif->save(sd,0); + if ((map->save_settings & 64) != 0) + chrif->save(sd, 0); return 0; } diff --git a/src/map/quest.h b/src/map/quest.h index 8837a1fb6..dda7c2c0a 100644 --- a/src/map/quest.h +++ b/src/map/quest.h @@ -69,7 +69,7 @@ struct quest_interface { /* */ struct quest_db *(*db) (int quest_id); int (*pc_login) (struct map_session_data *sd); - int (*add) (struct map_session_data *sd, int quest_id); + int (*add) (struct map_session_data *sd, int quest_id, unsigned int time_limit); int (*change) (struct map_session_data *sd, int qid1, int qid2); int (*delete) (struct map_session_data *sd, int quest_id); int (*update_objective_sub) (struct block_list *bl, va_list ap); diff --git a/src/map/script.c b/src/map/script.c index 69c210b28..628598584 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -30,6 +30,7 @@ #include "map/chat.h" #include "map/chrif.h" #include "map/clif.h" +#include "map/date.h" #include "map/elemental.h" #include "map/guild.h" #include "map/homunculus.h" @@ -16218,6 +16219,60 @@ BUILDIN(isstr) return true; } +enum datatype { + DATATYPE_NIL = 1 << 7, // we don't start at 1, to leave room for primitives + DATATYPE_STR = 1 << 8, + DATATYPE_INT = 1 << 9, + DATATYPE_CONST = 1 << 10, + DATATYPE_PARAM = 1 << 11, + DATATYPE_VAR = 1 << 12, + DATATYPE_LABEL = 1 << 13, +}; + +BUILDIN(getdatatype) { + int type; + + if (script_hasdata(st, 2)) { + struct script_data *data = script_getdata(st, 2); + + if (data_isstring(data)) { + type = DATATYPE_STR; + if (data->type == C_CONSTSTR) { + type |= DATATYPE_CONST; + } + } else if (data_isint(data)) { + type = DATATYPE_INT; + } else if (data_islabel(data)) { + type = DATATYPE_LABEL; + } else if (data_isreference(data)) { + if (reference_toconstant(data)) { + type = DATATYPE_CONST | DATATYPE_INT; + } else if (reference_toparam(data)) { + type = DATATYPE_PARAM | DATATYPE_INT; + } else if (reference_tovariable(data)) { + type = DATATYPE_VAR; + if (is_string_variable(reference_getname(data))) { + type |= DATATYPE_STR; + } else { + type |= DATATYPE_INT; + } + } else { + ShowError("script:getdatatype: Unknown reference type!\n"); + script->reportdata(data); + st->state = END; + return false; + } + } else { + type = data->type; // fallback to primitive type if unknown + } + } else { + type = DATATYPE_NIL; // nothing was passed + } + + script_pushint(st, type); + return true; +} + //======================================================= // chr <int> //------------------------------------------------------- @@ -20283,19 +20338,21 @@ BUILDIN(setquest) { unsigned short i; int quest_id; + unsigned int time_limit; struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) return true; quest_id = script_getnum(st, 2); + time_limit = script_hasdata(st, 3) ? script_getnum(st, 3) : 0; - quest->add(sd, quest_id); + quest->add(sd, quest_id, time_limit); // If questinfo is set, remove quest bubble once quest is set. - for(i = 0; i < map->list[sd->bl.m].qi_count; i++) { + for (i = 0; i < map->list[sd->bl.m].qi_count; i++) { struct questinfo *qi = &map->list[sd->bl.m].qi_data[i]; - if( qi->quest_id == quest_id ) { + if (qi->quest_id == quest_id) { #if PACKETVER >= 20120410 clif->quest_show_event(sd, &qi->nd->bl, 9999, 0); #else @@ -23156,6 +23213,100 @@ BUILDIN(mergeitem) return true; } +// getcalendartime(<day of month>, <day of week>{, <hour>{, <minute>}}); +// Returns the UNIX Timestamp of next ocurrency of given time +BUILDIN(getcalendartime) +{ + struct tm info = { 0 }; + int day_of_month = script_hasdata(st, 4) ? script_getnum(st, 4) : -1; + int day_of_week = script_hasdata(st, 5) ? script_getnum(st, 5) : -1; + int year = date_get_year(); + int month = date_get_month(); + int day = date_get_day(); + int cur_hour = date_get_hour(); + int cur_min = date_get_min(); + int hour = script_getnum(st, 2); + int minute = script_getnum(st, 3); + + info.tm_sec = 0; + info.tm_min = minute; + info.tm_hour = hour; + info.tm_mday = day; + info.tm_mon = month - 1; + info.tm_year = year - 1900; + + if (day_of_month > -1 && day_of_week > -1) { + ShowError("script:getcalendartime: You must only specify a day_of_week or a day_of_month, not both\n"); + script_pushint(st, -1); + return false; + } + if (day_of_month > -1 && (day_of_month < 1 || day_of_month > 31)) { + ShowError("script:getcalendartime: Day of Month in invalid range. Must be between 1 and 31.\n"); + script_pushint(st, -1); + return false; + } + if (day_of_week > -1 && (day_of_week < 0 || day_of_week > 6)) { + ShowError("script:getcalendartime: Day of Week in invalid range. Must be between 0 and 6.\n"); + script_pushint(st, -1); + return false; + } + if (hour > -1 && (hour > 23)) { + ShowError("script:getcalendartime: Hour in invalid range. Must be between 0 and 23.\n"); + script_pushint(st, -1); + return false; + } + if (minute > -1 && (minute > 59)) { + ShowError("script:getcalendartime: Minute in invalid range. Must be between 0 and 59.\n"); + script_pushint(st, -1); + return false; + } + if (hour == -1 || minute == -1) { + ShowError("script:getcalendartime: Minutes and Hours are required\n"); + script_pushint(st, -1); + return false; + } + + if (day_of_month > -1) { + if (day_of_month < day) { // Next Month + info.tm_mon++; + } else if (day_of_month == day) { // Today + if (hour < cur_hour || (hour == cur_hour && minute < cur_min)) { // But past time, next month + info.tm_mon++; + } + } + + // Loops until month has finding a month that has day_of_month + do { + time_t t; + struct tm *lt; + info.tm_mday = day_of_month; + t = mktime(&info); + lt = localtime(&t); + info = *lt; + } while (info.tm_mday != day_of_month); + } else if (day_of_week > -1) { + int cur_wday = date_get_dayofweek(); + + if (day_of_week > cur_wday) { // This week + info.tm_mday += (day_of_week - cur_wday); + } else if (day_of_week == cur_wday) { // Today + if (hour < cur_hour || (hour == cur_hour && minute <= cur_min)) { + info.tm_mday += 7; // Next week + } + } else if (day_of_week < cur_wday) { // Next week + info.tm_mday += (7 - cur_wday + day_of_week); + } + } else if (day_of_week == -1 && day_of_month == -1) { // Next occurence of hour/min + if (hour < cur_hour || (hour == cur_hour && minute < cur_min)) { + info.tm_mday++; + } + } + + script_pushint(st, mktime(&info)); + + return true; +} + /** place holder for the translation macro **/ BUILDIN(_) { @@ -23662,6 +23813,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(charisalpha,"si"), //isalpha [Valaris] BUILDIN_DEF(charat,"si"), BUILDIN_DEF(isstr,"v"), + BUILDIN_DEF(getdatatype, "?"), BUILDIN_DEF(chr,"i"), BUILDIN_DEF(ord,"s"), BUILDIN_DEF(setchar,"ssi"), @@ -23864,7 +24016,7 @@ void script_parse_builtin(void) { //Quest Log System [Inkfish] BUILDIN_DEF(questinfo, "ii??"), - BUILDIN_DEF(setquest, "i"), + BUILDIN_DEF(setquest, "i?"), BUILDIN_DEF(erasequest, "i?"), BUILDIN_DEF(completequest, "i?"), BUILDIN_DEF(questprogress, "i?"), @@ -23916,6 +24068,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(removechannelhandler, "ss"), BUILDIN_DEF(showscript, "s?"), BUILDIN_DEF(mergeitem,""), + BUILDIN_DEF(getcalendartime, "ii??"), BUILDIN_DEF(_,"s"), BUILDIN_DEF2(_, "_$", "s"), }; @@ -24135,6 +24288,15 @@ void script_hardcoded_constants(void) script->set_constant("PERM_DISABLE_EXP", PC_PERM_DISABLE_EXP, false, false); script->set_constant("PERM_DISABLE_SKILL_USAGE", PC_PERM_DISABLE_SKILL_USAGE, false, false); + script->constdb_comment("Data types"); + script->set_constant("DATATYPE_NIL", DATATYPE_NIL, false, false); + script->set_constant("DATATYPE_STR", DATATYPE_STR, false, false); + script->set_constant("DATATYPE_INT", DATATYPE_INT, false, false); + script->set_constant("DATATYPE_CONST", DATATYPE_CONST, false, false); + script->set_constant("DATATYPE_PARAM", DATATYPE_PARAM, false, false); + script->set_constant("DATATYPE_VAR", DATATYPE_VAR, false, false); + script->set_constant("DATATYPE_LABEL", DATATYPE_LABEL, false, false); + script->constdb_comment("Renewal"); #ifdef RENEWAL script->set_constant("RENEWAL", 1, false, false); diff --git a/src/plugins/HPMHooking/HPMHooking.Defs.inc b/src/plugins/HPMHooking/HPMHooking.Defs.inc index b4be9aff4..28009ff7a 100644 --- a/src/plugins/HPMHooking/HPMHooking.Defs.inc +++ b/src/plugins/HPMHooking/HPMHooking.Defs.inc @@ -5738,8 +5738,8 @@ typedef struct quest_db* (*HPMHOOK_pre_quest_db) (int *quest_id); typedef struct quest_db* (*HPMHOOK_post_quest_db) (struct quest_db* retVal___, int quest_id); typedef int (*HPMHOOK_pre_quest_pc_login) (struct map_session_data **sd); typedef int (*HPMHOOK_post_quest_pc_login) (int retVal___, struct map_session_data *sd); -typedef int (*HPMHOOK_pre_quest_add) (struct map_session_data **sd, int *quest_id); -typedef int (*HPMHOOK_post_quest_add) (int retVal___, struct map_session_data *sd, int quest_id); +typedef int (*HPMHOOK_pre_quest_add) (struct map_session_data **sd, int *quest_id, unsigned int *time_limit); +typedef int (*HPMHOOK_post_quest_add) (int retVal___, struct map_session_data *sd, int quest_id, unsigned int time_limit); typedef int (*HPMHOOK_pre_quest_change) (struct map_session_data **sd, int *qid1, int *qid2); typedef int (*HPMHOOK_post_quest_change) (int retVal___, struct map_session_data *sd, int qid1, int qid2); typedef int (*HPMHOOK_pre_quest_delete) (struct map_session_data **sd, int *quest_id); diff --git a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc index 4bd397240..3bde41022 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc @@ -60383,15 +60383,15 @@ int HP_quest_pc_login(struct map_session_data *sd) { } return retVal___; } -int HP_quest_add(struct map_session_data *sd, int quest_id) { +int HP_quest_add(struct map_session_data *sd, int quest_id, unsigned int time_limit) { int hIndex = 0; int retVal___ = 0; if (HPMHooks.count.HP_quest_add_pre > 0) { - int (*preHookFunc) (struct map_session_data **sd, int *quest_id); + int (*preHookFunc) (struct map_session_data **sd, int *quest_id, unsigned int *time_limit); *HPMforce_return = false; for (hIndex = 0; hIndex < HPMHooks.count.HP_quest_add_pre; hIndex++) { preHookFunc = HPMHooks.list.HP_quest_add_pre[hIndex].func; - retVal___ = preHookFunc(&sd, &quest_id); + retVal___ = preHookFunc(&sd, &quest_id, &time_limit); } if (*HPMforce_return) { *HPMforce_return = false; @@ -60399,13 +60399,13 @@ int HP_quest_add(struct map_session_data *sd, int quest_id) { } } { - retVal___ = HPMHooks.source.quest.add(sd, quest_id); + retVal___ = HPMHooks.source.quest.add(sd, quest_id, time_limit); } if (HPMHooks.count.HP_quest_add_post > 0) { - int (*postHookFunc) (int retVal___, struct map_session_data *sd, int quest_id); + int (*postHookFunc) (int retVal___, struct map_session_data *sd, int quest_id, unsigned int time_limit); for (hIndex = 0; hIndex < HPMHooks.count.HP_quest_add_post; hIndex++) { postHookFunc = HPMHooks.list.HP_quest_add_post[hIndex].func; - retVal___ = postHookFunc(retVal___, sd, quest_id); + retVal___ = postHookFunc(retVal___, sd, quest_id, time_limit); } } return retVal___; |