summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/script_commands.txt2
-rw-r--r--npc/quests/quests_amatsu.txt33
-rw-r--r--npc/quests/quests_moscovia.txt7
-rw-r--r--src/char/char.c139
-rw-r--r--src/map/script.c3
5 files changed, 112 insertions, 72 deletions
diff --git a/doc/script_commands.txt b/doc/script_commands.txt
index 1939ae36e..9bbb65c1c 100644
--- a/doc/script_commands.txt
+++ b/doc/script_commands.txt
@@ -3628,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)
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/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/script.c b/src/map/script.c
index b49844320..75582d72f 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;