summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--conf/map/battle/pet.conf5
-rw-r--r--conf/messages.conf6
-rw-r--r--db/constants.conf1
-rw-r--r--doc/constants.md1
-rw-r--r--doc/script_commands.txt55
-rw-r--r--npc/mapflag/nopet.txt78
-rw-r--r--npc/quests/quests_amatsu.txt33
-rw-r--r--npc/quests/quests_moscovia.txt7
-rw-r--r--npc/scripts_mapflags.conf1
-rw-r--r--src/char/char.c139
-rw-r--r--src/map/atcommand.c2
-rw-r--r--src/map/battle.c1
-rw-r--r--src/map/battle.h1
-rw-r--r--src/map/clif.c8
-rw-r--r--src/map/map.c13
-rw-r--r--src/map/map.h1
-rw-r--r--src/map/npc.c65
-rw-r--r--src/map/script.c6
-rw-r--r--src/map/script.h3
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 {