summaryrefslogtreecommitdiff
path: root/src/map
diff options
context:
space:
mode:
Diffstat (limited to 'src/map')
-rw-r--r--src/map/atcommand.cpp110
-rw-r--r--src/map/chrif.cpp147
-rw-r--r--src/map/clif.cpp64
-rw-r--r--src/map/clif.hpp4
-rw-r--r--src/map/fwd.hpp1
-rw-r--r--src/map/globals.cpp2
-rw-r--r--src/map/globals.hpp1
-rw-r--r--src/map/magic-stmt.cpp2
-rw-r--r--src/map/map.cpp3
-rw-r--r--src/map/mob.cpp50
-rw-r--r--src/map/npc-parse.cpp124
-rw-r--r--src/map/npc.cpp2
-rw-r--r--src/map/pc.cpp96
-rw-r--r--src/map/pc.hpp3
-rw-r--r--src/map/quest.cpp135
-rw-r--r--src/map/quest.hpp51
-rw-r--r--src/map/script-call.cpp4
-rw-r--r--src/map/script-fun.cpp163
18 files changed, 564 insertions, 398 deletions
diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp
index f226706..7739966 100644
--- a/src/map/atcommand.cpp
+++ b/src/map/atcommand.cpp
@@ -701,6 +701,69 @@ ATCE atcommand_goto(Session *s, dumb_ptr<map_session_data> sd,
}
static
+ATCE atcommand_npc(Session *s, dumb_ptr<map_session_data> sd,
+ ZString message)
+{
+ NpcName npc;
+
+ if (!asplit(message, &npc))
+ {
+ clif_displaymessage(s,
+ "Please, enter a npc name (usage: @npc/@warptonpc/@gotonpc <npc>)."_s);
+ return ATCE::USAGE;
+ }
+
+ dumb_ptr<npc_data> nd = npc_name2id(npc);
+ if (nd != nullptr)
+ {
+ if (nd->bl_m->flag.get(MapFlag::NOWARPTO)
+ && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
+ {
+ clif_displaymessage(s,
+ "You are not authorised to warp you to the map of this npc."_s);
+ return ATCE::PERM;
+ }
+ if (sd->bl_m->flag.get(MapFlag::NOWARP)
+ && !(pc_isGM(sd).satisfies(battle_config.any_warp_GM_min_level)))
+ {
+ clif_displaymessage(s,
+ "You are not authorised to warp you from your actual map."_s);
+ return ATCE::PERM;
+ }
+
+ int x = nd->bl_x, y = nd->bl_y, x0 = (x >= 5)? (x - 5): 0, j = 0,
+ y0 = (y >= 5)? (y - 5): 0, x1 = (x + 5), y1 = (y + 5), max;
+ max = (y1 - y0 + 1) * (x1 - x0 + 1) * 3;
+ P<map_local> m = TRY_UNWRAP(map_mapname2mapid(nd->bl_m->name_), return ATCE::OKAY);
+ if (max > 1000)
+ max = 1000;
+ if (bool(map_getcell(m, x, y) & MapCell::UNWALKABLE)){
+ do
+ {
+ x = random_::in(x0, x1);
+ y = random_::in(y0, y1);
+ }
+ while (bool(map_getcell(m, x, y) & MapCell::UNWALKABLE)
+ && (++j) < max);
+ if (j >= max)
+ {
+ return ATCE::OKAY; // Since reference of the place which boils first went wrong, it stops.
+ }
+ }
+ pc_setpos(sd, nd->bl_m->name_, x, y, BeingRemoveWhy::WARPED);
+ AString output = STRPRINTF("Jump to %s"_fmt, npc);
+ clif_displaymessage(s, output);
+ }
+ else
+ {
+ clif_displaymessage(s, "Npc not found."_s);
+ return ATCE::EXIST;
+ }
+
+ return ATCE::OKAY;
+}
+
+static
ATCE atcommand_jump(Session *s, dumb_ptr<map_session_data> sd,
ZString message)
{
@@ -1528,25 +1591,6 @@ ATCE atcommand_joblevelup(Session *s, dumb_ptr<map_session_data> sd,
}
static
-ATCE atcommand_gm(Session *s, dumb_ptr<map_session_data> sd,
- ZString message)
-{
- if (!message)
- return ATCE::USAGE;
-
- if (pc_isGM(sd))
- {
- // a GM can not use this function. only a normal player (become gm is not for gm!)
- clif_displaymessage(s, "You already have some GM powers."_s);
- return ATCE::PERM;
- }
- else
- chrif_changegm(sd->status_key.account_id, message);
-
- return ATCE::OKAY;
-}
-
-static
ATCE atcommand_pvpoff(Session *s, dumb_ptr<map_session_data> sd,
ZString)
{
@@ -1586,6 +1630,25 @@ ATCE atcommand_pvpoff(Session *s, dumb_ptr<map_session_data> sd,
}
static
+ATCE atcommand_exprate(Session *s, dumb_ptr<map_session_data>,
+ ZString message)
+{
+ int rate;
+
+ if (!extract(message, &rate) || !rate)
+ {
+ clif_displaymessage(s,
+ "Please, enter a rate adjustement (usage: @exprate <percent>)."_s);
+ return ATCE::USAGE;
+ }
+ battle_config.base_exp_rate = rate;
+ battle_config.job_exp_rate = rate;
+ AString output = STRPRINTF("All Xp at %d percent"_fmt, rate);
+ clif_displaymessage(s, output);
+ return ATCE::OKAY;
+}
+
+static
ATCE atcommand_pvpon(Session *s, dumb_ptr<map_session_data> sd,
ZString)
{
@@ -4907,6 +4970,9 @@ Map<XString, AtCommandInfo> atcommand_info =
{"goto"_s, {"<charname>"_s,
40, atcommand_goto,
"Warp yourself to another character"_s}},
+ {"npc"_s, {"<npc>"_s,
+ 40, atcommand_npc,
+ "Warp yourself to a npc"_s}},
{"jump"_s, {"[x] [y]"_s,
40, atcommand_jump,
"Warp yourself within a map"_s}},
@@ -4976,12 +5042,12 @@ Map<XString, AtCommandInfo> atcommand_info =
{"jlvl"_s, {"<delta>"_s,
60, atcommand_joblevelup,
"Adjust your job level"_s}},
- {"gm"_s, {"<password>"_s,
- 100, atcommand_gm,
- "Receive GM powers"_s}},
{"pvpoff"_s, {""_s,
60, atcommand_pvpoff,
"Enable PvP on your map"_s}},
+ {"exprate"_s, {"<percent>"_s,
+ 60, atcommand_exprate,
+ "Set base job/exp rate"_s}},
{"pvpon"_s, {""_s,
60, atcommand_pvpon,
"Disable PvP on your map"_s}},
diff --git a/src/map/chrif.cpp b/src/map/chrif.cpp
index bf4ae4e..2606911 100644
--- a/src/map/chrif.cpp
+++ b/src/map/chrif.cpp
@@ -218,7 +218,7 @@ int chrif_changemapserverack(Session *, const Packet_Fixed<0x2b06>& fixed)
if (fixed.error == 1)
{
if (battle_config.error_log)
- PRINTF("map server change failed.\n"_fmt);
+ PRINTF("Changing the map server failed.\n"_fmt);
pc_authfail(sd->status_key.account_id);
return 0;
}
@@ -241,7 +241,7 @@ int chrif_connectack(Session *s, const Packet_Fixed<0x2af9>& fixed)
{
if (fixed.code)
{
- PRINTF("Connected to char-server failed %d.\n"_fmt, fixed.code);
+ PRINTF("Connecting to char-server failed %d.\n"_fmt, fixed.code);
exit(1);
}
PRINTF("Connected to char-server (connection #%d).\n"_fmt, s);
@@ -249,11 +249,6 @@ int chrif_connectack(Session *s, const Packet_Fixed<0x2af9>& fixed)
chrif_sendmap(s);
- PRINTF("chrif: OnCharIfInit event done. (%d events)\n"_fmt,
- npc_event_doall(stringish<ScriptLabel>("OnCharIfInit"_s)));
- PRINTF("chrif: OnInterIfInit event done. (%d events)\n"_fmt,
- npc_event_doall(stringish<ScriptLabel>("OnInterIfInit"_s)));
-
return 0;
}
@@ -266,7 +261,7 @@ int chrif_sendmapack(Session *, Packet_Fixed<0x2afb> fixed)
{
if (fixed.unknown) //impossible
{
- PRINTF("chrif : send map list to char server failed %d\n"_fmt,
+ PRINTF("chrif: sending the map list to char-server failed %d\n"_fmt,
fixed.unknown);
exit(1);
}
@@ -345,23 +340,6 @@ int chrif_charselectreq(dumb_ptr<map_session_data> sd)
}
/*==========================================
- * GMに変化要求
- *------------------------------------------
- */
-void chrif_changegm(AccountId id, ZString pass)
-{
- if (!char_session)
- return;
-
- if (battle_config.etc_log)
- PRINTF("chrif_changegm: account: %d, password: '%s'.\n"_fmt, id, pass);
-
- Packet_Head<0x2b0a> head_0a;
- head_0a.account_id = id;
- send_vpacket<0x2b0a, 8, 1>(char_session, head_0a, pass);
-}
-
-/*==========================================
* Change Email
*------------------------------------------
*/
@@ -405,7 +383,7 @@ void chrif_char_ask_name(AccountId id, CharName character_name, short operation_
fixed_0e.operation = operation_type; // type of operation
if (operation_type == 2)
fixed_0e.ban_add = modif;
- PRINTF("chrif : sended 0x2b0e\n"_fmt);
+ PRINTF("chrif: sent 0x2b0e\n"_fmt);
send_fpacket<0x2b0e, 44>(char_session, fixed_0e);
}
@@ -419,7 +397,7 @@ void chrif_char_ask_name(AccountId id, CharName character_name, short operation_
* 4: unban
* 5: changesex
* type of answer:
- * 0: login-server resquest done
+ * 0: login-server request done
* 1: player not found
* 2: gm level too low
* 3: login-server offline
@@ -436,7 +414,7 @@ int chrif_char_ask_name_answer(Session *, const Packet_Fixed<0x2b0f>& fixed)
{
AString output;
if (fixed.error == 1) // player not found
- output = STRPRINTF("The player '%s' doesn't exist."_fmt,
+ output = STRPRINTF("The player, '%s,' doesn't exist."_fmt,
player_name);
else
{
@@ -445,20 +423,20 @@ int chrif_char_ask_name_answer(Session *, const Packet_Fixed<0x2b0f>& fixed)
case 1: // block
switch (fixed.error)
{
- case 0: // login-server resquest done
+ case 0: // login-server request done
output = STRPRINTF(
- "Login-server has been asked to block the player '%s'."_fmt,
+ "Login-server has been asked to block '%s'."_fmt,
player_name);
break;
//case 1: // player not found
case 2: // gm level too low
output = STRPRINTF(
- "Your GM level don't authorise you to block the player '%s'."_fmt,
+ "Your GM level doesn't authorize you to block the player '%s'."_fmt,
player_name);
break;
case 3: // login-server offline
output = STRPRINTF(
- "Login-server is offline. Impossible to block the the player '%s'."_fmt,
+ "Login-server is offline, so it's impossible to block '%s'."_fmt,
player_name);
break;
}
@@ -466,20 +444,20 @@ int chrif_char_ask_name_answer(Session *, const Packet_Fixed<0x2b0f>& fixed)
case 2: // ban
switch (fixed.error)
{
- case 0: // login-server resquest done
+ case 0: // login-server request done
output = STRPRINTF(
- "Login-server has been asked to ban the player '%s'."_fmt,
+ "Login-server has been asked to ban '%s'."_fmt,
player_name);
break;
//case 1: // player not found
case 2: // gm level too low
output = STRPRINTF(
- "Your GM level don't authorise you to ban the player '%s'."_fmt,
+ "Your GM level doesn't authorize you to ban '%s'."_fmt,
player_name);
break;
case 3: // login-server offline
output = STRPRINTF(
- "Login-server is offline. Impossible to ban the the player '%s'."_fmt,
+ "Login-server is offline, so it's impossible to ban '%s'."_fmt,
player_name);
break;
}
@@ -487,20 +465,20 @@ int chrif_char_ask_name_answer(Session *, const Packet_Fixed<0x2b0f>& fixed)
case 3: // unblock
switch (fixed.error)
{
- case 0: // login-server resquest done
+ case 0: // login-server request done
output = STRPRINTF(
- "Login-server has been asked to unblock the player '%s'."_fmt,
+ "Login-server has been asked to unblock '%s'."_fmt,
player_name);
break;
//case 1: // player not found
case 2: // gm level too low
output = STRPRINTF(
- "Your GM level don't authorise you to unblock the player '%s'."_fmt,
+ "Your GM level doesn't authorize you to unblock '%s'."_fmt,
player_name);
break;
case 3: // login-server offline
output = STRPRINTF(
- "Login-server is offline. Impossible to unblock the the player '%s'."_fmt,
+ "Login-server is offline, so it's impossible to unblock '%s'."_fmt,
player_name);
break;
}
@@ -508,20 +486,20 @@ int chrif_char_ask_name_answer(Session *, const Packet_Fixed<0x2b0f>& fixed)
case 4: // unban
switch (fixed.error)
{
- case 0: // login-server resquest done
+ case 0: // login-server request done
output = STRPRINTF(
- "Login-server has been asked to unban the player '%s'."_fmt,
+ "Login-server has been asked to unban '%s'."_fmt,
player_name);
break;
//case 1: // player not found
case 2: // gm level too low
output = STRPRINTF(
- "Your GM level don't authorise you to unban the player '%s'."_fmt,
+ "Your GM level doesn't authorize you to unban '%s'."_fmt,
player_name);
break;
case 3: // login-server offline
output = STRPRINTF(
- "Login-server is offline. Impossible to unban the the player '%s'."_fmt,
+ "Login-server is offline, so it's impossible to unban '%s'."_fmt,
player_name);
break;
}
@@ -529,20 +507,20 @@ int chrif_char_ask_name_answer(Session *, const Packet_Fixed<0x2b0f>& fixed)
case 5: // changesex
switch (fixed.error)
{
- case 0: // login-server resquest done
+ case 0: // login-server request done
output = STRPRINTF(
- "Login-server has been asked to change the sex of the player '%s'."_fmt,
+ "Login-server has been asked to change the sex of '%s'."_fmt,
player_name);
break;
//case 1: // player not found
case 2: // gm level too low
output = STRPRINTF(
- "Your GM level don't authorise you to change the sex of the player '%s'."_fmt,
+ "Your GM level doesn't authorize you to change the sex of '%s'."_fmt,
player_name);
break;
case 3: // login-server offline
output = STRPRINTF(
- "Login-server is offline. Impossible to change the sex of the the player '%s'."_fmt,
+ "Login-server is offline, so it's impossible to change the sex of '%s'."_fmt,
player_name);
break;
}
@@ -553,36 +531,12 @@ int chrif_char_ask_name_answer(Session *, const Packet_Fixed<0x2b0f>& fixed)
clif_displaymessage(sd->sess, output);
}
else
- PRINTF("chrif_char_ask_name_answer failed - player not online.\n"_fmt);
+ PRINTF("chrif_char_ask_name_answer failed because the player is not online.\n"_fmt);
return 0;
}
/*==========================================
- * End of GM change(@GM) (modified by Yor)
- *------------------------------------------
- */
-static
-void chrif_changedgm(Session *, const Packet_Fixed<0x2b0b>& fixed)
-{
- AccountId acc = fixed.account_id;
- GmLevel level = fixed.gm_level;
-
- dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(acc));
-
- if (battle_config.etc_log)
- PRINTF("chrif_changedgm: account: %d, GM level 0 -> %d.\n"_fmt, acc,
- level);
- if (sd != nullptr)
- {
- if (level)
- clif_displaymessage(sd->sess, "GM modification success."_s);
- else
- clif_displaymessage(sd->sess, "Failure of GM modification."_s);
- }
-}
-
-/*==========================================
* 性別変化終了 (modified by Yor)
*------------------------------------------
*/
@@ -609,15 +563,14 @@ void chrif_changedsex(Session *, const Packet_Fixed<0x2b0d>& fixed)
{
if (sd->status.inventory[i].nameid
&& bool(sd->status.inventory[i].equip))
- pc_unequipitem(sd, i, CalcStatus::NOW);
+ pc_unequipitem(sd, i, CalcStatus::LATER);
}
+ pc_calcstatus(sd, 0);
// save character
chrif_save(sd);
sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters
// do same modify in login-server for the account, but no in char-server (it ask again login_id1 to login, and don't remember it)
- clif_displaymessage(sd->sess,
- "Your sex has been changed (need disconexion by the server)..."_s);
- clif_setwaitclose(sd->sess); // forced to disconnect for the change
+ clif_fixpcpos(sd); // use clif_set0078_main_1d8 to send new sex to the client
}
}
else
@@ -746,14 +699,14 @@ int chrif_accountdeletion(Session *, const Packet_Fixed<0x2b13>& fixed)
{
sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters
clif_displaymessage(sd->sess,
- "Your account has been deleted (disconnection)..."_s);
+ "Your account has been deleted. You will now be disconnected..."_s);
clif_setwaitclose(sd->sess); // forced to disconnect for the change
}
}
else
{
if (sd != nullptr)
- PRINTF("chrif_accountdeletion failed - player not online.\n"_fmt);
+ PRINTF("chrif_accountdeletion failed because the player is not online.\n"_fmt);
}
return 0;
@@ -783,11 +736,11 @@ int chrif_accountban(Session *, const Packet_Fixed<0x2b14>& fixed)
{ // status or final date of a banishment
case 1: // 0 = Unregistered ID
clif_displaymessage(sd->sess,
- "Your account has 'Unregistered'."_s);
+ "Your account has an unregistered ID."_s);
break;
case 2: // 1 = Incorrect Password
clif_displaymessage(sd->sess,
- "Your account has an 'Incorrect Password'..."_s);
+ "Your password is incorrect."_s);
break;
case 3: // 2 = This ID is expired
clif_displaymessage(sd->sess,
@@ -795,7 +748,7 @@ int chrif_accountban(Session *, const Packet_Fixed<0x2b14>& fixed)
break;
case 4: // 3 = Rejected from Server
clif_displaymessage(sd->sess,
- "Your account has been rejected from server."_s);
+ "Your account has been rejected by the server."_s);
break;
case 5: // 4 = You have been blocked by the GM Team
clif_displaymessage(sd->sess,
@@ -803,19 +756,19 @@ int chrif_accountban(Session *, const Packet_Fixed<0x2b14>& fixed)
break;
case 6: // 5 = Your Game's EXE file is not the latest version
clif_displaymessage(sd->sess,
- "Your Game's EXE file is not the latest version."_s);
+ "You need to update your client."_s);
break;
case 7: // 6 = Your are Prohibited to log in until %s
clif_displaymessage(sd->sess,
- "Your account has been prohibited to log in."_s);
+ "Your account has been prohibited from logging in."_s);
break;
case 8: // 7 = Server is jammed due to over populated
clif_displaymessage(sd->sess,
- "Server is jammed due to over populated."_s);
+ "The server is overpopulated."_s);
break;
case 9: // 8 = No MSG (actually, all states after 9 except 99 are No MSG, use only this)
clif_displaymessage(sd->sess,
- "Your account has not more authorised."_s);
+ "Your account must be authorized."_s);
break;
case 100: // 99 = This ID has been totally erased
clif_displaymessage(sd->sess,
@@ -823,7 +776,7 @@ int chrif_accountban(Session *, const Packet_Fixed<0x2b14>& fixed)
break;
default:
clif_displaymessage(sd->sess,
- "Your account has not more authorised."_s);
+ "Your account must be authorized."_s);
break;
}
}
@@ -842,7 +795,7 @@ int chrif_accountban(Session *, const Packet_Fixed<0x2b14>& fixed)
else
{
if (sd != nullptr)
- PRINTF("chrif_accountban failed - player not online.\n"_fmt);
+ PRINTF("chrif_accountban failed because the player is not online.\n"_fmt);
}
return 0;
@@ -855,7 +808,7 @@ int chrif_accountban(Session *, const Packet_Fixed<0x2b14>& fixed)
static
int chrif_recvgmaccounts(Session *s, const std::vector<Packet_Repeat<0x2b15>>& repeat)
{
- PRINTF("From login-server: receiving of %d GM accounts information.\n"_fmt,
+ PRINTF("Receiving information on %d GM accounts from login-server.\n"_fmt,
pc_read_gm_account(s, repeat));
return 0;
@@ -865,7 +818,7 @@ static
void chrif_delete(Session *s)
{
assert (s == char_session);
- PRINTF("Map-server can't connect to char-server (connection #%d).\n"_fmt,
+ PRINTF("map-server can't connect to char-server (connection #%d).\n"_fmt,
s);
char_session = nullptr;
}
@@ -973,16 +926,6 @@ void chrif_parse(Session *s)
chrif_changemapserverack(s, fixed);
break;
}
- case 0x2b0b:
- {
- Packet_Fixed<0x2b0b> fixed;
- rv = recv_fpacket<0x2b0b, 10>(s, fixed);
- if (rv != RecvResult::Complete)
- break;
-
- chrif_changedgm(s, fixed);
- break;
- }
case 0x2b0d:
{
Packet_Fixed<0x2b0d> fixed;
@@ -1064,7 +1007,7 @@ void chrif_parse(Session *s)
return;
if (battle_config.error_log)
- PRINTF("chrif_parse : unknown packet %d %d\n"_fmt, s,
+ PRINTF("chrif_parse: unknown packet %d %d\n"_fmt, s,
packet_id);
s->set_eof();
return;
@@ -1118,7 +1061,7 @@ void check_connect_char_server(TimerData *, tick_t)
{
if (!char_session)
{
- PRINTF("Attempt to connect to char-server...\n"_fmt);
+ PRINTF("Attempting to connect to char-server...\n"_fmt);
chrif_state = 0;
char_session = make_connection(map_conf.char_ip, map_conf.char_port,
SessionParsers{.func_parse= chrif_parse, .func_delete= chrif_delete});
diff --git a/src/map/clif.cpp b/src/map/clif.cpp
index 577d7be..2c65d44 100644
--- a/src/map/clif.cpp
+++ b/src/map/clif.cpp
@@ -198,11 +198,6 @@ int is_deaf(dumb_ptr<block_list> bl)
return sd->special_state.deaf;
}
-static
-void clif_emotion_towards(dumb_ptr<block_list> bl,
- dumb_ptr<block_list> target, int type);
-
-
enum class ChatType
{
Party,
@@ -906,7 +901,7 @@ int clif_spawnnpc(dumb_ptr<npc_data> nd)
{
nullpo_retz(nd);
- if (nd->npc_class == NEGATIVE_SPECIES || nd->flag & 1 || nd->npc_class == INVISIBLE_CLASS)
+ if (nd->flag & 1 || nd->npc_class == INVISIBLE_CLASS)
return 0;
Packet_Fixed<0x007c> fixed_7c;
@@ -2325,7 +2320,7 @@ void clif_getareachar_npc(dumb_ptr<map_session_data> sd, dumb_ptr<npc_data> nd)
nullpo_retv(sd);
nullpo_retv(nd);
- if (nd->npc_class == NEGATIVE_SPECIES || nd->flag & 1 || nd->npc_class == INVISIBLE_CLASS)
+ if (nd->flag & 1 || nd->npc_class == INVISIBLE_CLASS)
return;
Buffer buf;
@@ -3113,7 +3108,6 @@ void clif_emotion(dumb_ptr<block_list> bl, int type)
clif_send(buf, bl, SendWho::AREA);
}
-static
void clif_emotion_towards(dumb_ptr<block_list> bl,
dumb_ptr<block_list> target, int type)
{
@@ -4671,6 +4665,60 @@ RecvResult clif_parse_PartyMessage(Session *s, dumb_ptr<map_session_data> sd)
return rv;
}
+void clif_sendallquest(dumb_ptr<map_session_data> sd)
+{
+ int i;
+ QuestId questid;
+ if (!sd)
+ return;
+
+ if (!sd->sess)
+ return;
+
+ Session *s = sd->sess;
+ Packet_Head<0x0215> head_215;
+ std::vector<Packet_Repeat<0x0215>> repeat_215;
+
+ assert (sd->status.global_reg_num < GLOBAL_REG_NUM);
+ for (QuestId q = wrap<QuestId>(0); q < wrap<QuestId>(-1); q = next(q))
+ {
+ P<struct quest_data> quest_data_ = TRY_UNWRAP(questdb_exists(q), continue);
+ for (i = 0; i < sd->status.global_reg_num; i++)
+ {
+ if (sd->status.global_reg[i].str == quest_data_->quest_vr)
+ {
+ int val = ((sd->status.global_reg[i].value & (((1 << quest_data_->quest_mask) - 1) << (quest_data_->quest_shift * quest_data_->quest_mask))) >> (quest_data_->quest_shift * quest_data_->quest_mask));
+ Packet_Repeat<0x0215> info;
+ info.variable = unwrap<QuestId>(quest_data_->questid);
+ info.value = val;
+ repeat_215.push_back(info);
+ break;
+ }
+ }
+ }
+
+ send_vpacket<0x0215, 4, 6>(s, head_215, repeat_215);
+ return;
+}
+
+void clif_sendquest(dumb_ptr<map_session_data> sd, QuestId questid, int value)
+{
+ if (!sd)
+ return;
+
+ if (!sd->sess)
+ return;
+
+ Session *s = sd->sess;
+
+ Packet_Fixed<0x0214> fixed;
+ fixed.variable = unwrap<QuestId>(questid);
+ fixed.value = value;
+ send_fpacket<0x0214, 8>(s, fixed);
+ return;
+}
+
+
func_table clif_parse_func_table[0x0220] =
{
{0, 10, nullptr, }, // 0x0000
diff --git a/src/map/clif.hpp b/src/map/clif.hpp
index 153cc7c..5117ff3 100644
--- a/src/map/clif.hpp
+++ b/src/map/clif.hpp
@@ -96,6 +96,7 @@ int clif_changeoption(dumb_ptr<block_list>); // area
int clif_useitemack(dumb_ptr<map_session_data>, IOff0, int, int); // self
void clif_emotion(dumb_ptr<block_list> bl, int type);
+void clif_emotion_towards(dumb_ptr<block_list> bl, dumb_ptr<block_list> target, int type);
void clif_sitting(Session *, dumb_ptr<map_session_data> sd);
// trade
@@ -174,6 +175,9 @@ int clif_GM_kick(dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> tsd,
int type);
int clif_foreachclient(std::function<void(dumb_ptr<map_session_data>)>);
+// quest
+void clif_sendallquest(dumb_ptr<map_session_data> sd);
+void clif_sendquest(dumb_ptr<map_session_data> sd, QuestId questid, int value);
void do_init_clif(void);
} // namespace map
diff --git a/src/map/fwd.hpp b/src/map/fwd.hpp
index 1db4ed0..911d566 100644
--- a/src/map/fwd.hpp
+++ b/src/map/fwd.hpp
@@ -65,6 +65,7 @@ class npc_data_warp;
class npc_data_message;
struct item_data;
+struct quest_data;
struct ScriptState;
struct str_data_t;
diff --git a/src/map/globals.cpp b/src/map/globals.cpp
index 09ff157..dce3906 100644
--- a/src/map/globals.cpp
+++ b/src/map/globals.cpp
@@ -26,6 +26,7 @@
#include "battle_conf.hpp"
#include "itemdb.hpp"
+#include "quest.hpp"
#include "magic-interpreter.hpp"
#include "map_conf.hpp"
#include "mob.hpp"
@@ -49,6 +50,7 @@ namespace tmwa
int chrif_state;
std::map<MapName, RString> resnametable;
Map<ItemNameId, item_data> item_db;
+ Map<QuestId, quest_data> quest_db;
namespace magic
{
// Global magic conf
diff --git a/src/map/globals.hpp b/src/map/globals.hpp
index 33cfec8..b457b4e 100644
--- a/src/map/globals.hpp
+++ b/src/map/globals.hpp
@@ -48,6 +48,7 @@ namespace tmwa
extern int chrif_state;
extern std::map<MapName, RString> resnametable;
extern Map<ItemNameId, item_data> item_db;
+ extern Map<QuestId, quest_data> quest_db;
namespace magic
{
// Global magic conf
diff --git a/src/map/magic-stmt.cpp b/src/map/magic-stmt.cpp
index fdeac3a..4d8330a 100644
--- a/src/map/magic-stmt.cpp
+++ b/src/map/magic-stmt.cpp
@@ -773,7 +773,7 @@ int op_injure(dumb_ptr<env_t> env, Slice<val_t> args)
if (target->bl_type == BL::PC
&& !target->bl_m->flag.get(MapFlag::PVP)
- && (caster->bl_type != BL::PC)
+ && (caster->bl_type == BL::PC)
&& ((caster->is_player()->state.pvpchannel > 1) && (target->is_player()->state.pvpchannel != caster->is_player()->state.pvpchannel)))
return 0; /* Cannot damage other players outside of pvp */
diff --git a/src/map/map.cpp b/src/map/map.cpp
index d502fbb..c1d760a 100644
--- a/src/map/map.cpp
+++ b/src/map/map.cpp
@@ -74,6 +74,7 @@
#include "magic-v2.hpp"
#include "map_conf.hpp"
#include "mob.hpp"
+#include "quest.hpp"
#include "npc.hpp"
#include "npc-parse.hpp"
#include "party.hpp"
@@ -1489,6 +1490,8 @@ bool map_confs(io::Spanned<XString> key, io::Spanned<ZString> value)
return itemdb_readdb(value.data);
if (key.data == "mob_db"_s)
return mob_readdb(value.data);
+ if (key.data == "quest_db"_s)
+ return quest_readdb(value.data);
if (key.data == "mob_skill_db"_s)
return mob_readskilldb(value.data);
if (key.data == "skill_db"_s)
diff --git a/src/map/mob.cpp b/src/map/mob.cpp
index cdb348c..539b547 100644
--- a/src/map/mob.cpp
+++ b/src/map/mob.cpp
@@ -333,8 +333,7 @@ int mob_gen_exp(mob_db_ *mob)
int xp = floor(effective_hp * pow(sqrt(attack_factor)
+ sqrt(dodge_factor)
+ sqrt(persuit_factor) + 55, 3)
- * aggression_factor / 2000000.0
- * static_cast<double>(battle_config.base_exp_rate) / 100.);
+ * aggression_factor / 2000000.0);
if (xp < 1)
xp = 1;
PRINTF("Exp for mob '%s' generated: %d\n"_fmt, mob->name, xp);
@@ -3531,30 +3530,33 @@ bool mob_readdb(ZString filename)
continue;
}
- // TODO move this lower
- get_mob_db(mob_class) = std::move(mdbv);
-
if (get_mob_db(mob_class).base_exp < 0)
- get_mob_db(mob_class).base_exp = 0;
- else if (get_mob_db(mob_class).base_exp > 0
- && (get_mob_db(mob_class).base_exp *
- battle_config.base_exp_rate / 100 > 1000000000
- || get_mob_db(mob_class).base_exp *
- battle_config.base_exp_rate / 100 < 0))
- get_mob_db(mob_class).base_exp = 1000000000;
- else
- get_mob_db(mob_class).base_exp = get_mob_db(mob_class).base_exp * battle_config.base_exp_rate / 100;
-
+ {
+ PRINTF("bad mob line: Xp needs to be greater than 0. %s\n"_fmt, line);
+ rv = false;
+ continue;
+ }
+ if (get_mob_db(mob_class).base_exp > 1000000000)
+ {
+ PRINTF("bad mob line: Xp needs to be less than 1000000000. %s\n"_fmt, line);
+ rv = false;
+ continue;
+ }
if (get_mob_db(mob_class).job_exp < 0)
- get_mob_db(mob_class).job_exp = 0;
- else if (get_mob_db(mob_class).job_exp > 0
- && (get_mob_db(mob_class).job_exp * battle_config.job_exp_rate /
- 100 > 1000000000
- || get_mob_db(mob_class).job_exp *
- battle_config.job_exp_rate / 100 < 0))
- get_mob_db(mob_class).job_exp = 1000000000;
- else
- get_mob_db(mob_class).job_exp = get_mob_db(mob_class).job_exp * battle_config.job_exp_rate / 100;
+ {
+ PRINTF("bad mob line: Job Xp needs to be greater than 0. %s\n"_fmt, line);
+ rv = false;
+ continue;
+ }
+ if (get_mob_db(mob_class).job_exp > 1000000000)
+ {
+ PRINTF("bad mob line: Job Xp needs to be less than 1000000000. %s\n"_fmt, line);
+ rv = false;
+ continue;
+ }
+
+ // TODO move this lower
+ get_mob_db(mob_class) = std::move(mdbv);
for (int i = 0; i < 8; i++)
{
diff --git a/src/map/npc-parse.cpp b/src/map/npc-parse.cpp
index 443a1e7..4d9fcbd 100644
--- a/src/map/npc-parse.cpp
+++ b/src/map/npc-parse.cpp
@@ -339,7 +339,7 @@ bool npc_load_mapflag(ast::npc::MapFlag& mapflag)
return false;
}
- if (battle_config.pk_mode && mf == MapFlag::NOPVP)
+ if (mf == MapFlag::NOPVP)
{
if (mapflag.vec_extra.data.size())
{
@@ -446,7 +446,7 @@ bool npc_load_script_none(ast::script::ScriptBody& body, ast::npc::ScriptNone& s
nd->bl_id = npc_get_new_npc_id();
nd->dir = DIR::S;
nd->flag = 0;
- nd->npc_class = NEGATIVE_SPECIES;
+ nd->npc_class = INVISIBLE_CLASS;
nd->speed = 200_ms;
nd->scr.script = std::move(script);
nd->option = Opt0::ZERO;
@@ -514,115 +514,6 @@ bool npc_load_script_none(ast::script::ScriptBody& body, ast::npc::ScriptNone& s
}
static
-bool npc_load_script_map_none(ast::script::ScriptBody& body, ast::npc::ScriptMapNone& script_map_none)
-{
- MapName mapname = script_map_none.m.data;
- int x = script_map_none.x.data, y = script_map_none.y.data;
- DIR dir = script_map_none.d.data;
- P<map_local> m = TRY_UNWRAP(map_mapname2mapid(mapname),
- {
- script_map_none.m.span.error("No such map"_s);
- return false;
- });
-
- std::unique_ptr<const ScriptBuffer> script = compile_script(STRPRINTF("script npc \"%s\""_fmt, script_map_none.name.data), body, false);
- if (script == nullptr)
- return false;
-
- dumb_ptr<npc_data_script> nd;
- nd.new_();
- nd->scr.event_needs_map = false;
-
- nd->name = script_map_none.name.data;
-
- nd->bl_prev = nd->bl_next = nullptr;
- nd->bl_m = m;
- nd->bl_x = x;
- nd->bl_y = y;
- nd->bl_id = npc_get_new_npc_id();
- nd->dir = dir;
- nd->flag = 0;
- nd->npc_class = NEGATIVE_SPECIES;
- nd->speed = 200_ms;
- nd->scr.script = std::move(script);
- nd->option = Opt0::ZERO;
- nd->opt1 = Opt1::ZERO;
- nd->opt2 = Opt2::ZERO;
- nd->opt3 = Opt3::ZERO;
-
- npc_script++;
- nd->bl_type = BL::NPC;
- nd->npc_subtype = NpcSubtype::SCRIPT;
-
- nd->n = map_addnpc(m, nd);
- map_addblock(nd);
-
- {
- struct event_data ev {};
- ev.nd = nd;
- ev.pos = 0;
- NpcEvent npcev;
- npcev.npc = nd->name;
- npcev.label = ScriptLabel();
- ev_db.insert(npcev, ev);
- }
-
- register_npc_name(nd);
-
- for (auto& pair : scriptlabel_db)
- npc_convertlabel_db(pair.first, pair.second, nd);
-
- for (npc_label_list& el : nd->scr.label_listv)
- {
- ScriptLabel lname = el.name;
- int pos = el.pos;
-
- if (lname.startswith("On"_s))
- {
- struct event_data ev {};
- ev.nd = nd;
- ev.pos = pos;
- NpcEvent buf;
- buf.npc = nd->name;
- buf.label = lname;
- ev_db.insert(buf, ev);
- }
- }
-
- for (npc_label_list& el : nd->scr.label_listv)
- {
- int t_ = 0;
- ScriptLabel lname = el.name;
- int pos = el.pos;
- if (lname.startswith("OnTimer"_s) && extract(lname.xslice_t(7), &t_) && t_ > 0)
- {
- interval_t t = static_cast<interval_t>(t_);
-
- npc_timerevent_list tel {};
- tel.timer = t;
- tel.pos = pos;
-
- auto it = std::lower_bound(nd->scr.timer_eventv.begin(), nd->scr.timer_eventv.end(), tel,
- [](const npc_timerevent_list& l, const npc_timerevent_list& r)
- {
- return l.timer < r.timer;
- }
- );
- assert (it == nd->scr.timer_eventv.end() || it->timer != tel.timer);
-
- nd->scr.timer_eventv.insert(it, std::move(tel));
- }
- }
- // The counter starts stopped with 0 ticks, which is the first event,
- // unless there is none, in which case begin == end.
- nd->scr.timer = interval_t::zero();
- nd->scr.next_event = nd->scr.timer_eventv.begin();
- // nd->scr.timerid = nullptr;
-
- return true;
-}
-
-static
bool npc_load_script_map(ast::script::ScriptBody& body, ast::npc::ScriptMap& script_map)
{
MapName mapname = script_map.m.data;
@@ -761,17 +652,6 @@ bool npc_load_script_any(ast::npc::Script *script)
{
return npc_load_script_none(script->body, script_none);
}
- MATCH_CASE (ast::npc::ScriptMapNone&, script_map_none)
- {
- auto& mapname = script_map_none.m;
- Option<P<map_local>> m = map_mapname2mapid(mapname.data);
- if (m.is_none())
- {
- mapname.span.error(STRPRINTF("Map not found: %s"_fmt, mapname.data));
- return false;
- }
- return npc_load_script_map_none(script->body, script_map_none);
- }
MATCH_CASE (ast::npc::ScriptMap&, script_map)
{
auto& mapname = script_map.m;
diff --git a/src/map/npc.cpp b/src/map/npc.cpp
index 56c33cc..4296432 100644
--- a/src/map/npc.cpp
+++ b/src/map/npc.cpp
@@ -583,7 +583,7 @@ int npc_checknear(dumb_ptr<map_session_data> sd, BlockId id)
if (nd->bl_type != BL::NPC)
return 1;
- if (nd->npc_class == NEGATIVE_SPECIES)
+ if (nd->npc_class == INVISIBLE_CLASS)
return 0;
// エリア判定
diff --git a/src/map/pc.cpp b/src/map/pc.cpp
index 29be372..6fa35b0 100644
--- a/src/map/pc.cpp
+++ b/src/map/pc.cpp
@@ -64,6 +64,7 @@
#include "skill.hpp"
#include "storage.hpp"
#include "trade.hpp"
+#include "quest.hpp"
#include "../poison.hpp"
@@ -794,6 +795,9 @@ int pc_authok(AccountId id, int login_id2,
pc_calcstatus(sd, 1);
+ npc_event_doall_l(stringish<ScriptLabel>("OnPCLoginEvent"_s), sd->bl_id, nullptr);
+ // Init Quest Log
+ clif_sendallquest(sd);
return 0;
}
@@ -2854,6 +2858,12 @@ int pc_gainexp_reason(dumb_ptr<map_session_data> sd, int base_exp, int job_exp,
}
}
+ // Double Xp Weekends
+ base_exp = (base_exp * static_cast<double>(battle_config.base_exp_rate) / 100.);
+ if (base_exp <= 0)
+ base_exp = 0;
+ else if (base_exp > 1000000000)
+ base_exp = 1000000000;
sd->status.base_exp += base_exp;
// [Fate] Adjust experience points that healers can extract from this character
@@ -2861,7 +2871,6 @@ int pc_gainexp_reason(dumb_ptr<map_session_data> sd, int base_exp, int job_exp,
{
const int max_heal_xp =
20 + (sd->status.base_level * sd->status.base_level);
-
sd->heal_xp += base_exp;
if (sd->heal_xp > max_heal_xp)
sd->heal_xp = max_heal_xp;
@@ -2884,6 +2893,12 @@ int pc_gainexp_reason(dumb_ptr<map_session_data> sd, int base_exp, int job_exp,
}
}
+ // Double Xp Weekends
+ job_exp = (job_exp * static_cast<double>(battle_config.job_exp_rate) / 100.);
+ if (job_exp <= 0)
+ job_exp = 0;
+ else if (job_exp > 1000000000)
+ job_exp = 1000000000;
sd->status.job_exp += job_exp;
if (sd->status.job_exp < 0)
sd->status.job_exp = 0;
@@ -3480,8 +3495,7 @@ int pc_setparam(dumb_ptr<map_session_data> sd, SP type, int val)
}
break;
case SP::SEX:
- // this is a really bad idea
- sd->sex = static_cast<SEX>(val);
+ chrif_char_ask_name(AccountId(), sd->status_key.name, 5, HumanTimeDiff());
break;
case SP::WEIGHT:
sd->weight = val;
@@ -3507,7 +3521,7 @@ int pc_setparam(dumb_ptr<map_session_data> sd, SP type, int val)
case SP::INT:
case SP::DEX:
case SP::LUK:
- sd->status.attrs[sp_to_attr(type)] = val;
+ pc_statusup2(sd, type, (val - sd->status.attrs[sp_to_attr(type)]));
break;
}
clif_updatestatus(sd, type);
@@ -3787,14 +3801,37 @@ void pc_setregstr(dumb_ptr<map_session_data> sd, SIR reg, RString str)
int pc_readglobalreg(dumb_ptr<map_session_data> sd, VarName reg)
{
int i;
-
+ int quest_shift = 0;
+ int quest_mask = 0;
nullpo_retz(sd);
+ QuestId questid;
+ XString var = reg;
+ VarName vr;
assert (sd->status.global_reg_num < GLOBAL_REG_NUM);
+ Option<P<struct quest_data>> quest_data_ = questdb_searchname(var);
+ OMATCH_BEGIN_SOME(quest_data, quest_data_)
+ {
+ questid = quest_data->questid;
+ reg = quest_data->quest_vr;
+ vr = quest_data->quest_var;
+ quest_shift = quest_data->quest_shift;
+ quest_mask = quest_data->quest_mask;
+ }
+ OMATCH_END ();
for (i = 0; i < sd->status.global_reg_num; i++)
{
if (sd->status.global_reg[i].str == reg)
- return sd->status.global_reg[i].value;
+ {
+ if (questid)
+ {
+ return ((sd->status.global_reg[i].value & (((1 << quest_mask) - 1) << (quest_shift * quest_mask))) >> (quest_shift * quest_mask));
+ }
+ else
+ {
+ return sd->status.global_reg[i].value;
+ }
+ }
}
return 0;
@@ -3807,8 +3844,13 @@ int pc_readglobalreg(dumb_ptr<map_session_data> sd, VarName reg)
int pc_setglobalreg(dumb_ptr<map_session_data> sd, VarName reg, int val)
{
int i;
-
+ int quest_shift = 0;
+ int quest_mask = 0;
+ int bitval = val;
nullpo_retz(sd);
+ QuestId questid;
+ XString var = reg;
+ VarName vr;
//PC_DIE_COUNTERがスクリプトなどで変更された時の処理
if (reg == stringish<VarName>("PC_DIE_COUNTER"_s) && sd->die_counter != val)
@@ -3816,6 +3858,17 @@ int pc_setglobalreg(dumb_ptr<map_session_data> sd, VarName reg, int val)
sd->die_counter = val;
pc_calcstatus(sd, 0);
}
+ Option<P<struct quest_data>> quest_data_ = questdb_searchname(var);
+ OMATCH_BEGIN_SOME(quest_data, quest_data_)
+ {
+ questid = quest_data->questid;
+ reg = quest_data->quest_vr;
+ vr = quest_data->quest_var;
+ quest_shift = quest_data->quest_shift;
+ quest_mask = quest_data->quest_mask;
+ assert (((1 << quest_mask) - 1) >= val);
+ }
+ OMATCH_END ();
assert (sd->status.global_reg_num < GLOBAL_REG_NUM);
if (val == 0)
{
@@ -3823,9 +3876,18 @@ int pc_setglobalreg(dumb_ptr<map_session_data> sd, VarName reg, int val)
{
if (sd->status.global_reg[i].str == reg)
{
- sd->status.global_reg[i] =
- sd->status.global_reg[sd->status.global_reg_num - 1];
- sd->status.global_reg_num--;
+ if (questid)
+ {
+ bitval = ((sd->status.global_reg[i].value & ~(((1 << quest_mask) - 1) << (quest_shift * quest_mask))) | (val << (quest_shift * quest_mask)));
+ clif_sendquest(sd, questid, val);
+ }
+ sd->status.global_reg[i].value = bitval;
+ if (sd->status.global_reg[i].value == 0)
+ {
+ sd->status.global_reg[i] =
+ sd->status.global_reg[sd->status.global_reg_num - 1];
+ sd->status.global_reg_num--;
+ }
break;
}
}
@@ -3835,14 +3897,24 @@ int pc_setglobalreg(dumb_ptr<map_session_data> sd, VarName reg, int val)
{
if (sd->status.global_reg[i].str == reg)
{
- sd->status.global_reg[i].value = val;
+ if (questid)
+ {
+ bitval = ((sd->status.global_reg[i].value & ~(((1 << quest_mask) - 1) << (quest_shift * quest_mask))) | (val << (quest_shift * quest_mask)));
+ clif_sendquest(sd, questid, val);
+ }
+ sd->status.global_reg[i].value = bitval;
return 0;
}
}
if (sd->status.global_reg_num < GLOBAL_REG_NUM)
{
sd->status.global_reg[i].str = reg;
- sd->status.global_reg[i].value = val;
+ if (questid)
+ {
+ bitval = ((sd->status.global_reg[i].value & ~(((1 << quest_mask) - 1) << (quest_shift * quest_mask))) | (val << (quest_shift * quest_mask)));
+ clif_sendquest(sd, questid, val);
+ }
+ sd->status.global_reg[i].value = bitval;
sd->status.global_reg_num++;
return 0;
}
diff --git a/src/map/pc.hpp b/src/map/pc.hpp
index 6879f79..d100938 100644
--- a/src/map/pc.hpp
+++ b/src/map/pc.hpp
@@ -28,6 +28,7 @@
#include "../mmo/clif.t.hpp"
#include "map.hpp"
+#include "quest.hpp"
namespace tmwa
@@ -145,6 +146,8 @@ int pc_readreg(dumb_ptr<map_session_data>, SIR);
void pc_setreg(dumb_ptr<map_session_data>, SIR, int);
ZString pc_readregstr(dumb_ptr<map_session_data> sd, SIR reg);
void pc_setregstr(dumb_ptr<map_session_data> sd, SIR reg, RString str);
+void update_quest(dumb_ptr<map_session_data> sd, VarName quest_var, int value);
+void update_allquest(dumb_ptr<map_session_data> sd);
int pc_readglobalreg(dumb_ptr<map_session_data>, VarName );
int pc_setglobalreg(dumb_ptr<map_session_data>, VarName , int);
int pc_readaccountreg(dumb_ptr<map_session_data>, VarName );
diff --git a/src/map/quest.cpp b/src/map/quest.cpp
new file mode 100644
index 0000000..dfe19ff
--- /dev/null
+++ b/src/map/quest.cpp
@@ -0,0 +1,135 @@
+#include "quest.hpp"
+// quest.cpp - Quest Log.
+//
+// Copyright © 2015 Ed Pasek <pasekei@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program 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/>.
+
+#include <algorithm>
+
+#include "../strings/astring.hpp"
+#include "../strings/zstring.hpp"
+#include "../strings/xstring.hpp"
+
+#include "../generic/db.hpp"
+
+#include "../io/cxxstdio.hpp"
+#include "../io/extract.hpp"
+#include "../io/line.hpp"
+
+#include "../mmo/config_parse.hpp"
+#include "../mmo/extract_enums.hpp"
+
+#include "../ast/quest.hpp"
+
+#include "../poison.hpp"
+#include "globals.hpp"
+#include "script-parse.hpp"
+
+namespace tmwa
+{
+namespace map
+{
+// Function declarations
+
+static
+void questdb_searchname_sub(Borrowed<struct quest_data> quest, VarName str, Borrowed<Option<Borrowed<struct quest_data>>> dst)
+{
+ if (quest->quest_var == str)
+ *dst = Some(quest);
+}
+
+Option<Borrowed<struct quest_data>> questdb_searchname(XString str_)
+{
+ VarName str = stringish<VarName>(str_);
+ if (XString(str) != str_)
+ return None;
+ Option<P<struct quest_data>> quest = None;
+ for (auto& pair : quest_db)
+ questdb_searchname_sub(borrow(pair.second), str, borrow(quest));
+ return quest;
+}
+
+Borrowed<struct quest_data> questdb_search(QuestId questid)
+{
+ Option<P<struct quest_data>> id_ = quest_db.search(questid);
+ OMATCH_BEGIN_SOME (id, id_)
+ {
+ return id;
+ }
+ OMATCH_END ();
+
+ P<struct quest_data> id = quest_db.init(questid);
+
+ id->questid = questid;
+
+ return id;
+}
+
+Option<Borrowed<struct quest_data>> questdb_exists(QuestId questid)
+{
+ return quest_db.search(questid);
+}
+
+bool quest_readdb(ZString filename)
+{
+ io::LineCharReader in(filename);
+
+ if (!in.is_open())
+ {
+ PRINTF("can't read %s\n"_fmt, filename);
+ return false;
+ }
+
+ int ln = 0;
+
+ while (true)
+ {
+ auto res = TRY_UNWRAP(ast::quest::parse_quest(in),
+ {
+ PRINTF("read %s done (count=%d)\n"_fmt, filename, ln);
+ return true;
+ });
+ if (res.get_failure())
+ PRINTF("%s\n"_fmt, res.get_failure());
+ ast::quest::QuestOrComment ioc = TRY_UNWRAP(std::move(res.get_success()), return false);
+
+ MATCH_BEGIN (ioc)
+ {
+ MATCH_CASE (const ast::quest::Comment&, c)
+ {
+ (void)c;
+ }
+ MATCH_CASE (const ast::quest::Quest&, quest)
+ {
+ ln++;
+
+ quest_data qdv {};
+ qdv.questid = quest.questid.data;
+ qdv.quest_var = quest.quest_var.data;
+ qdv.quest_vr = quest.quest_vr.data;
+ qdv.quest_shift = quest.quest_shift.data;
+ qdv.quest_mask = quest.quest_mask.data;
+
+ Borrowed<struct quest_data> id = questdb_search(qdv.questid);
+ *id = std::move(qdv);
+ }
+ }
+ MATCH_END ();
+ }
+}
+} // namespace map
+} // namespace tmwa
diff --git a/src/map/quest.hpp b/src/map/quest.hpp
new file mode 100644
index 0000000..65e6f4e
--- /dev/null
+++ b/src/map/quest.hpp
@@ -0,0 +1,51 @@
+#pragma once
+// quest.hpp - Quest Log.
+//
+// Copyright © 2015 Ed Pasek <pasekei@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program 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/>.
+
+#include "fwd.hpp"
+
+#include "../mmo/ids.hpp"
+#include "../high/mmo.hpp"
+
+#include "map.hpp"
+#include "script-buffer.hpp"
+
+namespace tmwa
+{
+namespace map
+{
+constexpr int MAX_QUEST_DB (60355+1);
+struct quest_data
+{
+ QuestId questid;
+ VarName quest_var;
+ VarName quest_vr;
+ int quest_shift;
+ int quest_mask;
+};
+inline
+Option<Borrowed<struct quest_data>> questdb_searchname(VarName) = delete;
+Option<Borrowed<struct quest_data>> questdb_searchname(XString quest_var);
+Borrowed<struct quest_data> questdb_search(QuestId questid);
+Option<Borrowed<struct quest_data>> questdb_exists(QuestId questid);
+
+// get quest var by quest name / mask / bit
+bool quest_readdb(ZString filename);
+} // namespace map
+} // namespace tmwa
diff --git a/src/map/script-call.cpp b/src/map/script-call.cpp
index f412328..c3c6aa1 100644
--- a/src/map/script-call.cpp
+++ b/src/map/script-call.cpp
@@ -757,7 +757,7 @@ void run_script_main(ScriptState *st, Borrowed<const ScriptBuffer> rootscript)
{
rerun_pos = st->scriptp.pos;
st->state = ScriptEndState::ZERO;
- if (!st->freeloop && gotocount > 0 && (--gotocount) <= 0)
+ if (st->freeloop != 1 && gotocount > 0 && (--gotocount) <= 0)
{
PRINTF("run_script: infinity loop !\n"_fmt);
st->state = ScriptEndState::END;
@@ -806,7 +806,7 @@ void run_script_main(ScriptState *st, Borrowed<const ScriptBuffer> rootscript)
st->state = ScriptEndState::END;
break;
}
- if (!st->freeloop && cmdcount > 0 && (--cmdcount) <= 0)
+ if (st->freeloop != 1 && cmdcount > 0 && (--cmdcount) <= 0)
{
PRINTF("run_script: infinity loop !\n"_fmt);
st->state = ScriptEndState::END;
diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp
index c327f26..3291cfc 100644
--- a/src/map/script-fun.cpp
+++ b/src/map/script-fun.cpp
@@ -108,7 +108,7 @@ void builtin_goto(ScriptState *st)
{
if (!AARG(0).is<ScriptDataPos>())
{
- PRINTF("script: goto: not label !\n"_fmt);
+ PRINTF("script: goto: that's not a label!\n"_fmt);
st->state = ScriptEndState::END;
return;
}
@@ -149,7 +149,7 @@ void builtin_callfunc(ScriptState *st)
}
OMATCH_CASE_NONE ()
{
- PRINTF("script:callfunc: function not found! [%s]\n"_fmt, str);
+ PRINTF("script: callfunc: function not found! [%s]\n"_fmt, str);
st->state = ScriptEndState::END;
}
}
@@ -538,7 +538,7 @@ void builtin_setarray(ScriptState *st)
if (prefix != '$' && prefix != '@')
{
- PRINTF("builtin_setarray: illegal scope !\n"_fmt);
+ PRINTF("builtin_setarray: illegal scope!\n"_fmt);
return;
}
if (prefix != '$')
@@ -569,7 +569,7 @@ void builtin_cleararray(ScriptState *st)
if (prefix != '$' && prefix != '@')
{
- PRINTF("builtin_cleararray: illegal scope !\n"_fmt);
+ PRINTF("builtin_cleararray: illegal scope!\n"_fmt);
return;
}
if (prefix != '$')
@@ -626,7 +626,7 @@ void builtin_getarraysize(ScriptState *st)
if (prefix != '$' && prefix != '@')
{
- PRINTF("builtin_copyarray: illegal scope !\n"_fmt);
+ PRINTF("builtin_copyarray: illegal scope!\n"_fmt);
return;
}
@@ -645,7 +645,7 @@ void builtin_getelementofarray(ScriptState *st)
int i = conv_num(st, &AARG(1));
if (i > 255 || i < 0)
{
- PRINTF("script: getelementofarray (operator[]): param2 illegal number %d\n"_fmt,
+ PRINTF("script: getelementofarray (operator[]): param2 illegal number: %d\n"_fmt,
i);
push_int<ScriptDataInt>(st->stack, 0);
}
@@ -657,11 +657,29 @@ void builtin_getelementofarray(ScriptState *st)
}
else
{
- PRINTF("script: getelementofarray (operator[]): param1 not name !\n"_fmt);
+ PRINTF("script: getelementofarray (operator[]): param1 not named!\n"_fmt);
push_int<ScriptDataInt>(st->stack, 0);
}
}
+static
+void builtin_wgm(ScriptState *st)
+{
+ ZString message = ZString(conv_str(st, &AARG(0)));
+
+ intif_wis_message_to_gm(WISP_SERVER_NAME,
+ battle_config.hack_info_GM_level,
+ STRPRINTF("[GM] %s"_fmt, message));
+}
+
+static
+void builtin_gmlog(ScriptState *st)
+{
+ dumb_ptr<map_session_data> sd = script_rid2sd(st);
+ ZString message = ZString(conv_str(st, &AARG(0)));
+ log_atcommand(sd, STRPRINTF("{SCRIPT} %s"_fmt, message));
+}
+
/*==========================================
*
*------------------------------------------
@@ -717,7 +735,7 @@ void builtin_countitem(ScriptState *st)
else
{
if (battle_config.error_log)
- PRINTF("wrong item ID : countitem (%i)\n"_fmt, nameid);
+ PRINTF("wrong item ID: countitem (%i)\n"_fmt, nameid);
}
push_int<ScriptDataInt>(st->stack, count);
@@ -755,7 +773,7 @@ void builtin_checkweight(ScriptState *st)
amount = conv_num(st, &AARG(1));
if (amount <= 0 || !nameid)
{
- //if get wrong item ID or amount<=0, don't count weight of non existing items
+ //If it gets the wrong item ID or the amount<=0, don't count its weight (assume it's a non-existent item)
push_int<ScriptDataInt>(st->stack, 0);
return;
}
@@ -907,7 +925,7 @@ void builtin_delitem(ScriptState *st)
if (!nameid || amount <= 0)
{
- //by Lupus. Don't run FOR if u got wrong item ID or amount<=0
+ //By Lupus. Don't run FOR if you've got the wrong item ID or amount<=0
return;
}
@@ -934,31 +952,6 @@ void builtin_delitem(ScriptState *st)
}
/*==========================================
- *キャラ関係のパラメータ取得
- *------------------------------------------
- */
-static
-void builtin_readparam(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd;
-
- SP type = SP(conv_num(st, &AARG(0)));
- if (HARG(1))
- sd = map_nick2sd(stringish<CharName>(ZString(conv_str(st, &AARG(1)))));
- else
- sd = script_rid2sd(st);
-
- if (sd == nullptr)
- {
- push_int<ScriptDataInt>(st->stack, -1);
- return;
- }
-
- push_int<ScriptDataInt>(st->stack, pc_readparam(sd, type));
-
-}
-
-/*==========================================
*キャラ関係のID取得
*------------------------------------------
*/
@@ -1150,20 +1143,6 @@ void builtin_getequipname(ScriptState *st)
}
/*==========================================
- *
- *------------------------------------------
- */
-static
-void builtin_statusup2(ScriptState *st)
-{
- SP type = SP(conv_num(st, &AARG(0)));
- int val = conv_num(st, &AARG(1));
- dumb_ptr<map_session_data> sd = script_rid2sd(st);
- pc_statusup2(sd, type, val);
-
-}
-
-/*==========================================
* 装備品による能力値ボーナス
*------------------------------------------
*/
@@ -1955,7 +1934,7 @@ static
void builtin_debugmes(ScriptState *st)
{
RString mes = conv_str(st, &AARG(0));
- PRINTF("script debug : %d %d : %s\n"_fmt,
+ PRINTF("script debug: %d %d: '%s'\n"_fmt,
st->rid, st->oid, mes);
}
@@ -1972,20 +1951,6 @@ void builtin_resetstatus(ScriptState *st)
}
/*==========================================
- * 性別変換
- *------------------------------------------
- */
-static
-void builtin_changesex(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd = nullptr;
- sd = script_rid2sd(st);
-
- chrif_char_ask_name(AccountId(), sd->status_key.name, 5, HumanTimeDiff()); // type: 5 - changesex
- chrif_save(sd);
-}
-
-/*==========================================
* RIDのアタッチ
*------------------------------------------
*/
@@ -2164,11 +2129,22 @@ void builtin_getpvpflag(ScriptState *st)
static
void builtin_emotion(ScriptState *st)
{
- int type;
- type = conv_num(st, &AARG(0));
+ ZString str;
+ dumb_ptr<map_session_data> pl_sd = nullptr;
+ int type = conv_num(st, &AARG(0));
+ if (HARG(1)) {
+ str = ZString(conv_str(st, &AARG(1)));
+ CharName player = stringish<CharName>(str);
+ pl_sd = map_nick2sd(player);
+ }
if (type < 0 || type > 200)
return;
- clif_emotion(map_id2bl(st->oid), type);
+ if (pl_sd != nullptr)
+ clif_emotion_towards(map_id2bl(st->oid), pl_sd, type);
+ else if (st->rid && str == "self"_s)
+ clif_emotion(map_id2sd(st->rid), type);
+ else
+ clif_emotion(map_id2bl(st->oid), type);
}
static
@@ -2296,11 +2272,11 @@ void builtin_getitemlink(ScriptState *st)
{
OMATCH_CASE_SOME (item_data)
{
- buf = STRPRINTF("[@@%d|%s@@]"_fmt, item_data->nameid, item_data->jname);
+ buf = STRPRINTF("@@%d|@@"_fmt, item_data->nameid);
}
OMATCH_CASE_NONE ()
{
- buf = STRPRINTF("Unknown Item: %s"_fmt, name);
+ buf = "Unknown Item"_s;
}
}
OMATCH_END ();
@@ -2577,25 +2553,6 @@ void builtin_unequipbyid(ScriptState *st)
}
/*==========================================
- * gmcommand [MouseJstr]
- *
- * suggested on the forums...
- *------------------------------------------
- */
-
-static
-void builtin_gmcommand(ScriptState *st)
-{
- dumb_ptr<map_session_data> sd;
-
- sd = script_rid2sd(st);
- RString cmd = conv_str(st, &AARG(0));
-
- is_atcommand(sd->sess, sd, cmd, GmLevel::from(-1U));
-
-}
-
-/*==========================================
* npcwarp [remoitnane]
* Move NPC to a new position on the same map.
*------------------------------------------
@@ -2613,7 +2570,7 @@ void builtin_npcwarp(ScriptState *st)
if (!nd)
{
- PRINTF("builtin_npcwarp: no such npc: %s\n"_fmt, npc);
+ PRINTF("builtin_npcwarp: no such npc: '%s'\n"_fmt, npc);
return;
}
@@ -2656,7 +2613,7 @@ void builtin_npcareawarp(ScriptState *st)
if (!nd)
{
- PRINTF("builtin_npcareawarp: no such npc: %s\n"_fmt, npc);
+ PRINTF("builtin_npcareawarp: no such npc: '%s'\n"_fmt, npc);
return;
}
@@ -2901,7 +2858,7 @@ void builtin_shop(ScriptState *st)
nd = npc_name2id(name);
if (!nd)
{
- PRINTF("builtin_shop: no such npc: %s\n"_fmt, name);
+ PRINTF("builtin_shop: no such npc: '%s'\n"_fmt, name);
return;
}
@@ -2934,7 +2891,7 @@ void builtin_fakenpcname(ScriptState *st)
dumb_ptr<npc_data> nd = npc_name2id(name);
if (!nd)
{
- PRINTF("builtin_fakenpcname: no such npc: %s\n"_fmt, name);
+ PRINTF("builtin_fakenpcname: no such npc: '%s'\n"_fmt, name);
return;
}
nd->name = newname;
@@ -2996,7 +2953,7 @@ void builtin_strnpcinfo(ScriptState *st)
nd = npc_name2id(npc);
if (!nd)
{
- PRINTF("builtin_strnpcinfo: no such npc: %s\n"_fmt, npc);
+ PRINTF("builtin_strnpcinfo: no such npc: '%s'\n"_fmt, npc);
return;
}
} else {
@@ -3036,7 +2993,7 @@ void builtin_getnpcx(ScriptState *st)
nd = npc_name2id(name);
if (!nd)
{
- PRINTF("builtin_getnpcx: no such npc: %s\n"_fmt, name);
+ PRINTF("builtin_getnpcx: no such npc: '%s'\n"_fmt, name);
return;
}
} else {
@@ -3060,7 +3017,7 @@ void builtin_getnpcy(ScriptState *st)
nd = npc_name2id(name);
if (!nd)
{
- PRINTF("builtin_getnpcy: no such npc: %s\n"_fmt, name);
+ PRINTF("builtin_getnpcy: no such npc: '%s'\n"_fmt, name);
return;
}
} else {
@@ -3109,12 +3066,10 @@ BuiltinFunction builtin_functions[] =
BUILTIN(getitem, "Ii??"_s, '\0'),
BUILTIN(makeitem, "IiMxy"_s, '\0'),
BUILTIN(delitem, "Ii"_s, '\0'),
- BUILTIN(readparam, "i?"_s, 'i'),
BUILTIN(getcharid, "i?"_s, 'i'),
BUILTIN(strcharinfo, "i"_s, 's'),
BUILTIN(getequipid, "i"_s, 'i'),
BUILTIN(getequipname, "i"_s, 's'),
- BUILTIN(statusup2, "ii"_s, '\0'),
BUILTIN(bonus, "ii"_s, '\0'),
BUILTIN(bonus2, "iii"_s, '\0'),
BUILTIN(skill, "ii?"_s, '\0'),
@@ -3134,11 +3089,11 @@ BuiltinFunction builtin_functions[] =
BUILTIN(killmonster, "ME"_s, '\0'),
BUILTIN(donpcevent, "E"_s, '\0'),
BUILTIN(addtimer, "tE"_s, '\0'),
- BUILTIN(initnpctimer, ""_s, '\0'),
+ BUILTIN(initnpctimer, "?"_s, '\0'),
BUILTIN(startnpctimer, "?"_s, '\0'),
- BUILTIN(stopnpctimer, ""_s, '\0'),
- BUILTIN(getnpctimer, "i"_s, 'i'),
- BUILTIN(setnpctimer, "i"_s, '\0'),
+ BUILTIN(stopnpctimer, "?"_s, '\0'),
+ BUILTIN(getnpctimer, "i?"_s, 'i'),
+ BUILTIN(setnpctimer, "i?"_s, '\0'),
BUILTIN(announce, "si"_s, '\0'),
BUILTIN(mapannounce, "Msi"_s, '\0'),
BUILTIN(getusers, "i"_s, 'i'),
@@ -3151,8 +3106,9 @@ BuiltinFunction builtin_functions[] =
BUILTIN(sc_end, "i"_s, '\0'),
BUILTIN(sc_check, "i"_s, 'i'),
BUILTIN(debugmes, "s"_s, '\0'),
+ BUILTIN(wgm, "s"_s, '\0'),
+ BUILTIN(gmlog, "s"_s, '\0'),
BUILTIN(resetstatus, ""_s, '\0'),
- BUILTIN(changesex, ""_s, '\0'),
BUILTIN(attachrid, "i"_s, 'i'),
BUILTIN(detachrid, ""_s, '\0'),
BUILTIN(isloggedin, "i"_s, 'i'),
@@ -3163,7 +3119,7 @@ BuiltinFunction builtin_functions[] =
BUILTIN(pvpoff, "M"_s, '\0'),
BUILTIN(setpvpchannel, "i"_s, '\0'),
BUILTIN(getpvpflag, "i"_s, 'i'),
- BUILTIN(emotion, "i"_s, '\0'),
+ BUILTIN(emotion, "i?"_s, '\0'),
BUILTIN(mapwarp, "MMxy"_s, '\0'),
BUILTIN(mobcount, "ME"_s, 'i'),
BUILTIN(marriage, "P"_s, 'i'),
@@ -3182,7 +3138,6 @@ BuiltinFunction builtin_functions[] =
BUILTIN(specialeffect2, "i"_s, '\0'),
BUILTIN(nude, ""_s, '\0'),
BUILTIN(unequipbyid, "i"_s, '\0'),
- BUILTIN(gmcommand, "s"_s, '\0'),
BUILTIN(npcwarp, "xys"_s, '\0'),
BUILTIN(npcareawarp, "xyxyis"_s, '\0'),
BUILTIN(message, "Ps"_s, '\0'),