From 3f6b7497531f9ace331ca74d271898e938245c04 Mon Sep 17 00:00:00 2001 From: Carlos Date: Tue, 18 Sep 2018 17:10:35 -0300 Subject: Added ifdef on mmo.h to allow change it with CPPFLAGS --- src/common/mmo.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src') diff --git a/src/common/mmo.h b/src/common/mmo.h index 9bcf82cc7..78a14e20c 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -132,7 +132,9 @@ #endif // PACKETVER_RE && (PACKETVER == 20120410 || PACKETVER == 10120418) // Comment the following line to disable sc_data saving. [Skotlex] +#ifndef ENABLE_SC_SAVING #define ENABLE_SC_SAVING +#endif #if PACKETVER >= 20070227 // Comment the following like to disable server-side hot-key saving support. [Skotlex] @@ -163,9 +165,13 @@ #else #define MAX_BASE_CARTS 5 #endif +#ifndef MAX_CARTS #define MAX_CARTS (MAX_BASE_CARTS + MAX_CARTDECORATION_CARTS) +#endif +#ifndef MAX_INVENTORY #define MAX_INVENTORY 100 +#endif //Max number of characters per account. Note that changing this setting alone is not enough if the client is not hexed to support more characters as well. #if PACKETVER >= 20100413 #ifndef MAX_CHARS @@ -178,19 +184,31 @@ #endif //Number of slots carded equipment can have. Never set to less than 4 as they are also used to keep the data of forged items/equipment. [Skotlex] //Note: The client seems unable to receive data for more than 4 slots due to all related packets having a fixed size. +#ifndef MAX_SLOTS #define MAX_SLOTS 4 +#endif //Max amount of a single stacked item +#ifndef MAX_AMOUNT #define MAX_AMOUNT 30000 +#endif +#ifndef MAX_ZENY #define MAX_ZENY INT_MAX +#endif //Official Limit: 2.1b ( the var that stores the money doesn't go much higher than this by default ) +#ifndef MAX_BANK_ZENY #define MAX_BANK_ZENY INT_MAX +#endif #ifndef MAX_LEVEL #define MAX_LEVEL 175 #endif +#ifndef MAX_FAME #define MAX_FAME 1000000000 +#endif +#ifndef MAX_CART #define MAX_CART 100 +#endif #ifndef MAX_SKILL_DB #define MAX_SKILL_DB 1510 ///< Maximum number of skills in the skill DB (compacted array size) #endif -- cgit v1.2.3-70-g09d2 From 6b3d80109c2076a271a2f668ab2536814ca72d83 Mon Sep 17 00:00:00 2001 From: gumi Date: Sat, 28 Mar 2020 16:56:20 -0400 Subject: add support for binary and octal number literals --- src/common/cbasetypes.h | 4 ++- src/map/script.c | 89 ++++++++++++++++++++++++++++++++++++------------- 2 files changed, 69 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/common/cbasetypes.h b/src/common/cbasetypes.h index 0b5613316..3ca0c5f67 100644 --- a/src/common/cbasetypes.h +++ b/src/common/cbasetypes.h @@ -410,13 +410,15 @@ typedef char bool; #define ISALPHA(c) (isalpha((unsigned char)(c))) #define ISCNTRL(c) (iscntrl((unsigned char)(c))) #define ISDIGIT(c) (isdigit((unsigned char)(c))) +#define ISXDIGIT(c) (isxdigit((unsigned char)(c))) +#define ISBDIGIT(c) ((unsigned char)(c) == '0' || (unsigned char)(c) == '1') +#define ISODIGIT(c) ((unsigned char)(c) >= '0' && (unsigned char)(c) <= '7') #define ISGRAPH(c) (isgraph((unsigned char)(c))) #define ISLOWER(c) (islower((unsigned char)(c))) #define ISPRINT(c) (isprint((unsigned char)(c))) #define ISPUNCT(c) (ispunct((unsigned char)(c))) #define ISSPACE(c) (isspace((unsigned char)(c))) #define ISUPPER(c) (isupper((unsigned char)(c))) -#define ISXDIGIT(c) (isxdigit((unsigned char)(c))) #define TOASCII(c) (toascii((unsigned char)(c))) #define TOLOWER(c) (tolower((unsigned char)(c))) #define TOUPPER(c) (toupper((unsigned char)(c))) diff --git a/src/map/script.c b/src/map/script.c index b8a7979a7..d5e73ad65 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -1161,6 +1161,41 @@ static const char *parse_variable(const char *p) return p; } +/** + * converts a number expression literal to an actual integer +*/ +static long long parse_number(const char *p, char **np) { + long long lli = 0; + unsigned char radix = 10; + + nullpo_retr(lli, p); + + if (*p == '0' && p[1] == 'x') { + p += 2; + radix = 16; // hexadecimal + } else if (*p == '0' && p[1] == 'o') { + p += 2; + radix = 8; // octal + } else if (*p == '0' && p[1] == 'b') { + p += 2; + radix = 2; // binary + } + + // actual parsing happens here + lli = strtoll(p, np, radix); + + // make sure we can't underflow/overflow + if (lli < INT_MIN) { + lli = INT_MIN; + script->disp_warning_message("parse_number: underflow detected, capping value to INT_MIN", p); + } else if (lli > INT_MAX) { + lli = INT_MAX; + script->disp_warning_message("parse_number: overflow detected, capping value to INT_MAX", p); + } + + return lli; +} + /* * Checks whether the gives string is a number literal * @@ -1177,24 +1212,44 @@ static const char *parse_variable(const char *p) static bool is_number(const char *p) { const char *np; - if (!p) - return false; - if (*p == '-' || *p == '+') + nullpo_retr(false, p); + + if (*p == '-' || *p == '+') { p++; + } + np = p; + if (*p == '0' && p[1] == 'x') { - p+=2; - np = p; - // Hexadecimal - while (ISXDIGIT(*np)) + // Hexadecimal: 0xFFFF + np = p += 2; + while (ISXDIGIT(*np)) { np++; + } + } else if (*p == '0' && p[1] == 'b') { + // Binary: 0b0001 + np = p += 2; + while (ISBDIGIT(*np)) { + np++; + } + } else if (*p == '0' && p[1] == 'o') { + // Octal: 0o1500 + np = p += 2; + while (ISODIGIT(*np)) { + np++; + } } else { - // Decimal - while (ISDIGIT(*np)) + // Decimal: 1234 + while (ISDIGIT(*np)) { np++; + } } - if (p != np && *np != '_' && !ISALPHA(*np)) // At least one digit, and next isn't a letter or _ + + if (p != np && *np != '_' && !ISALPHA(*np)) { + // At least one digit, and next isn't a letter or _ return true; + } + return false; } @@ -1276,20 +1331,8 @@ static const char *parse_simpleexpr_paren(const char *p) static const char *parse_simpleexpr_number(const char *p) { char *np = NULL; - long long lli; + long long lli = parse_number(p, &np); - nullpo_retr(NULL, p); - while (*p == '0' && ISDIGIT(p[1])) - p++; // Skip leading zeros, we don't support octal literals - - lli = strtoll(p, &np, 0); - if (lli < INT_MIN) { - lli = INT_MIN; - script->disp_warning_message("parse_simpleexpr: underflow detected, capping value to INT_MIN", p); - } else if (lli > INT_MAX) { - lli = INT_MAX; - script->disp_warning_message("parse_simpleexpr: overflow detected, capping value to INT_MAX", p); - } script->addi((int)lli); // Cast is safe, as it's already been checked for overflows return np; -- cgit v1.2.3-70-g09d2 From 776755bd02919ea4a5101671c0d86534a2ce8674 Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Sat, 2 May 2020 04:21:49 +0200 Subject: Implement status icon display for SC_ARMOR_RESIST --- src/map/status.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'src') diff --git a/src/map/status.c b/src/map/status.c index d3e85e5be..c502086cf 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -8699,6 +8699,32 @@ static int status_change_start_sub(struct block_list *src, struct block_list *bl //associated, and yet are not wrong/unknown. [Skotlex] //break; } + case SC_ARMOR_RESIST: + if (val1 > 0) { + int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WATER); + int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WATER); + clif->status_change(bl, sc_icn, sc_typ, 1, total_tick, 0, 0, 0); + } + + if (val2 > 0) { + int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_GROUND); + int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_GROUND); + clif->status_change(bl, sc_icn, sc_typ, 1, total_tick, 0, 0, 0); + } + + if (val3 > 0) { + int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_FIRE); + int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_FIRE); + clif->status_change(bl, sc_icn, sc_typ, 1, total_tick, 0, 0, 0); + } + + if (val4 > 0) { + int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WIND); + int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WIND); + clif->status_change(bl, sc_icn, sc_typ, 1, total_tick, 0, 0, 0); + } + + break; case SC_MER_FLEE: case SC_MER_ATK: case SC_MER_HIT: @@ -11056,6 +11082,20 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid, break; } break; + case SC_ARMOR_RESIST: + if (sce->val1 > 0) + clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WATER)); + + if (sce->val2 > 0) + clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_GROUND)); + + if (sce->val3 > 0) + clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_FIRE)); + + if (sce->val4 > 0) + clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WIND)); + + break; } opt_flag = 1; -- cgit v1.2.3-70-g09d2 From 8194350f0bad88086edf0e7a001b9f41df904099 Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Sat, 2 May 2020 04:52:55 +0200 Subject: Implement SC_RESIST_PROPERTY_WATER logic --- src/map/status.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src') diff --git a/src/map/status.c b/src/map/status.c index c502086cf..4f2ebe3db 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -865,6 +865,7 @@ static void initChangeTables(void) status->dbs->ChangeFlagTable[SC_WEDDING] |= SCB_SPEED; status->dbs->ChangeFlagTable[SC_ARMORPROPERTY] |= SCB_ALL; status->dbs->ChangeFlagTable[SC_ARMOR_RESIST] |= SCB_ALL; + status->dbs->ChangeFlagTable[SC_RESIST_PROPERTY_WATER] |= SCB_ALL; status->dbs->ChangeFlagTable[SC_ATKER_BLOOD] |= SCB_ALL; status->dbs->ChangeFlagTable[SC_WALKSPEED] |= SCB_SPEED; status->dbs->ChangeFlagTable[SC_TARGET_BLOOD] |= SCB_ALL; @@ -3029,6 +3030,10 @@ static int status_calc_pc_(struct map_session_data *sd, enum e_status_calc_opt o sd->subele[ELE_FIRE] += sc->data[SC_ARMOR_RESIST]->val3; sd->subele[ELE_WIND] += sc->data[SC_ARMOR_RESIST]->val4; } + if (sc->data[SC_RESIST_PROPERTY_WATER] != NULL) { // Coldproof Potion + sd->subele[ELE_WATER] += sc->data[SC_RESIST_PROPERTY_WATER]->val1; + sd->subele[ELE_WIND] += sc->data[SC_RESIST_PROPERTY_WATER]->val2; + } if (sc->data[SC_FIRE_CLOAK_OPTION]) { i = sc->data[SC_FIRE_CLOAK_OPTION]->val2; sd->subele[ELE_FIRE] += i; @@ -7753,6 +7758,7 @@ static int status_change_start_sub(struct block_list *src, struct block_list *bl case SC_ENCHANTARMS: case SC_ARMORPROPERTY: case SC_ARMOR_RESIST: + case SC_RESIST_PROPERTY_WATER: break; case SC_GOSPEL: //Must not override a casting gospel char. @@ -8724,6 +8730,11 @@ static int status_change_start_sub(struct block_list *src, struct block_list *bl clif->status_change(bl, sc_icn, sc_typ, 1, total_tick, 0, 0, 0); } + break; + case SC_RESIST_PROPERTY_WATER: + if (val1 <= 0) + flag |= SCFLAG_NOICON; + break; case SC_MER_FLEE: case SC_MER_ATK: -- cgit v1.2.3-70-g09d2 From 5bb28472659689a517dc14fcbcc5041a9f2e9224 Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Sat, 2 May 2020 04:59:53 +0200 Subject: Implement SC_RESIST_PROPERTY_GROUND logic --- src/map/status.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/map/status.c b/src/map/status.c index 4f2ebe3db..069fd0580 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -866,6 +866,7 @@ static void initChangeTables(void) status->dbs->ChangeFlagTable[SC_ARMORPROPERTY] |= SCB_ALL; status->dbs->ChangeFlagTable[SC_ARMOR_RESIST] |= SCB_ALL; status->dbs->ChangeFlagTable[SC_RESIST_PROPERTY_WATER] |= SCB_ALL; + status->dbs->ChangeFlagTable[SC_RESIST_PROPERTY_GROUND] |= SCB_ALL; status->dbs->ChangeFlagTable[SC_ATKER_BLOOD] |= SCB_ALL; status->dbs->ChangeFlagTable[SC_WALKSPEED] |= SCB_SPEED; status->dbs->ChangeFlagTable[SC_TARGET_BLOOD] |= SCB_ALL; @@ -3034,6 +3035,10 @@ static int status_calc_pc_(struct map_session_data *sd, enum e_status_calc_opt o sd->subele[ELE_WATER] += sc->data[SC_RESIST_PROPERTY_WATER]->val1; sd->subele[ELE_WIND] += sc->data[SC_RESIST_PROPERTY_WATER]->val2; } + if (sc->data[SC_RESIST_PROPERTY_GROUND] != NULL) { // Earthproof Potion + sd->subele[ELE_EARTH] += sc->data[SC_RESIST_PROPERTY_GROUND]->val1; + sd->subele[ELE_FIRE] += sc->data[SC_RESIST_PROPERTY_GROUND]->val2; + } if (sc->data[SC_FIRE_CLOAK_OPTION]) { i = sc->data[SC_FIRE_CLOAK_OPTION]->val2; sd->subele[ELE_FIRE] += i; @@ -7759,6 +7764,7 @@ static int status_change_start_sub(struct block_list *src, struct block_list *bl case SC_ARMORPROPERTY: case SC_ARMOR_RESIST: case SC_RESIST_PROPERTY_WATER: + case SC_RESIST_PROPERTY_GROUND: break; case SC_GOSPEL: //Must not override a casting gospel char. @@ -8732,6 +8738,7 @@ static int status_change_start_sub(struct block_list *src, struct block_list *bl break; case SC_RESIST_PROPERTY_WATER: + case SC_RESIST_PROPERTY_GROUND: if (val1 <= 0) flag |= SCFLAG_NOICON; -- cgit v1.2.3-70-g09d2 From 49988ac53690a0194d111a57603db68941ae3558 Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Sat, 2 May 2020 05:05:12 +0200 Subject: Implement SC_RESIST_PROPERTY_FIRE logic --- src/map/status.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/map/status.c b/src/map/status.c index 069fd0580..41805b1e2 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -867,6 +867,7 @@ static void initChangeTables(void) status->dbs->ChangeFlagTable[SC_ARMOR_RESIST] |= SCB_ALL; status->dbs->ChangeFlagTable[SC_RESIST_PROPERTY_WATER] |= SCB_ALL; status->dbs->ChangeFlagTable[SC_RESIST_PROPERTY_GROUND] |= SCB_ALL; + status->dbs->ChangeFlagTable[SC_RESIST_PROPERTY_FIRE] |= SCB_ALL; status->dbs->ChangeFlagTable[SC_ATKER_BLOOD] |= SCB_ALL; status->dbs->ChangeFlagTable[SC_WALKSPEED] |= SCB_SPEED; status->dbs->ChangeFlagTable[SC_TARGET_BLOOD] |= SCB_ALL; @@ -3039,6 +3040,10 @@ static int status_calc_pc_(struct map_session_data *sd, enum e_status_calc_opt o sd->subele[ELE_EARTH] += sc->data[SC_RESIST_PROPERTY_GROUND]->val1; sd->subele[ELE_FIRE] += sc->data[SC_RESIST_PROPERTY_GROUND]->val2; } + if (sc->data[SC_RESIST_PROPERTY_FIRE] != NULL) { // Fireproof Potion + sd->subele[ELE_FIRE] += sc->data[SC_RESIST_PROPERTY_FIRE]->val1; + sd->subele[ELE_WATER] += sc->data[SC_RESIST_PROPERTY_FIRE]->val2; + } if (sc->data[SC_FIRE_CLOAK_OPTION]) { i = sc->data[SC_FIRE_CLOAK_OPTION]->val2; sd->subele[ELE_FIRE] += i; @@ -7765,6 +7770,7 @@ static int status_change_start_sub(struct block_list *src, struct block_list *bl case SC_ARMOR_RESIST: case SC_RESIST_PROPERTY_WATER: case SC_RESIST_PROPERTY_GROUND: + case SC_RESIST_PROPERTY_FIRE: break; case SC_GOSPEL: //Must not override a casting gospel char. @@ -8739,6 +8745,7 @@ static int status_change_start_sub(struct block_list *src, struct block_list *bl break; case SC_RESIST_PROPERTY_WATER: case SC_RESIST_PROPERTY_GROUND: + case SC_RESIST_PROPERTY_FIRE: if (val1 <= 0) flag |= SCFLAG_NOICON; -- cgit v1.2.3-70-g09d2 From ad5506fb804ded1435390707c52f6c040aee3a49 Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Sat, 2 May 2020 05:09:53 +0200 Subject: Implement SC_RESIST_PROPERTY_WIND logic --- src/map/status.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/map/status.c b/src/map/status.c index 41805b1e2..72c382496 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -868,6 +868,7 @@ static void initChangeTables(void) status->dbs->ChangeFlagTable[SC_RESIST_PROPERTY_WATER] |= SCB_ALL; status->dbs->ChangeFlagTable[SC_RESIST_PROPERTY_GROUND] |= SCB_ALL; status->dbs->ChangeFlagTable[SC_RESIST_PROPERTY_FIRE] |= SCB_ALL; + status->dbs->ChangeFlagTable[SC_RESIST_PROPERTY_WIND] |= SCB_ALL; status->dbs->ChangeFlagTable[SC_ATKER_BLOOD] |= SCB_ALL; status->dbs->ChangeFlagTable[SC_WALKSPEED] |= SCB_SPEED; status->dbs->ChangeFlagTable[SC_TARGET_BLOOD] |= SCB_ALL; @@ -3044,6 +3045,10 @@ static int status_calc_pc_(struct map_session_data *sd, enum e_status_calc_opt o sd->subele[ELE_FIRE] += sc->data[SC_RESIST_PROPERTY_FIRE]->val1; sd->subele[ELE_WATER] += sc->data[SC_RESIST_PROPERTY_FIRE]->val2; } + if (sc->data[SC_RESIST_PROPERTY_WIND] != NULL) { // Thunderproof Potion + sd->subele[ELE_WIND] += sc->data[SC_RESIST_PROPERTY_WIND]->val1; + sd->subele[ELE_EARTH] += sc->data[SC_RESIST_PROPERTY_WIND]->val2; + } if (sc->data[SC_FIRE_CLOAK_OPTION]) { i = sc->data[SC_FIRE_CLOAK_OPTION]->val2; sd->subele[ELE_FIRE] += i; @@ -7771,6 +7776,7 @@ static int status_change_start_sub(struct block_list *src, struct block_list *bl case SC_RESIST_PROPERTY_WATER: case SC_RESIST_PROPERTY_GROUND: case SC_RESIST_PROPERTY_FIRE: + case SC_RESIST_PROPERTY_WIND: break; case SC_GOSPEL: //Must not override a casting gospel char. @@ -8746,6 +8752,7 @@ static int status_change_start_sub(struct block_list *src, struct block_list *bl case SC_RESIST_PROPERTY_WATER: case SC_RESIST_PROPERTY_GROUND: case SC_RESIST_PROPERTY_FIRE: + case SC_RESIST_PROPERTY_WIND: if (val1 <= 0) flag |= SCFLAG_NOICON; -- cgit v1.2.3-70-g09d2 From 686c575eef6dfbd34ed5d4cbebef6f739d52fdca Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Sat, 2 May 2020 16:39:34 +0200 Subject: Apply, remove and re-apply status icons shared by SC_RESIST_PROPERTY_* and SC_ARMOR_RESIST --- src/map/status.c | 364 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 344 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/map/status.c b/src/map/status.c index 72c382496..8faee80d5 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -8723,40 +8723,186 @@ static int status_change_start_sub(struct block_list *src, struct block_list *bl //associated, and yet are not wrong/unknown. [Skotlex] //break; } - case SC_ARMOR_RESIST: - if (val1 > 0) { + case SC_ARMOR_RESIST: { + struct status_change_entry *sce_water = sc->data[SC_RESIST_PROPERTY_WATER]; + struct status_change_entry *sce_ground = sc->data[SC_RESIST_PROPERTY_GROUND]; + struct status_change_entry *sce_fire = sc->data[SC_RESIST_PROPERTY_FIRE]; + struct status_change_entry *sce_wind = sc->data[SC_RESIST_PROPERTY_WIND]; + + // Water + int sum_water = val1 + ((sce_fire != NULL) ? sce_fire->val2 : 0); + bool show_icon = true; + if (sce_water != NULL) { + sum_water += sce_water->val1; + int left = (int)DIFF_TICK(timer->get(sce_water->timer)->tick, timer->gettick()); + if (left > total_tick && sum_water - val1 > 0) + show_icon = false; + } + if (val1 > 0 && sum_water > 0 && show_icon) { int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WATER); int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WATER); clif->status_change(bl, sc_icn, sc_typ, 1, total_tick, 0, 0, 0); + } else if (sum_water <= 0) { + clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WATER)); } - if (val2 > 0) { + // Ground + int sum_ground = val2 + ((sce_wind != NULL) ? sce_wind->val2 : 0); + show_icon = true; + if (sce_ground != NULL) { + sum_ground += sce_ground->val1; + int left = (int)DIFF_TICK(timer->get(sce_ground->timer)->tick, timer->gettick()); + if (left > total_tick && sum_ground - val2 > 0) + show_icon = false; + } + if (val2 > 0 && sum_ground > 0 && show_icon) { int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_GROUND); int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_GROUND); clif->status_change(bl, sc_icn, sc_typ, 1, total_tick, 0, 0, 0); + } else if (sum_ground <= 0) { + clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_GROUND)); } - if (val3 > 0) { + // Fire + int sum_fire = val3 + ((sce_ground != NULL) ? sce_ground->val2 : 0); + show_icon = true; + if (sce_fire != NULL) { + sum_fire += sce_fire->val1; + int left = (int)DIFF_TICK(timer->get(sce_fire->timer)->tick, timer->gettick()); + if (left > total_tick && sum_fire - val3 > 0) + show_icon = false; + } + if (val3 > 0 && sum_fire > 0 && show_icon) { int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_FIRE); int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_FIRE); clif->status_change(bl, sc_icn, sc_typ, 1, total_tick, 0, 0, 0); + } else if (sum_fire <= 0) { + clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_FIRE)); } - if (val4 > 0) { + // Wind + int sum_wind = val4 + ((sce_water != NULL) ? sce_water->val2 : 0); + show_icon = true; + if (sce_wind != NULL) { + sum_wind += sce_wind->val1; + int left = (int)DIFF_TICK(timer->get(sce_wind->timer)->tick, timer->gettick()); + if (left > total_tick && sum_wind - val4 > 0) + show_icon = false; + } + if (val4 > 0 && sum_wind > 0 && show_icon) { int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WIND); int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WIND); clif->status_change(bl, sc_icn, sc_typ, 1, total_tick, 0, 0, 0); + } else if (sum_wind <= 0) { + clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WIND)); } break; - case SC_RESIST_PROPERTY_WATER: - case SC_RESIST_PROPERTY_GROUND: - case SC_RESIST_PROPERTY_FIRE: - case SC_RESIST_PROPERTY_WIND: - if (val1 <= 0) + } + case SC_RESIST_PROPERTY_WATER: { + struct status_change_entry *sce_all = sc->data[SC_ARMOR_RESIST]; + struct status_change_entry *sce_fire = sc->data[SC_RESIST_PROPERTY_FIRE]; + struct status_change_entry *sce_wind = sc->data[SC_RESIST_PROPERTY_WIND]; + + // Water + int sum_water = val1 + ((sce_fire != NULL) ? sce_fire->val2 : 0); + if (sce_all != NULL) { + sum_water += sce_all->val1; + int left = (int)DIFF_TICK(timer->get(sce_all->timer)->tick, timer->gettick()); + if (left > total_tick && sum_water - val1 > 0) + flag |= SCFLAG_NOICON; + } + if (sum_water <= 0) { + clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WATER)); + flag |= SCFLAG_NOICON; + } + + // Wind + int sum_wind = val2 + ((sce_wind != NULL) ? sce_wind->val1 : 0); + sum_wind += (sce_all != NULL) ? sce_all->val4 : 0; + if (sum_wind <= 0) + clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WIND)); + + break; + } + case SC_RESIST_PROPERTY_GROUND: { + struct status_change_entry *sce_all = sc->data[SC_ARMOR_RESIST]; + struct status_change_entry *sce_wind = sc->data[SC_RESIST_PROPERTY_WIND]; + struct status_change_entry *sce_fire = sc->data[SC_RESIST_PROPERTY_FIRE]; + + // Ground + int sum_ground = val1 + ((sce_wind != NULL) ? sce_wind->val2 : 0); + if (sce_all != NULL) { + sum_ground += sce_all->val2; + int left = (int)DIFF_TICK(timer->get(sce_all->timer)->tick, timer->gettick()); + if (left > total_tick && sum_ground - val1 > 0) + flag |= SCFLAG_NOICON; + } + if (sum_ground <= 0) { + clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_GROUND)); + flag |= SCFLAG_NOICON; + } + + // Fire + int sum_fire = val2 + ((sce_fire != NULL) ? sce_fire->val1 : 0); + sum_fire += (sce_all != NULL) ? sce_all->val3 : 0; + if (sum_fire <= 0) + clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_FIRE)); + + break; + } + case SC_RESIST_PROPERTY_FIRE: { + struct status_change_entry *sce_all = sc->data[SC_ARMOR_RESIST]; + struct status_change_entry *sce_ground = sc->data[SC_RESIST_PROPERTY_GROUND]; + struct status_change_entry *sce_water = sc->data[SC_RESIST_PROPERTY_WATER]; + + // Fire + int sum_fire = val1 + ((sce_ground != NULL) ? sce_ground->val2 : 0); + if (sce_all != NULL) { + sum_fire += sce_all->val3; + int left = (int)DIFF_TICK(timer->get(sce_all->timer)->tick, timer->gettick()); + if (left > total_tick && sum_fire - val1 > 0) + flag |= SCFLAG_NOICON; + } + if (sum_fire <= 0) { + clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_FIRE)); flag |= SCFLAG_NOICON; + } + + // Water + int sum_water = val2 + ((sce_water != NULL) ? sce_water->val1 : 0); + sum_water += (sce_all != NULL) ? sce_all->val1 : 0; + if (sum_water <= 0) + clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WATER)); + + break; + } + case SC_RESIST_PROPERTY_WIND: { + struct status_change_entry *sce_all = sc->data[SC_ARMOR_RESIST]; + struct status_change_entry *sce_water = sc->data[SC_RESIST_PROPERTY_WATER]; + struct status_change_entry *sce_ground = sc->data[SC_RESIST_PROPERTY_GROUND]; + + // Wind + int sum_wind = val1 + ((sce_water != NULL) ? sce_water->val2 : 0); + if (sce_all != NULL) { + sum_wind += sce_all->val4; + int left = (int)DIFF_TICK(timer->get(sce_all->timer)->tick, timer->gettick()); + if (left > total_tick && sum_wind - val1 > 0) + flag |= SCFLAG_NOICON; + } + if (sum_wind <= 0) { + clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WIND)); + flag |= SCFLAG_NOICON; + } + + // Ground + int sum_ground = val2 + ((sce_ground != NULL) ? sce_ground->val1 : 0); + sum_ground += (sce_all != NULL) ? sce_all->val2 : 0; + if (sum_ground <= 0) + clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_GROUND)); break; + } case SC_MER_FLEE: case SC_MER_ATK: case SC_MER_HIT: @@ -10683,6 +10829,9 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid, vd = status->get_viewdata(bl); calc_flag = status->dbs->ChangeFlagTable[type]; + + bool remove_icon = true; + switch(type) { case SC_GRANITIC_ARMOR: { @@ -11114,18 +11263,192 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid, break; } break; - case SC_ARMOR_RESIST: - if (sce->val1 > 0) - clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WATER)); + case SC_ARMOR_RESIST: { + struct status_change_entry *sce_water = sc->data[SC_RESIST_PROPERTY_WATER]; + struct status_change_entry *sce_ground = sc->data[SC_RESIST_PROPERTY_GROUND]; + struct status_change_entry *sce_fire = sc->data[SC_RESIST_PROPERTY_FIRE]; + struct status_change_entry *sce_wind = sc->data[SC_RESIST_PROPERTY_WIND]; - if (sce->val2 > 0) - clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_GROUND)); + // Water + clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WATER)); + if (sce_water != NULL) { + int sum_water = sce_water->val1 + ((sce_fire != NULL) ? sce_fire->val2 : 0); + if (sce_water->val1 > 0 && sum_water > 0) { + const struct TimerData *td = timer->get(sce_water->timer); + int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WATER); + int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WATER); + int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); + int sc_ttl = sce_water->total_tick; + clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0); + } + } - if (sce->val3 > 0) - clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_FIRE)); + // Ground + clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_GROUND)); + if (sce_ground != NULL) { + int sum_ground = sce_ground->val1 + ((sce_wind != NULL) ? sce_wind->val2 : 0); + if (sce_ground->val1 > 0 && sum_ground > 0) { + const struct TimerData *td = timer->get(sce_ground->timer); + int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_GROUND); + int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_GROUND); + int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); + int sc_ttl = sce_ground->total_tick; + clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0); + } + } - if (sce->val4 > 0) - clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WIND)); + // Fire + clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_FIRE)); + if (sce_fire != NULL) { + int sum_fire = sce_fire->val1 + ((sce_ground != NULL) ? sce_ground->val2 : 0); + if (sce_fire->val1 > 0 && sum_fire > 0) { + const struct TimerData *td = timer->get(sce_fire->timer); + int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_FIRE); + int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_FIRE); + int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); + int sc_ttl = sce_fire->total_tick; + clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0); + } + } + + // Wind + clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WIND)); + if (sce_wind != NULL) { + int sum_wind = sce_wind->val1 + ((sce_water != NULL) ? sce_water->val2 : 0); + if (sce_wind->val1 > 0 && sum_wind > 0) { + const struct TimerData *td = timer->get(sce_wind->timer); + int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WIND); + int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WIND); + int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); + int sc_ttl = sce_wind->total_tick; + clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0); + } + } + + break; + } + case SC_RESIST_PROPERTY_WATER: + if (sc->data[SC_ARMOR_RESIST] != NULL) { + // Water + int sum_water = sc->data[SC_ARMOR_RESIST]->val1; + if (sc->data[SC_RESIST_PROPERTY_FIRE] != NULL) + sum_water += sc->data[SC_RESIST_PROPERTY_FIRE]->val2; + if (sc->data[SC_ARMOR_RESIST]->val1 > 0 && sum_water > 0) { + const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer); + int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WATER); + int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WATER); + int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); + int sc_ttl = sc->data[SC_ARMOR_RESIST]->total_tick; + clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0); + remove_icon = false; + } + + // Wind + int sum_wind = sc->data[SC_ARMOR_RESIST]->val4; + if (sc->data[SC_RESIST_PROPERTY_WIND] != NULL) + sum_wind += sc->data[SC_RESIST_PROPERTY_WIND]->val1; + if (sc->data[SC_ARMOR_RESIST]->val4 > 0 && sum_wind > 0) { + const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer); + int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WIND); + int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WIND); + int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); + int sc_ttl = sc->data[SC_ARMOR_RESIST]->total_tick; + clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0); + } + } + + break; + case SC_RESIST_PROPERTY_GROUND: + if (sc->data[SC_ARMOR_RESIST] != NULL) { + // Ground + int sum_ground = sc->data[SC_ARMOR_RESIST]->val2; + if (sc->data[SC_RESIST_PROPERTY_WIND] != NULL) + sum_ground += sc->data[SC_RESIST_PROPERTY_WIND]->val2; + if (sc->data[SC_ARMOR_RESIST]->val2 > 0 && sum_ground > 0) { + const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer); + int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_GROUND); + int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_GROUND); + int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); + int sc_ttl = sc->data[SC_ARMOR_RESIST]->total_tick; + clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0); + remove_icon = false; + } + + // Fire + int sum_fire = sc->data[SC_ARMOR_RESIST]->val3; + if (sc->data[SC_RESIST_PROPERTY_FIRE] != NULL) + sum_fire += sc->data[SC_RESIST_PROPERTY_FIRE]->val1; + if (sc->data[SC_ARMOR_RESIST]->val3 > 0 && sum_fire > 0) { + const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer); + int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_FIRE); + int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_FIRE); + int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); + int sc_ttl = sc->data[SC_ARMOR_RESIST]->total_tick; + clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0); + } + } + + break; + case SC_RESIST_PROPERTY_FIRE: + if (sc->data[SC_ARMOR_RESIST] != NULL) { + // Fire + int sum_fire = sc->data[SC_ARMOR_RESIST]->val3; + if (sc->data[SC_RESIST_PROPERTY_GROUND] != NULL) + sum_fire += sc->data[SC_RESIST_PROPERTY_GROUND]->val2; + if (sc->data[SC_ARMOR_RESIST]->val3 > 0 && sum_fire > 0) { + const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer); + int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_FIRE); + int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_FIRE); + int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); + int sc_ttl = sc->data[SC_ARMOR_RESIST]->total_tick; + clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0); + remove_icon = false; + } + + // Water + int sum_water = sc->data[SC_ARMOR_RESIST]->val1; + if (sc->data[SC_RESIST_PROPERTY_WATER] != NULL) + sum_water += sc->data[SC_RESIST_PROPERTY_WATER]->val1; + if (sc->data[SC_ARMOR_RESIST]->val1 > 0 && sum_water > 0) { + const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer); + int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WATER); + int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WATER); + int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); + int sc_ttl = sc->data[SC_ARMOR_RESIST]->total_tick; + clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0); + } + } + + break; + case SC_RESIST_PROPERTY_WIND: + if (sc->data[SC_ARMOR_RESIST] != NULL) { + // Wind + int sum_wind = sc->data[SC_ARMOR_RESIST]->val4; + if (sc->data[SC_RESIST_PROPERTY_WATER] != NULL) + sum_wind += sc->data[SC_RESIST_PROPERTY_WATER]->val2; + if (sc->data[SC_ARMOR_RESIST]->val4 > 0 && sum_wind > 0) { + const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer); + int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WIND); + int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WIND); + int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); + int sc_ttl = sc->data[SC_ARMOR_RESIST]->total_tick; + clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0); + remove_icon = false; + } + + // Ground + int sum_ground = sc->data[SC_ARMOR_RESIST]->val2; + if (sc->data[SC_RESIST_PROPERTY_GROUND] != NULL) + sum_ground += sc->data[SC_RESIST_PROPERTY_GROUND]->val1; + if (sc->data[SC_ARMOR_RESIST]->val2 > 0 && sum_ground > 0) { + const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer); + int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_GROUND); + int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_GROUND); + int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); + int sc_ttl = sc->data[SC_ARMOR_RESIST]->total_tick; + clif->status_change_sub(bl, sc_icn, sc_typ, 1, sc_tck, sc_ttl, 0, 0, 0); + } + } break; } @@ -11341,7 +11664,8 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid, #endif //On Aegis, when turning off a status change, first goes the sc packet, then the option packet. - clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(type)); + if (remove_icon) + clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(type)); if( opt_flag&8 ) //bugreport:681 clif->changeoption2(bl); -- cgit v1.2.3-70-g09d2 From 29d40c5a52ab4bb1ef08e03b763bfa47f6cad0fe Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Fri, 1 May 2020 06:21:33 +0200 Subject: Add constant for maximum string variable value length Also add static assert check for SCRIPT_VARNAME_LENGTH --- src/common/mmo.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/common/mmo.h b/src/common/mmo.h index 9421f6e35..d2f3aa8f1 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -380,7 +380,10 @@ STATIC_ASSERT(MAX_ITEM_OPTIONS <= 5, "This value is limited by the client and da #define JOBL_BABY 0x2000 #define JOBL_THIRD 0x4000 -#define SCRIPT_VARNAME_LENGTH 32 ///< Maximum length of a script variable +#define SCRIPT_VARNAME_LENGTH 32 ///< Maximum length of a script variable's name including affixes and excluding NULL-terminator. +STATIC_ASSERT(SCRIPT_VARNAME_LENGTH <= 32, "This value is limited by the inter-server communication and database layout and should only be increased if you know the consequences."); +#define SCRIPT_STRING_VAR_LENGTH 255 ///< Maximum length of strings stored in script variables excluding NULL-terminator. +STATIC_ASSERT(SCRIPT_STRING_VAR_LENGTH <= 255, "This value is limited by the inter-server communication and database layout and should only be increased if you know the consequences."); #define INFINITE_DURATION (-1) // Infinite duration for status changes -- cgit v1.2.3-70-g09d2 From f165d0c080d25559e7fbc4439e52b376acf4c77f Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Sun, 3 May 2020 06:41:05 +0200 Subject: Add timer data verification --- src/map/status.c | 160 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 96 insertions(+), 64 deletions(-) (limited to 'src') diff --git a/src/map/status.c b/src/map/status.c index 8faee80d5..5ea4d880d 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -8732,11 +8732,14 @@ static int status_change_start_sub(struct block_list *src, struct block_list *bl // Water int sum_water = val1 + ((sce_fire != NULL) ? sce_fire->val2 : 0); bool show_icon = true; - if (sce_water != NULL) { - sum_water += sce_water->val1; - int left = (int)DIFF_TICK(timer->get(sce_water->timer)->tick, timer->gettick()); - if (left > total_tick && sum_water - val1 > 0) - show_icon = false; + if (sce_water != NULL && sce_water->timer != INVALID_TIMER) { + const struct TimerData *td = timer->get(sce_water->timer); + if (td != NULL) { + sum_water += sce_water->val1; + int left = (int)DIFF_TICK(td->tick, timer->gettick()); + if (left > total_tick && sum_water - val1 > 0) + show_icon = false; + } } if (val1 > 0 && sum_water > 0 && show_icon) { int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WATER); @@ -8749,11 +8752,14 @@ static int status_change_start_sub(struct block_list *src, struct block_list *bl // Ground int sum_ground = val2 + ((sce_wind != NULL) ? sce_wind->val2 : 0); show_icon = true; - if (sce_ground != NULL) { - sum_ground += sce_ground->val1; - int left = (int)DIFF_TICK(timer->get(sce_ground->timer)->tick, timer->gettick()); - if (left > total_tick && sum_ground - val2 > 0) - show_icon = false; + if (sce_ground != NULL && sce_ground->timer != INVALID_TIMER) { + const struct TimerData *td = timer->get(sce_ground->timer); + if (td != NULL) { + sum_ground += sce_ground->val1; + int left = (int)DIFF_TICK(td->tick, timer->gettick()); + if (left > total_tick && sum_ground - val2 > 0) + show_icon = false; + } } if (val2 > 0 && sum_ground > 0 && show_icon) { int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_GROUND); @@ -8766,11 +8772,14 @@ static int status_change_start_sub(struct block_list *src, struct block_list *bl // Fire int sum_fire = val3 + ((sce_ground != NULL) ? sce_ground->val2 : 0); show_icon = true; - if (sce_fire != NULL) { - sum_fire += sce_fire->val1; - int left = (int)DIFF_TICK(timer->get(sce_fire->timer)->tick, timer->gettick()); - if (left > total_tick && sum_fire - val3 > 0) - show_icon = false; + if (sce_fire != NULL && sce_fire->timer != INVALID_TIMER) { + const struct TimerData *td = timer->get(sce_fire->timer); + if (td != NULL) { + sum_fire += sce_fire->val1; + int left = (int)DIFF_TICK(td->tick, timer->gettick()); + if (left > total_tick && sum_fire - val3 > 0) + show_icon = false; + } } if (val3 > 0 && sum_fire > 0 && show_icon) { int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_FIRE); @@ -8783,11 +8792,14 @@ static int status_change_start_sub(struct block_list *src, struct block_list *bl // Wind int sum_wind = val4 + ((sce_water != NULL) ? sce_water->val2 : 0); show_icon = true; - if (sce_wind != NULL) { - sum_wind += sce_wind->val1; - int left = (int)DIFF_TICK(timer->get(sce_wind->timer)->tick, timer->gettick()); - if (left > total_tick && sum_wind - val4 > 0) - show_icon = false; + if (sce_wind != NULL && sce_wind->timer != INVALID_TIMER) { + const struct TimerData *td = timer->get(sce_wind->timer); + if (td != NULL) { + sum_wind += sce_wind->val1; + int left = (int)DIFF_TICK(td->tick, timer->gettick()); + if (left > total_tick && sum_wind - val4 > 0) + show_icon = false; + } } if (val4 > 0 && sum_wind > 0 && show_icon) { int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WIND); @@ -8806,11 +8818,14 @@ static int status_change_start_sub(struct block_list *src, struct block_list *bl // Water int sum_water = val1 + ((sce_fire != NULL) ? sce_fire->val2 : 0); - if (sce_all != NULL) { - sum_water += sce_all->val1; - int left = (int)DIFF_TICK(timer->get(sce_all->timer)->tick, timer->gettick()); - if (left > total_tick && sum_water - val1 > 0) - flag |= SCFLAG_NOICON; + if (sce_all != NULL && sce_all->timer != INVALID_TIMER) { + const struct TimerData *td = timer->get(sce_all->timer); + if (td != NULL) { + sum_water += sce_all->val1; + int left = (int)DIFF_TICK(td->tick, timer->gettick()); + if (left > total_tick && sum_water - val1 > 0) + flag |= SCFLAG_NOICON; + } } if (sum_water <= 0) { clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WATER)); @@ -8832,11 +8847,14 @@ static int status_change_start_sub(struct block_list *src, struct block_list *bl // Ground int sum_ground = val1 + ((sce_wind != NULL) ? sce_wind->val2 : 0); - if (sce_all != NULL) { - sum_ground += sce_all->val2; - int left = (int)DIFF_TICK(timer->get(sce_all->timer)->tick, timer->gettick()); - if (left > total_tick && sum_ground - val1 > 0) - flag |= SCFLAG_NOICON; + if (sce_all != NULL && sce_all->timer != INVALID_TIMER) { + const struct TimerData *td = timer->get(sce_all->timer); + if (td != NULL) { + sum_ground += sce_all->val2; + int left = (int)DIFF_TICK(td->tick, timer->gettick()); + if (left > total_tick && sum_ground - val1 > 0) + flag |= SCFLAG_NOICON; + } } if (sum_ground <= 0) { clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_GROUND)); @@ -8858,11 +8876,14 @@ static int status_change_start_sub(struct block_list *src, struct block_list *bl // Fire int sum_fire = val1 + ((sce_ground != NULL) ? sce_ground->val2 : 0); - if (sce_all != NULL) { - sum_fire += sce_all->val3; - int left = (int)DIFF_TICK(timer->get(sce_all->timer)->tick, timer->gettick()); - if (left > total_tick && sum_fire - val1 > 0) - flag |= SCFLAG_NOICON; + if (sce_all != NULL && sce_all->timer != INVALID_TIMER) { + const struct TimerData *td = timer->get(sce_all->timer); + if (td != NULL) { + sum_fire += sce_all->val3; + int left = (int)DIFF_TICK(td->tick, timer->gettick()); + if (left > total_tick && sum_fire - val1 > 0) + flag |= SCFLAG_NOICON; + } } if (sum_fire <= 0) { clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_FIRE)); @@ -8884,11 +8905,14 @@ static int status_change_start_sub(struct block_list *src, struct block_list *bl // Wind int sum_wind = val1 + ((sce_water != NULL) ? sce_water->val2 : 0); - if (sce_all != NULL) { - sum_wind += sce_all->val4; - int left = (int)DIFF_TICK(timer->get(sce_all->timer)->tick, timer->gettick()); - if (left > total_tick && sum_wind - val1 > 0) - flag |= SCFLAG_NOICON; + if (sce_all != NULL && sce_all->timer != INVALID_TIMER) { + const struct TimerData *td = timer->get(sce_all->timer); + if (td != NULL) { + sum_wind += sce_all->val4; + int left = (int)DIFF_TICK(td->tick, timer->gettick()); + if (left > total_tick && sum_wind - val1 > 0) + flag |= SCFLAG_NOICON; + } } if (sum_wind <= 0) { clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WIND)); @@ -11271,10 +11295,10 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid, // Water clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WATER)); - if (sce_water != NULL) { + if (sce_water != NULL && sce_water->timer != INVALID_TIMER) { int sum_water = sce_water->val1 + ((sce_fire != NULL) ? sce_fire->val2 : 0); - if (sce_water->val1 > 0 && sum_water > 0) { - const struct TimerData *td = timer->get(sce_water->timer); + const struct TimerData *td = timer->get(sce_water->timer); + if (td != NULL && sce_water->val1 > 0 && sum_water > 0) { int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WATER); int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WATER); int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); @@ -11285,10 +11309,10 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid, // Ground clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_GROUND)); - if (sce_ground != NULL) { + if (sce_ground != NULL && sce_ground->timer != INVALID_TIMER) { int sum_ground = sce_ground->val1 + ((sce_wind != NULL) ? sce_wind->val2 : 0); - if (sce_ground->val1 > 0 && sum_ground > 0) { - const struct TimerData *td = timer->get(sce_ground->timer); + const struct TimerData *td = timer->get(sce_ground->timer); + if (td != NULL && sce_ground->val1 > 0 && sum_ground > 0) { int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_GROUND); int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_GROUND); int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); @@ -11299,10 +11323,10 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid, // Fire clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_FIRE)); - if (sce_fire != NULL) { + if (sce_fire != NULL && sce_fire->timer != INVALID_TIMER) { int sum_fire = sce_fire->val1 + ((sce_ground != NULL) ? sce_ground->val2 : 0); - if (sce_fire->val1 > 0 && sum_fire > 0) { - const struct TimerData *td = timer->get(sce_fire->timer); + const struct TimerData *td = timer->get(sce_fire->timer); + if (td != NULL && sce_fire->val1 > 0 && sum_fire > 0) { int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_FIRE); int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_FIRE); int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); @@ -11313,10 +11337,10 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid, // Wind clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_RESIST_PROPERTY_WIND)); - if (sce_wind != NULL) { + if (sce_wind != NULL && sce_wind->timer != INVALID_TIMER) { int sum_wind = sce_wind->val1 + ((sce_water != NULL) ? sce_water->val2 : 0); - if (sce_wind->val1 > 0 && sum_wind > 0) { - const struct TimerData *td = timer->get(sce_wind->timer); + const struct TimerData *td = timer->get(sce_wind->timer); + if (td != NULL && sce_wind->val1 > 0 && sum_wind > 0) { int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WIND); int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WIND); int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); @@ -11328,13 +11352,16 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid, break; } case SC_RESIST_PROPERTY_WATER: - if (sc->data[SC_ARMOR_RESIST] != NULL) { + if (sc->data[SC_ARMOR_RESIST] != NULL && sc->data[SC_ARMOR_RESIST]->timer != INVALID_TIMER) { + const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer); + if (td == NULL) + break; + // Water int sum_water = sc->data[SC_ARMOR_RESIST]->val1; if (sc->data[SC_RESIST_PROPERTY_FIRE] != NULL) sum_water += sc->data[SC_RESIST_PROPERTY_FIRE]->val2; if (sc->data[SC_ARMOR_RESIST]->val1 > 0 && sum_water > 0) { - const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer); int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WATER); int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WATER); int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); @@ -11348,7 +11375,6 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid, if (sc->data[SC_RESIST_PROPERTY_WIND] != NULL) sum_wind += sc->data[SC_RESIST_PROPERTY_WIND]->val1; if (sc->data[SC_ARMOR_RESIST]->val4 > 0 && sum_wind > 0) { - const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer); int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WIND); int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WIND); int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); @@ -11359,13 +11385,16 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid, break; case SC_RESIST_PROPERTY_GROUND: - if (sc->data[SC_ARMOR_RESIST] != NULL) { + if (sc->data[SC_ARMOR_RESIST] != NULL && sc->data[SC_ARMOR_RESIST]->timer != INVALID_TIMER) { + const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer); + if (td == NULL) + break; + // Ground int sum_ground = sc->data[SC_ARMOR_RESIST]->val2; if (sc->data[SC_RESIST_PROPERTY_WIND] != NULL) sum_ground += sc->data[SC_RESIST_PROPERTY_WIND]->val2; if (sc->data[SC_ARMOR_RESIST]->val2 > 0 && sum_ground > 0) { - const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer); int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_GROUND); int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_GROUND); int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); @@ -11379,7 +11408,6 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid, if (sc->data[SC_RESIST_PROPERTY_FIRE] != NULL) sum_fire += sc->data[SC_RESIST_PROPERTY_FIRE]->val1; if (sc->data[SC_ARMOR_RESIST]->val3 > 0 && sum_fire > 0) { - const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer); int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_FIRE); int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_FIRE); int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); @@ -11390,13 +11418,16 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid, break; case SC_RESIST_PROPERTY_FIRE: - if (sc->data[SC_ARMOR_RESIST] != NULL) { + if (sc->data[SC_ARMOR_RESIST] != NULL && sc->data[SC_ARMOR_RESIST]->timer != INVALID_TIMER) { + const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer); + if (td == NULL) + break; + // Fire int sum_fire = sc->data[SC_ARMOR_RESIST]->val3; if (sc->data[SC_RESIST_PROPERTY_GROUND] != NULL) sum_fire += sc->data[SC_RESIST_PROPERTY_GROUND]->val2; if (sc->data[SC_ARMOR_RESIST]->val3 > 0 && sum_fire > 0) { - const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer); int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_FIRE); int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_FIRE); int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); @@ -11410,7 +11441,6 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid, if (sc->data[SC_RESIST_PROPERTY_WATER] != NULL) sum_water += sc->data[SC_RESIST_PROPERTY_WATER]->val1; if (sc->data[SC_ARMOR_RESIST]->val1 > 0 && sum_water > 0) { - const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer); int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WATER); int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WATER); int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); @@ -11421,13 +11451,16 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid, break; case SC_RESIST_PROPERTY_WIND: - if (sc->data[SC_ARMOR_RESIST] != NULL) { + if (sc->data[SC_ARMOR_RESIST] != NULL && sc->data[SC_ARMOR_RESIST]->timer != INVALID_TIMER) { + const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer); + if (td == NULL) + break; + // Wind int sum_wind = sc->data[SC_ARMOR_RESIST]->val4; if (sc->data[SC_RESIST_PROPERTY_WATER] != NULL) sum_wind += sc->data[SC_RESIST_PROPERTY_WATER]->val2; if (sc->data[SC_ARMOR_RESIST]->val4 > 0 && sum_wind > 0) { - const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer); int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_WIND); int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_WIND); int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); @@ -11441,7 +11474,6 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid, if (sc->data[SC_RESIST_PROPERTY_GROUND] != NULL) sum_ground += sc->data[SC_RESIST_PROPERTY_GROUND]->val1; if (sc->data[SC_ARMOR_RESIST]->val2 > 0 && sum_ground > 0) { - const struct TimerData *td = timer->get(sc->data[SC_ARMOR_RESIST]->timer); int sc_icn = status->get_sc_icon(SC_RESIST_PROPERTY_GROUND); int sc_typ = status->get_sc_relevant_bl_types(SC_RESIST_PROPERTY_GROUND); int sc_tck = (int)DIFF_TICK(td->tick, timer->gettick()); -- cgit v1.2.3-70-g09d2 From 06e65c769bbb66045e0d51da6a321a4c4ef1ff42 Mon Sep 17 00:00:00 2001 From: gumi Date: Sun, 22 Jul 2018 23:37:10 -0400 Subject: allow local NPC functions to be public or private --- src/map/map.h | 8 + src/map/npc.c | 11 +- src/map/npc.h | 1 + src/map/script.c | 547 ++++++++++++++++++++++++++++++++++++++++--------------- src/map/script.h | 15 +- 5 files changed, 423 insertions(+), 159 deletions(-) (limited to 'src') diff --git a/src/map/map.h b/src/map/map.h index 2de6df2f7..b3cdef025 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -329,6 +329,14 @@ enum bl_type { enum npc_subtype { WARP, SHOP, SCRIPT, CASHSHOP, TOMB }; +/** optional flags for script labels, used by the label db */ +enum script_label_flags { + /** the label can be called from outside the local scope of the NPC */ + LABEL_IS_EXTERN = 0x1, + /** the label is a public or private local NPC function */ + LABEL_IS_USERFUNC = 0x2, +}; + /** * Race type IDs. * diff --git a/src/map/npc.c b/src/map/npc.c index 40ec380ee..570305ba1 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -389,7 +389,8 @@ static int npc_event_export(struct npc_data *nd, int i) Assert_ret(i >= 0 && i < nd->u.scr.label_list_num); lname = nd->u.scr.label_list[i].name; pos = nd->u.scr.label_list[i].pos; - if ((lname[0] == 'O' || lname[0] == 'o') && (lname[1] == 'N' || lname[1] == 'n')) { + + if ((nd->u.scr.label_list[i].flags & LABEL_IS_EXTERN) != 0 && (nd->u.scr.label_list[i].flags & LABEL_IS_USERFUNC) == 0) { struct event_data *ev; struct linkdb_node **label_linkdb = NULL; char buf[EVENT_NAME_LENGTH]; @@ -3054,11 +3055,11 @@ static int npc_unload(struct npc_data *nd, bool single, bool unload_mobs) aFree(nd->u.shop.shop_item); /// src check for duplicate shops. [Orcao] } else if (nd->subtype == SCRIPT) { char evname[EVENT_NAME_LENGTH]; - + snprintf(evname, ARRAYLENGTH(evname), "%s::OnNPCUnload", nd->exname); struct event_data *ev = strdb_get(npc->ev_db, evname); - + if (ev != NULL) script->run_npc(nd->u.scr.script, ev->pos, 0, nd->bl.id); /// Run OnNPCUnload. @@ -3665,6 +3666,7 @@ static void npc_convertlabel_db(struct npc_label_list *label_list, const char *f for( i = 0; i < script->label_count; i++ ) { const char* lname = script->get_str(script->labels[i].key); int lpos = script->labels[i].pos; + enum script_label_flags flags = script->labels[i].flags; struct npc_label_list* label; const char *p; size_t len; @@ -3686,6 +3688,7 @@ static void npc_convertlabel_db(struct npc_label_list *label_list, const char *f safestrncpy(label->name, lname, sizeof(label->name)); label->pos = lpos; + label->flags = flags; } } @@ -5606,7 +5609,7 @@ static int npc_reload(void) npc->npc_last_npd = NULL; npc->npc_last_path = NULL; npc->npc_last_ref = NULL; - + const int npc_new_min = npc->npc_id; struct s_mapiterator *iter = mapit_geteachiddb(); diff --git a/src/map/npc.h b/src/map/npc.h index 1585a2bc8..a73a3ae06 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -59,6 +59,7 @@ struct npc_timerevent_list { struct npc_label_list { char name[NAME_LENGTH]; int pos; + enum script_label_flags flags; }; struct npc_barter_currency { diff --git a/src/map/script.c b/src/map/script.c index c08f5e829..9d6b9d8a2 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -848,79 +848,134 @@ static const char *parse_callfunc(const char *p, int require_paren, int is_custo nullpo_retr(NULL, p); // is need add check for arg null pointer below? - func = script->add_word(p); - if (script->str_data[func].type == C_FUNC) { - script->syntax.nested_call++; - if (script->syntax.last_func != -1) { - if (script->str_data[func].val == script->buildin_lang_macro_offset) { - script->syntax.lang_macro_active = true; - macro = true; - } else if (script->str_data[func].val == script->buildin_lang_macro_fmtstring_offset) { - script->syntax.lang_macro_fmtstring_active = true; - macro = true; - } + + if (*p == '"') { + p2 = ++p; // jump to the start of the word + + // find the closing quote + while (*p2 != '"') { + ++p2; } - if( !macro ) { - // buildin function + if (p2[1] == ':' && p2[2] == ':') { + func = script->add_str("callfunctionofnpc"); + arg = "*"; // we already take care of the "vs" part of "vs*" + + script->syntax.nested_call++; script->syntax.last_func = script->str_data[func].val; script->addl(func); script->addc(C_ARG); - } - arg = script->buildin[script->str_data[func].val]; - if (script->str_data[func].deprecated) - DeprecationWarning(p); - if( !arg ) arg = &null_arg; // Use a dummy, null string - } else if( script->str_data[func].type == C_USERFUNC || script->str_data[func].type == C_USERFUNC_POS ) { - // script defined function - script->addl(script->buildin_callsub_ref); - script->addc(C_ARG); - script->addl(func); - arg = script->buildin[script->str_data[script->buildin_callsub_ref].val]; - if( *arg == 0 ) - disp_error_message("parse_callfunc: callsub has no arguments, please review its definition",p); - if( *arg != '*' ) - ++arg; // count func as argument + script->addc(C_STR); + do { + script->addb(*p++); // npc name + } while (p < p2); + script->addb(0); + + p = p2 + 3; // skip to start of func name + p2 = script->skip_word(p); + + script->addc(C_STR); + do { + script->addb(*p++); // func name + } while (p < p2); + script->addb(0); + + p = p2; // skip to just before the () + } else { + disp_error_message("script:parse_callfunc: invalid public function call syntax!", p2 + 1); + } } else { + func = script->add_word(p); + if (script->str_data[func].type == C_FUNC) { + script->syntax.nested_call++; + + if (script->syntax.last_func != -1) { + if (script->str_data[func].val == script->buildin_lang_macro_offset) { + script->syntax.lang_macro_active = true; + macro = true; + } else if (script->str_data[func].val == script->buildin_lang_macro_fmtstring_offset) { + script->syntax.lang_macro_fmtstring_active = true; + macro = true; + } + } + + if (!macro) { + // buildin function + script->syntax.last_func = script->str_data[func].val; + script->addl(func); + script->addc(C_ARG); + } + + arg = script->buildin[script->str_data[func].val]; + + if (script->str_data[func].deprecated == 1) { + DeprecationWarning(p); + } + + if (arg == NULL) { + arg = &null_arg; // Use a dummy, null string + } + } else if (script->str_data[func].type == C_USERFUNC || script->str_data[func].type == C_USERFUNC_POS) { + // script defined function + script->addl(script->buildin_callsub_ref); + script->addc(C_ARG); + script->addl(func); + arg = script->buildin[script->str_data[script->buildin_callsub_ref].val]; + + if (*arg == 0) { + disp_error_message("script:parse_callfunc: callsub has no arguments, please review its definition", p); + } + + if (*arg != '*') { + ++arg; // count func as argument + } + } else { #ifdef SCRIPT_CALLFUNC_CHECK - const char* name = script->get_str(func); - if( !is_custom && strdb_get(script->userfunc_db, name) == NULL ) { + const char *name = script->get_str(func); + if (is_custom == 0 && strdb_get(script->userfunc_db, name) == NULL) { #endif - disp_error_message("parse_line: expect command, missing function name or calling undeclared function",p); + disp_error_message("script:parse_callfunc: expect command, missing function name or calling undeclared function", p); #ifdef SCRIPT_CALLFUNC_CHECK - } else {; - script->addl(script->buildin_callfunc_ref); - script->addc(C_ARG); - script->addc(C_STR); - while( *name ) script->addb(*name ++); - script->addb(0); - arg = script->buildin[script->str_data[script->buildin_callfunc_ref].val]; - if( *arg != '*' ) ++ arg; - } + } else { + script->addl(script->buildin_callfunc_ref); + script->addc(C_ARG); + script->addc(C_STR); + + while (*name != '\0') { + script->addb(*name++); + } + + script->addb(0); + arg = script->buildin[script->str_data[script->buildin_callfunc_ref].val]; + + if (*arg != '*') { + ++ arg; + } + } #endif + } } p = script->skip_word(p); p = script->skip_space(p); script->syntax.curly[script->syntax.curly_count].type = TYPE_ARGLIST; script->syntax.curly[script->syntax.curly_count].count = 0; - if( *p == ';' ) - {// ';' + + if (*p == ';') { + // ';' script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_NO_PAREN; - } else if( *p == '(' && *(p2=script->skip_space(p+1)) == ')' ) - {// '(' ')' + } else if (*p == '(' && *(p2 = script->skip_space(p + 1)) == ')') { + // '(' ')' script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_PAREN; p = p2; - /* - } else if( 0 && require_paren && *p != '(' ) - {// - script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_NO_PAREN; - */ - } else {// - if( require_paren ) { - if( *p != '(' ) - disp_error_message("need '('",p); + } else { + // + if (require_paren == 1) { + if (*p != '(') { + disp_error_message("script:parse_callfunc: need '('", p); + } + ++p; // skip '(' script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_PAREN; } else if( *p == '(' ) { @@ -928,41 +983,65 @@ static const char *parse_callfunc(const char *p, int require_paren, int is_custo } else { script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_NO_PAREN; } + ++script->syntax.curly_count; - while( *arg ) { - p2=script->parse_subexpr(p,-1); - if( p == p2 ) - break; // not an argument - if( *arg != '*' ) - ++arg; // next argument - p=script->skip_space(p2); - if( *arg == 0 || *p != ',' ) - break; // no more arguments + while (*arg != '\0') { + p2 = script->parse_subexpr(p, -1); + + if (p == p2) { + // not an argument + break; + } + + if (*arg != '*') { + // next argument + ++arg; + } + + p = script->skip_space(p2); + + if (*arg == 0 || *p != ',') { + // no more arguments + break; + } + ++p; // skip comma } + --script->syntax.curly_count; } - if( arg && *arg && *arg != '?' && *arg != '*' ) - disp_error_message2("parse_callfunc: not enough arguments, expected ','", p, script->config.warn_func_mismatch_paramnum); - if( script->syntax.curly[script->syntax.curly_count].type != TYPE_ARGLIST ) - disp_error_message("parse_callfunc: DEBUG last curly is not an argument list",p); - if( script->syntax.curly[script->syntax.curly_count].flag == ARGLIST_PAREN ) { - if( *p != ')' ) - disp_error_message("parse_callfunc: expected ')' to close argument list",p); + + if (arg != NULL && *arg != '\0' && *arg != '?' && *arg != '*') { + disp_error_message2("script:parse_callfunc: not enough arguments, expected ','", p, script->config.warn_func_mismatch_paramnum); + } + + if (script->syntax.curly[script->syntax.curly_count].type != TYPE_ARGLIST) { + disp_error_message("parse_callfunc: DEBUG last curly is not an argument list", p); + } + + if (script->syntax.curly[script->syntax.curly_count].flag == ARGLIST_PAREN) { + if (*p != ')') { + disp_error_message("script:parse_callfunc: expected ')' to close argument list", p); + } + ++p; - if (script->str_data[func].val == script->buildin_lang_macro_offset) + if (script->str_data[func].val == script->buildin_lang_macro_offset) { script->syntax.lang_macro_active = false; - else if (script->str_data[func].val == script->buildin_lang_macro_fmtstring_offset) + } else if (script->str_data[func].val == script->buildin_lang_macro_fmtstring_offset) { script->syntax.lang_macro_fmtstring_active = false; + } } if (!macro) { - if (0 == --script->syntax.nested_call) + if (0 == --script->syntax.nested_call) { script->syntax.last_func = -1; + } + script->addc(C_FUNC); } + return p; } @@ -1230,16 +1309,29 @@ static int script_string_dup(char *str) *------------------------------------------*/ static const char *parse_simpleexpr(const char *p) { - p=script->skip_space(p); + p = script->skip_space(p); nullpo_retr(NULL, p); - if (*p == ';' || *p == ',') - disp_error_message("parse_simpleexpr: unexpected end of expression",p); + + if (*p == ';' || *p == ',') { + disp_error_message("script:parse_simpleexpr: unexpected end of expression", p); + } + if (*p == '(') { return script->parse_simpleexpr_paren(p); } else if (is_number(p)) { return script->parse_simpleexpr_number(p); } else if(*p == '"') { + const char *p2 = p + 1; + + while (*p2 != '"') { + ++p2; + } + + if (p2[1] == ':' && p2[2] == ':') { + return script->parse_callfunc(p, 1, 0); // XXX: why does callfunc use int for booleans? + } + return script->parse_simpleexpr_string(p); } else { return script->parse_simpleexpr_name(p); @@ -1577,6 +1669,85 @@ static const char *parse_line(const char *p) return p; } +/** + * parses a local function expression + * + * expects these formats: + * function ; + * function {