diff options
-rw-r--r-- | conf/map/battle/pet.conf | 5 | ||||
-rw-r--r-- | conf/messages.conf | 6 | ||||
-rw-r--r-- | db/constants.conf | 1 | ||||
-rw-r--r-- | doc/constants.md | 1 | ||||
-rw-r--r-- | doc/script_commands.txt | 55 | ||||
-rw-r--r-- | npc/mapflag/nopet.txt | 78 | ||||
-rw-r--r-- | npc/quests/quests_amatsu.txt | 33 | ||||
-rw-r--r-- | npc/quests/quests_moscovia.txt | 7 | ||||
-rw-r--r-- | npc/scripts_mapflags.conf | 1 | ||||
-rw-r--r-- | src/char/char.c | 139 | ||||
-rw-r--r-- | src/map/atcommand.c | 2 | ||||
-rw-r--r-- | src/map/battle.c | 1 | ||||
-rw-r--r-- | src/map/battle.h | 1 | ||||
-rw-r--r-- | src/map/clif.c | 8 | ||||
-rw-r--r-- | src/map/map.c | 13 | ||||
-rw-r--r-- | src/map/map.h | 1 | ||||
-rw-r--r-- | src/map/npc.c | 65 | ||||
-rw-r--r-- | src/map/script.c | 6 | ||||
-rw-r--r-- | src/map/script.h | 3 |
19 files changed, 285 insertions, 141 deletions
diff --git a/conf/map/battle/pet.conf b/conf/map/battle/pet.conf index 3060b6e64..6d013b0ef 100644 --- a/conf/map/battle/pet.conf +++ b/conf/map/battle/pet.conf @@ -95,11 +95,6 @@ pet_max_stats: 99 pet_max_atk1: 500 pet_max_atk2: 1000 -// Are pets disabled during Guild Wars? -// If set to true, pets are automatically returned to egg when entering castles during WoE times -// and hatching is forbidden within as well. -pet_disable_in_gvg: false - // Should the pet immediately be removed when its intimacy drops to 0? (Note 1) // If set to false the pet will randomly walk around the map before being removed. pet_remove_immediately: true diff --git a/conf/messages.conf b/conf/messages.conf index 98b0e0a9d..d8338968e 100644 --- a/conf/messages.conf +++ b/conf/messages.conf @@ -646,8 +646,10 @@ 668: Shadow Chaser T 669: Summoner -//670-853 FREE (please start using from the top if you need, leave the 670+ range for new jobs) +//670-852 FREE (please start using from the top if you need, leave the 670+ range for new jobs) + +853: NoPet | // Mapflag to disable Autoloot Commands 854: Auto loot item are disabled on this map. @@ -667,7 +669,7 @@ 863: Duel: Can't use this item in duel. 864: You cannot use this command when dead. 865: Can't create chat rooms in this area. -866: Pets are not allowed in Guild Wars. +866: Pets are disabled in this map. 867: You're not dead. 868: Your current memo positions are: 869: You broke the target's weapon. diff --git a/db/constants.conf b/db/constants.conf index 70f5569b4..700207c80 100644 --- a/db/constants.conf +++ b/db/constants.conf @@ -438,6 +438,7 @@ constants_db: { mf_pairship_endable: 58 mf_nostorage: 59 mf_nogstorage: 60 + mf_nopet: 61 comment__: "Cell Properties" cell_walkable: 0 diff --git a/doc/constants.md b/doc/constants.md index dde1647b3..18b7e9185 100644 --- a/doc/constants.md +++ b/doc/constants.md @@ -364,6 +364,7 @@ - `mf_pairship_endable`: 58 - `mf_nostorage`: 59 - `mf_nogstorage`: 60 +- `mf_nopet`: 61 ### Cell Properties diff --git a/doc/script_commands.txt b/doc/script_commands.txt index db37ef284..9bbb65c1c 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -3195,23 +3195,24 @@ This command sets a bunch of arrays with a complete list of whatever the invoking character has in its inventory, including all the data needed to recreate these items perfectly if they are destroyed. Here's what you get: -@inventorylist_id[] - array of item ids. -@inventorylist_idx[] - array of item inventory index. -@inventorylist_amount[] - their corresponding item amounts. -@inventorylist_equip[] - will return the slot the item is equipped on, if at all. -@inventorylist_refine[] - for how much it is refined. -@inventorylist_identify[] - whether it is identified. -@inventorylist_attribute[] - whether it is broken. -@inventorylist_card1[] - These four arrays contain card data for the -@inventorylist_card2[] items. These data slots are also used to store -@inventorylist_card3[] names inscribed on the items, so you can -@inventorylist_card4[] explicitly check if the character owns an item - made by a specific craftsman. -@inventorylist_expire[] - expire time (Unix time stamp). 0 means never - expires. -@inventorylist_bound[] - whether it is an account bounded item or not. -@inventorylist_favorite[] - whether it is favorite (inside favorite tab) or not. -@inventorylist_count - the number of items in these lists. +@inventorylist_id[] - array of item ids. +@inventorylist_idx[] - array of item inventory index. +@inventorylist_amount[] - their corresponding item amounts. +@inventorylist_equip[] - will return the slot the item is equipped on, if at all. +@inventorylist_refine[] - for how much it is refined. +@inventorylist_identify[] - whether it is identified. +@inventorylist_attribute[] - whether it is broken. +@inventorylist_card1[] - These four arrays contain card data for the items. +@inventorylist_card2[] These data slots are also used to store names inscribed +@inventorylist_card3[] on the items, so you can explicitly check if the character +@inventorylist_card4[] owns an item made by a specific craftsman. +@inventorylist_expire[] - expire time (Unix time stamp). 0 means never expires. +@inventorylist_bound[] - whether it is an account bounded item or not. +@inventorylist_favorite[] - whether it is favorite (inside favorite tab) or not. +@inventorylist_opt_id1~5[] - array of random option id. +@inventorylist_opt_val1~5[] - array of random option val. +@inventorylist_opt_param1~5[] - array of random option param. +@inventorylist_count - the number of items in these lists. This could be handy to save/restore a character's inventory, since no other command returns such a complete set of data, and could also be the @@ -3239,14 +3240,15 @@ recreate these items perfectly if they are destroyed. Here's what you get: @cartinventorylist_refine[] - for how much it is refined. @cartinventorylist_identify[] - whether it is identified. @cartinventorylist_attribute[] - whether it is broken. -@cartinventorylist_card1[] - These four arrays contain card data for the -@cartinventorylist_card2[] items. These data slots are also used to store -@cartinventorylist_card3[] names inscribed on the items, so you can -@cartinventorylist_card4[] explicitly check if the character owns an item - made by a specific craftsman. -@cartinventorylist_expire[] - expire time (Unix time stamp). 0 means never - expires. +@cartinventorylist_card1[] - These four arrays contain card data for the items. +@cartinventorylist_card2[] These data slots are also used to store names inscribed on the items, +@cartinventorylist_card3[] so you can explicitly check if the character owns an item +@cartinventorylist_card4[] made by a specific craftsman. +@cartinventorylist_expire[] - expire time (Unix time stamp). 0 means never expires. @cartinventorylist_bound - whether it is an account bound item or not. +@inventorylist_opt_id1~5[] - array of random option id. +@inventorylist_opt_val1~5[] - array of random option val. +@inventorylist_opt_param1~5[] - array of random option param. @cartinventorylist_count - the number of items in these lists. This could be handy to save/restore a character's cart_inventory, since no @@ -3626,7 +3628,7 @@ If the player is not found, returns -1. *gettimetick(<type>) Valid types are : - 0 - server's tick (milleseconds), unsigned int, loops every ~50 days + 0 - server's tick (milleseconds), unsigned int, loops every ~25 days 1 - time since the start of the current day in seconds 2 - UNIX epoch time (number of seconds elapsed since 1st of January 1970) @@ -7656,7 +7658,8 @@ In the OnBuyItem, two arrays are filled (@bought_nameid and and the amount sold of it. Same goes for the OnSellItem label, only the variables are named different (@sold_nameid, @sold_quantity, @sold_refine, @sold_attribute, @sold_identify, @sold_card1, @sold_card2, @sold_card3, -@sold_card4). An example on a shop comes with Hercules, and can be found +@sold_card4, @sold_opt_id1~5, @sold_opt_val1~5, @sold_opt_param1~5). +An example on a shop comes with Hercules, and can be found in the doc/sample/npc_dynamic_shop.txt file. This example shows how to use the labels and their set variables to create diff --git a/npc/mapflag/nopet.txt b/npc/mapflag/nopet.txt new file mode 100644 index 000000000..82f9e36eb --- /dev/null +++ b/npc/mapflag/nopet.txt @@ -0,0 +1,78 @@ +//================= Hercules Script ======================================= +//= _ _ _ +//= | | | | | | +//= | |_| | ___ _ __ ___ _ _| | ___ ___ +//= | _ |/ _ \ '__/ __| | | | |/ _ \/ __| +//= | | | | __/ | | (__| |_| | | __/\__ \ +//= \_| |_/\___|_| \___|\__,_|_|\___||___/ +//================= License =============================================== +//= This file is part of Hercules. +//= http://herc.ws - http://github.com/HerculesWS/Hercules +//= +//= Copyright (C) 2012-2020 Hercules Dev Team +//= +//= Hercules is free software: you can redistribute it and/or modify +//= it under the terms of the GNU General Public License as published by +//= the Free Software Foundation, either version 3 of the License, or +//= (at your option) any later version. +//= +//= This program is distributed in the hope that it will be useful, +//= but WITHOUT ANY WARRANTY; without even the implied warranty of +//= MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//= GNU General Public License for more details. +//= +//= You should have received a copy of the GNU General Public License +//= along with this program. If not, see <http://www.gnu.org/licenses/>. +//========================================================================= +//= Mapflag: Disable pet in map. +//================= Current Version ======================================= +//= 1.0 +//================= Description =========================================== +//= Players can't hatch pet in the map, existing pet will return to egg. +//========================================================================= + +// GvG Arenas ============= +// guild_vs1 mapflag nopet +// guild_vs2 mapflag nopet +// guild_vs3 mapflag nopet +// guild_vs4 mapflag nopet +// guild_vs5 mapflag nopet + +// Guild Castles ========== +// aldeg_cas01 mapflag nopet +// aldeg_cas02 mapflag nopet +// aldeg_cas03 mapflag nopet +// aldeg_cas04 mapflag nopet +// aldeg_cas05 mapflag nopet +// gefg_cas01 mapflag nopet +// gefg_cas02 mapflag nopet +// gefg_cas03 mapflag nopet +// gefg_cas04 mapflag nopet +// gefg_cas05 mapflag nopet +// payg_cas01 mapflag nopet +// payg_cas02 mapflag nopet +// payg_cas03 mapflag nopet +// payg_cas04 mapflag nopet +// payg_cas05 mapflag nopet +// prtg_cas01 mapflag nopet +// prtg_cas02 mapflag nopet +// prtg_cas03 mapflag nopet +// prtg_cas04 mapflag nopet +// prtg_cas05 mapflag nopet +// schg_cas01 mapflag nopet +// schg_cas02 mapflag nopet +// schg_cas03 mapflag nopet +// schg_cas04 mapflag nopet +// schg_cas05 mapflag nopet +// arug_cas01 mapflag nopet +// arug_cas02 mapflag nopet +// arug_cas03 mapflag nopet +// arug_cas04 mapflag nopet +// arug_cas05 mapflag nopet + +// Novice Guild Castles === +// n_castle mapflag nopet +// nguild_alde mapflag nopet +// nguild_gef mapflag nopet +// nguild_pay mapflag nopet +// nguild_prt mapflag nopet diff --git a/npc/quests/quests_amatsu.txt b/npc/quests/quests_amatsu.txt index 3c55f91a3..504ab6032 100644 --- a/npc/quests/quests_amatsu.txt +++ b/npc/quests/quests_amatsu.txt @@ -399,11 +399,14 @@ OnStartArena: enablenpc "Grandma#ama1"; enablenpc "Grandpa#ama"; warpwaitingpc "ama_test",50,83; - donpcevent "Timer#ama::OnEnable"; + enablenpc("Timer#ama"); + initnpctimer("Timer#ama"); disablewaitingroomevent "Assistant#ama"; end; OnReset: + stopnpctimer("Timer#ama"); + disablenpc("Timer#ama"); enablewaitingroomevent "Assistant#ama"; end; } @@ -620,7 +623,6 @@ ama_test,50,100,3 script Coach#ama 4_M_JPN2,15,15,{ mes "Don't lose your high self-esteem"; mes "in the future. Farewell."; close2; - donpcevent "Timer#ama::OnDisable"; warp "amatsu",223,230; disablenpc "Coach#ama"; donpcevent "Assistant#ama::OnReset"; @@ -665,7 +667,6 @@ ama_test,50,100,3 script Coach#ama 4_M_JPN2,15,15,{ setquest 8128; warp "amatsu",223,230; disablenpc "Coach#ama"; - donpcevent "Timer#ama::OnDisable"; donpcevent "Assistant#ama::OnReset"; end; } @@ -754,7 +755,6 @@ OnTouch: changequest 8129,8130; warp "amatsu",223,230; disablenpc "Coach#after"; - donpcevent "Timer#ama::OnDisable"; donpcevent "Assistant#ama::OnReset"; end; } @@ -764,14 +764,6 @@ OnInit: disablenpc "Timer#ama"; end; -OnEnable: - enablenpc "Timer#ama"; - initnpctimer; - end; -OnDisable: - stopnpctimer; - end; - OnTimer1000: mapannounce "ama_test"," The Timer has been activated. You have 6 minutes. Annihilate the monsters in time! ",bc_map; end; @@ -788,26 +780,11 @@ OnTimer361000: end; OnTimer361500: - enablenpc "backwarp#ama"; - end; - -OnTimer362000: - disablenpc "backwarp#ama"; + areawarp("ama_test", 25, 75, 80, 130, "amatsu", 115, 95); end; OnTimer362500: donpcevent "Assistant#ama::OnReset"; - donpcevent "Timer#ama::OnDisable"; - end; -} - -ama_test,50,100,0 script backwarp#ama FAKE_NPC,25,25,{ -OnInit: - disablenpc "backwarp#ama"; - end; - -OnTouch: - warp "amatsu",115,95; end; } diff --git a/npc/quests/quests_moscovia.txt b/npc/quests/quests_moscovia.txt index 3f44a9b0a..e0678cec9 100644 --- a/npc/quests/quests_moscovia.txt +++ b/npc/quests/quests_moscovia.txt @@ -1134,7 +1134,7 @@ mosk_ship,101,111,4 script rudder#ship HIDDEN_NPC,{ mes "Hey! Listen to what I am saying."; mes "How come you go there without my"; mes "permission..."; - next; + close; } mes "[Mr. Ibanoff]"; mes "What? How did you get on"; @@ -1171,7 +1171,10 @@ S_Rud1: mes "ever encountered! Be careful! We"; mes "must repulse these monsters!"; ++$@mos1_edq; - donpcevent "Baehideun3#ship::OnEnable"; + if (mos_whale_edq >= 241) + donpcevent "Baehideun4#ship::OnEnable"; + else + donpcevent "Baehideun3#ship::OnEnable"; } mos_whale_edq = (getarg(1) == 2)?((mos_whale_edq >= 241)?((.@r != 3)?26:25):((.@r != 3)?10:11)):mos_whale_edq + 1; close; diff --git a/npc/scripts_mapflags.conf b/npc/scripts_mapflags.conf index 084004244..74fb40610 100644 --- a/npc/scripts_mapflags.conf +++ b/npc/scripts_mapflags.conf @@ -58,3 +58,4 @@ "npc/mapflag/skillduration.txt", "npc/mapflag/notomb.txt", "npc/mapflag/private_airship.txt", +"npc/mapflag/nopet.txt", diff --git a/src/char/char.c b/src/char/char.c index c61b6107a..b3de22c00 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -2535,19 +2535,39 @@ static void char_changesex(int account_id, int sex) } /** - * Performs the necessary operations when changing a character's sex, such as - * correcting the job class and unequipping items, and propagating the - * information to the guild data. + * Performs the necessary operations when changing a character's gender, + * such as correcting the job class and unequipping items, + * and propagating the information to the guild data. * - * @param sex The new sex (SEX_MALE or SEX_FEMALE). - * @param acc The character's account ID. - * @param char_id The character ID. - * @param class The character's current job class. + * @param sex The character's new gender (SEX_MALE or SEX_FEMALE). + * @param acc The character's account ID. + * @param char_id The character ID. + * @param class The character's current job class. * @param guild_id The character's guild ID. - */ + * + **/ static void char_change_sex_sub(int sex, int acc, int char_id, int class, int guild_id) { - // job modification + struct SqlStmt *stmt = SQL->StmtMalloc(inter->sql_handle); + + /** If we can't save the data, there's nothing to do. **/ + if (stmt == NULL) { + SqlStmt_ShowDebug(stmt); + return; + } + + const char *query_inv = "UPDATE `%s` SET `equip`='0' WHERE `char_id`=?"; + + /** Don't change gender if resetting the view data fails to prevent character from being unable to login. **/ + if (SQL_ERROR == SQL->StmtPrepare(stmt, query_inv, inventory_db) + || SQL_ERROR == SQL->StmtBindParam(stmt, 0, SQLDT_INT32, &char_id, sizeof(char_id)) + || SQL_ERROR == SQL->StmtExecute(stmt)) { + SqlStmt_ShowDebug(stmt); + SQL->StmtFree(stmt); + return; + } + + /** Correct the job class for gender specific jobs according to the passed gender. **/ if (class == JOB_BARD || class == JOB_DANCER) class = (sex == SEX_MALE ? JOB_BARD : JOB_DANCER); else if (class == JOB_CLOWN || class == JOB_GYPSY) @@ -2563,14 +2583,30 @@ static void char_change_sex_sub(int sex, int acc, int char_id, int class, int gu else if (class == JOB_KAGEROU || class == JOB_OBORO) class = (sex == SEX_MALE ? JOB_KAGEROU : JOB_OBORO); - if (SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `%s` SET `equip`='0' WHERE `char_id`='%d'", inventory_db, char_id)) - Sql_ShowDebug(inter->sql_handle); +#if PACKETVER >= 20141016 + char gender = (sex == SEX_MALE) ? 'M' : ((sex == SEX_FEMALE) ? 'F' : 'U'); +#else + char gender = 'U'; +#endif - if (SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `%s` SET `class`='%d', `weapon`='0', `shield`='0', " - "`head_top`='0', `head_mid`='0', `head_bottom`='0' WHERE `char_id`='%d'", - char_db, class, char_id)) - Sql_ShowDebug(inter->sql_handle); - if (guild_id) // If there is a guild, update the guild_member data [Skotlex] + const char *query_char = "UPDATE `%s` SET `class`=?, `weapon`='0', `shield`='0', `head_top`='0', " + "`head_mid`='0', `head_bottom`='0', `robe`='0', `sex`=? WHERE `char_id`=?"; + + /** Don't update guild data if changing gender fails to prevent data de-synchronisation. **/ + if (SQL_ERROR == SQL->StmtPrepare(stmt, query_char, char_db) + || SQL_ERROR == SQL->StmtBindParam(stmt, 0, SQLDT_INT32, &class, sizeof(class)) + || SQL_ERROR == SQL->StmtBindParam(stmt, 1, SQLDT_ENUM, &gender, sizeof(gender)) + || SQL_ERROR == SQL->StmtBindParam(stmt, 2, SQLDT_INT32, &char_id, sizeof(char_id)) + || SQL_ERROR == SQL->StmtExecute(stmt)) { + SqlStmt_ShowDebug(stmt); + SQL->StmtFree(stmt); + return; + } + + SQL->StmtFree(stmt); + + /** Update guild member data if a guild ID was passed. **/ + if (guild_id != 0) inter_guild->sex_changed(guild_id, acc, char_id, sex); } @@ -3504,45 +3540,68 @@ static void char_ask_name_ack(int fd, int acc, const char *name, int type, int r } /** - * Changes a character's sex. - * The information is updated on database, and the character is kicked if it - * currently is online. + * Changes a character's gender. + * The information is updated on database, and the character is kicked if it currently is online. * - * @param char_id The character's ID. - * @param sex The new sex. + * @param char_id The character ID + * @param sex The character's new gender (SEX_MALE or SEX_FEMALE). * @retval 0 in case of success. * @retval 1 in case of failure. - */ + * + **/ static int char_changecharsex(int char_id, int sex) { - int class = 0, guild_id = 0, account_id = 0; - char *data; + struct SqlStmt *stmt = SQL->StmtMalloc(inter->sql_handle); - // get character data - if (SQL_ERROR == SQL->Query(inter->sql_handle, "SELECT `account_id`,`class`,`guild_id` FROM `%s` WHERE `char_id` = '%d'", char_db, char_id)) { - Sql_ShowDebug(inter->sql_handle); + /** If we can't load the data, there's nothing to do. **/ + if (stmt == NULL) { + SqlStmt_ShowDebug(stmt); return 1; } - if (SQL->NumRows(inter->sql_handle) != 1 || SQL_ERROR == SQL->NextRow(inter->sql_handle)) { - SQL->FreeResult(inter->sql_handle); + + const char *query = "SELECT `account_id`, `class`, `guild_id` FROM `%s` WHERE `char_id`=?"; + int account_id = 0; + int class = 0; + int guild_id = 0; + + /** Abort changing gender if there was an error while loading the data. **/ + if (SQL_ERROR == SQL->StmtPrepare(stmt, query, char_db) + || SQL_ERROR == SQL->StmtBindParam(stmt, 0, SQLDT_INT32, &char_id, sizeof(char_id)) + || SQL_ERROR == SQL->StmtExecute(stmt) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 0, SQLDT_INT32, &account_id, sizeof(account_id), NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 1, SQLDT_INT32, &class, sizeof(class), NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 2, SQLDT_INT32, &guild_id, sizeof(guild_id), NULL, NULL)) { + SqlStmt_ShowDebug(stmt); + SQL->StmtFree(stmt); return 1; } - SQL->GetData(inter->sql_handle, 0, &data, NULL); account_id = atoi(data); - SQL->GetData(inter->sql_handle, 1, &data, NULL); class = atoi(data); - SQL->GetData(inter->sql_handle, 2, &data, NULL); guild_id = atoi(data); - SQL->FreeResult(inter->sql_handle); - if (SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `%s` SET `sex` = '%c' WHERE `char_id` = '%d'", char_db, sex == SEX_MALE ? 'M' : 'F', char_id)) { - Sql_ShowDebug(inter->sql_handle); + /** Abort changing gender if no character was found. **/ + if (SQL->StmtNumRows(stmt) < 1) { + ShowError("char_changecharsex: Requested non-existant character! (ID: %d)\n", char_id); + SQL->StmtFree(stmt); return 1; } - char_change_sex_sub(sex, account_id, char_id, class, guild_id); - // disconnect player if online on char-server - chr->disconnect_player(account_id); + /** Abort changing gender if more than one character was found. **/ + if (SQL->StmtNumRows(stmt) > 1) { + ShowError("char_changecharsex: There are multiple characters with identical ID! (ID: %d)\n", char_id); + SQL->StmtFree(stmt); + return 1; + } + + /** Abort changing gender if fetching the data fails. **/ + if (SQL_ERROR == SQL->StmtNextRow(stmt)) { + SqlStmt_ShowDebug(stmt); + SQL->StmtFree(stmt); + return 1; + } + + SQL->StmtFree(stmt); + char_change_sex_sub(sex, account_id, char_id, class, guild_id); + chr->disconnect_player(account_id); // Disconnect player if online on char-server. + chr->changesex(account_id, sex); // Notify all mapservers about this change. - // notify all mapservers about this change - chr->changesex(account_id, sex); return 0; } diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 9d5c601bf..c1a717439 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -4101,6 +4101,8 @@ ACMD(mapinfo) strcat(atcmd_output, msg_fd(fd, 1292)); // PrivateAirshipStartable | if (map->list[m_id].flag.pairship_endable) strcat(atcmd_output, msg_fd(fd, 1293)); // PrivateAirshipEndable | + if (map->list[m_id].flag.nopet != 0) + strcat(atcmd_output, msg_fd(fd, 853)); // NoPet | clif->message(fd, atcmd_output); switch (list) { diff --git a/src/map/battle.c b/src/map/battle.c index 689622cf4..a571a555d 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -7100,7 +7100,6 @@ static const struct battle_data { { "pet_max_stats", &battle_config.pet_max_stats, 99, 0, INT_MAX, }, { "pet_max_atk1", &battle_config.pet_max_atk1, 750, 0, INT_MAX, }, { "pet_max_atk2", &battle_config.pet_max_atk2, 1000, 0, INT_MAX, }, - { "pet_disable_in_gvg", &battle_config.pet_no_gvg, 0, 0, 1, }, { "pet_remove_immediately", &battle_config.pet_remove_immediately, 1, 0, 1, }, { "skill_min_damage", &battle_config.skill_min_damage, 2|4, 0, 1|2|4, }, { "finger_offensive_type", &battle_config.finger_offensive_type, 0, 0, 1, }, diff --git a/src/map/battle.h b/src/map/battle.h index f4ad9c556..abf4c0f68 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -228,7 +228,6 @@ struct Battle_Config { int pet_max_stats; //[Skotlex] int pet_max_atk1; //[Skotlex] int pet_max_atk2; //[Skotlex] - int pet_no_gvg; //Disables pets in gvg. [Skotlex] int pet_equip_required; int pet_remove_immediately; diff --git a/src/map/clif.c b/src/map/clif.c index fd84961d9..f44d9a716 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -7661,8 +7661,8 @@ static void clif_sendegg(struct map_session_data *sd) nullpo_retv(sd); fd = sd->fd; - if (battle_config.pet_no_gvg && map_flag_gvg2(sd->bl.m)) { //Disable pet hatching in GvG grounds during Guild Wars [Skotlex] - clif->message(fd, msg_sd(sd, 866)); // "Pets are not allowed in Guild Wars." + if (map->list[sd->bl.m].flag.nopet != 0) { + clif->message(fd, msg_sd(sd, 866)); // "Pets are disabled in this map." return; } @@ -10982,8 +10982,8 @@ static void clif_parse_LoadEndAck(int fd, struct map_session_data *sd) // Spawn pet. if (sd->pd != NULL) { - if (battle_config.pet_no_gvg != 0 && map_flag_gvg2(sd->bl.m)) { // Return the pet to egg. [Skotlex] - clif->message(sd->fd, msg_sd(sd, 866)); // "Pets are not allowed in Guild Wars." + if (map->list[sd->bl.m].flag.nopet != 0) { // Return the pet to egg. [Skotlex] + clif->message(sd->fd, msg_sd(sd, 866)); // Pets are not allowed in Guild Wars. pet->menu(sd, 3); // Option 3 is return to egg. } else { pet->spawn(sd, false); diff --git a/src/map/map.c b/src/map/map.c index 221d60fa4..c88118b43 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -5469,6 +5469,19 @@ static bool map_zone_mf_cache(int m, char *flag, char *params) map_zone_mf_cache_add(m, rflag); } } + } else if (strcmpi(flag, "nopet") == 0) { + if (state == 0) { + if (map->list[m].flag.nopet != 0) { + sprintf(rflag, "nopet\t%d", map->list[m].flag.nopet); + map_zone_mf_cache_add(m, rflag); + } + } + if (sscanf(params, "%d", &state) == 1) { + if (state != map->list[m].flag.nopet) { + sprintf(rflag, "nopet\t%d", state); + map_zone_mf_cache_add(m, rflag); + } + } } return false; diff --git a/src/map/map.h b/src/map/map.h index 17f210bc3..e7c0cb50d 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -799,6 +799,7 @@ struct map_data { unsigned pairship_endable : 1; unsigned nostorage : 2; unsigned nogstorage : 2; + unsigned nopet : 1; uint32 noviewid; ///< noviewid (bitmask - @see enum equip_pos) } flag; struct point save; diff --git a/src/map/npc.c b/src/map/npc.c index 055c1843b..7a3fa9c3f 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -2715,43 +2715,47 @@ static int npc_selllist_sub(struct map_session_data *sd, struct itemlist *item_l char card_slot[NAME_LENGTH]; char opt_index_str[NAME_LENGTH]; char opt_value_str[NAME_LENGTH]; - int i, j; + char opt_param_str[NAME_LENGTH]; + int i = 0; + int j = 0; int key_nameid = 0; int key_amount = 0; int key_refine = 0; - int key_attribute = 0; + int key_attribute = ATTR_NONE; int key_identify = 0; int key_card[MAX_SLOTS]; int key_opt_idx[MAX_ITEM_OPTIONS]; int key_opt_value[MAX_ITEM_OPTIONS]; + int key_opt_param[MAX_ITEM_OPTIONS]; nullpo_ret(sd); nullpo_ret(item_list); nullpo_ret(nd); // discard old contents - script->cleararray_pc(sd, "@sold_nameid", (void*)0); - script->cleararray_pc(sd, "@sold_quantity", (void*)0); - script->cleararray_pc(sd, "@sold_refine", (void*)0); - script->cleararray_pc(sd, "@sold_attribute", (void*)0); - script->cleararray_pc(sd, "@sold_identify", (void*)0); - - for( j = 0; j < MAX_SLOTS; j++ ) - {// clear each of the card slot entries + script->cleararray_pc(sd, "@sold_nameid", (void *)0); + script->cleararray_pc(sd, "@sold_quantity", (void *)0); + script->cleararray_pc(sd, "@sold_refine", (void *)0); + script->cleararray_pc(sd, "@sold_attribute", (void *)0); + script->cleararray_pc(sd, "@sold_identify", (void *)0); + + for (j = 0; j < MAX_SLOTS; j++) { // clear each of the card slot entries key_card[j] = 0; snprintf(card_slot, sizeof(card_slot), "@sold_card%d", j + 1); - script->cleararray_pc(sd, card_slot, (void*)0); + script->cleararray_pc(sd, card_slot, (void *)0); } for (j = 0; j < MAX_ITEM_OPTIONS; j++) { // Clear Each item option entry key_opt_idx[j] = 0; key_opt_value[j] = 0; + key_opt_param[j] = 0; - snprintf(opt_index_str, sizeof(opt_index_str), "@slot_opt_idx%d", j + 1); - script->cleararray_pc(sd, opt_index_str, (void*)0); - - snprintf(opt_value_str, sizeof(opt_value_str), "@slot_opt_val%d", j + 1); - script->cleararray_pc(sd, opt_value_str, (void*)0); + snprintf(opt_index_str, sizeof(opt_index_str), "@sold_opt_idx%d", j + 1); + script->cleararray_pc(sd, opt_index_str, (void *)0); + snprintf(opt_value_str, sizeof(opt_value_str), "@sold_opt_val%d", j + 1); + script->cleararray_pc(sd, opt_value_str, (void *)0); + snprintf(opt_param_str, sizeof(opt_param_str), "@sold_opt_param%d", j + 1); + script->cleararray_pc(sd, opt_param_str, (void *)0); } // save list of to be sold items @@ -2764,32 +2768,31 @@ static int npc_selllist_sub(struct map_session_data *sd, struct itemlist *item_l intptr_t attribute = item->attribute; intptr_t identify = item->identify; - script->setarray_pc(sd, "@sold_nameid", i, (void*)nameid, &key_nameid); - script->setarray_pc(sd, "@sold_quantity", i, (void*)amount, &key_amount); - // process item based information into the arrays - script->setarray_pc(sd, "@sold_refine", i, (void*)refine, &key_refine); - script->setarray_pc(sd, "@sold_attribute", i, (void*)attribute, &key_attribute); - script->setarray_pc(sd, "@sold_identify", i, (void*)identify, &key_identify); + script->setarray_pc(sd, "@sold_nameid", i, (void *)nameid, &key_nameid); + script->setarray_pc(sd, "@sold_quantity", i, (void *)amount, &key_amount); + script->setarray_pc(sd, "@sold_refine", i, (void *)refine, &key_refine); + script->setarray_pc(sd, "@sold_attribute", i, (void *)attribute, &key_attribute); + script->setarray_pc(sd, "@sold_identify", i, (void *)identify, &key_identify); for (j = 0; j < MAX_SLOTS; j++) { intptr_t card = item->card[j]; - // store each of the cards/special info from the item in the array snprintf(card_slot, sizeof(card_slot), "@sold_card%d", j + 1); - script->setarray_pc(sd, card_slot, i, (void*)card, &key_card[j]); + script->setarray_pc(sd, card_slot, i, (void *)card, &key_card[j]); } for (j = 0; j < MAX_ITEM_OPTIONS; j++) { intptr_t opt_idx = item->option[j].index; intptr_t opt_value = item->option[j].value; + intptr_t opt_param = item->option[j].param; - snprintf(opt_index_str, sizeof(opt_index_str), "@slot_opt_idx%d", j + 1); - script->setarray_pc(sd, opt_index_str, i, (void*)opt_idx, &key_opt_idx[j]); - - snprintf(opt_value_str, sizeof(opt_value_str), "@slot_opt_val%d", j + 1); - script->setarray_pc(sd, opt_value_str, i, (void*)opt_value, &key_opt_value[j]); + snprintf(opt_index_str, sizeof(opt_index_str), "@sold_opt_idx%d", j + 1); + script->setarray_pc(sd, opt_index_str, i, (void *)opt_idx, &key_opt_idx[j]); + snprintf(opt_value_str, sizeof(opt_value_str), "@sold_opt_val%d", j + 1); + script->setarray_pc(sd, opt_value_str, i, (void *)opt_value, &key_opt_value[j]); + snprintf(opt_param_str, sizeof(opt_param_str), "@sold_opt_param%d", j + 1); + script->setarray_pc(sd, opt_param_str, i, (void *)opt_param, &key_opt_param[j]); } - } // invoke event @@ -5239,6 +5242,8 @@ static const char *npc_parse_mapflag(const char *w1, const char *w2, const char map->list[m].flag.nostorage = (state) ? cap_value(atoi(w4), 1, 3) : 0; } else if (!strcmpi(w3, "nogstorage")) { map->list[m].flag.nogstorage = (state) ? cap_value(atoi(w4), 1, 3) : 0; + } else if (strcmpi(w3, "nopet") == 0) { + map->list[m].flag.nopet = (state != 0) ? 1 : 0; } else { npc->parse_unknown_mapflag(mapname, w3, w4, start, buffer, filepath, retval); } diff --git a/src/map/script.c b/src/map/script.c index b49844320..9372299bb 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -11272,7 +11272,8 @@ static BUILDIN(gettimetick) case 0: default: //type 0:(System Ticks) - script_pushint(st,(int)timer->gettick()); // TODO: change this to int64 when we'll support 64 bit script values + // Conjunction with INT_MAX is done to prevent overflow. (Script variables are signed integers.) + script_pushint(st, timer->gettick() & INT_MAX); // TODO: change this to int64 when we'll support 64 bit script values break; } return true; @@ -14045,6 +14046,7 @@ static BUILDIN(getmapflag) case MF_PAIRSHIP_ENDABLE: script_pushint(st, map->list[m].flag.pairship_endable); break; case MF_NOSTORAGE: script_pushint(st, map->list[m].flag.nostorage); break; case MF_NOGSTORAGE: script_pushint(st, map->list[m].flag.nogstorage); break; + case MF_NOPET: script_pushint(st, map->list[m].flag.nopet); break; } } @@ -14177,6 +14179,7 @@ static BUILDIN(setmapflag) case MF_PAIRSHIP_ENDABLE: map->list[m].flag.pairship_endable = 1; break; case MF_NOSTORAGE: map->list[m].flag.nostorage = cap_value(val, 0, 3); break; case MF_NOGSTORAGE: map->list[m].flag.nogstorage = cap_value(val, 0, 3); break; + case MF_NOPET: map->list[m].flag.nopet = 1; break; } } @@ -14270,6 +14273,7 @@ static BUILDIN(removemapflag) case MF_NOVIEWID: map->list[m].flag.noviewid = EQP_NONE; break; case MF_NOSTORAGE: map->list[m].flag.nostorage = 0; break; case MF_NOGSTORAGE: map->list[m].flag.nogstorage = 0; break; + case MF_NOPET: map->list[m].flag.nopet = 0; break; } } diff --git a/src/map/script.h b/src/map/script.h index 4bf8c436b..60f403d2d 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -345,7 +345,8 @@ enum { MF_PAIRSHIP_STARTABLE, MF_PAIRSHIP_ENDABLE, MF_NOSTORAGE, - MF_NOGSTORAGE + MF_NOGSTORAGE, + MF_NOPET, }; enum navigation_service { |