summaryrefslogtreecommitdiff
path: root/src/emap
diff options
context:
space:
mode:
Diffstat (limited to 'src/emap')
-rw-r--r--src/emap/atcommand.c84
-rw-r--r--src/emap/atcommand.h14
-rw-r--r--src/emap/clif.c377
-rw-r--r--src/emap/clif.h26
-rw-r--r--src/emap/data/itemd.c68
-rw-r--r--src/emap/data/itemd.h13
-rw-r--r--src/emap/data/mapd.c40
-rw-r--r--src/emap/data/mapd.h12
-rw-r--r--src/emap/data/npcd.c38
-rw-r--r--src/emap/data/npcd.h12
-rw-r--r--src/emap/data/session.c48
-rw-r--r--src/emap/data/session.h13
-rw-r--r--src/emap/init.c244
-rw-r--r--src/emap/itemdb.c91
-rw-r--r--src/emap/itemdb.h11
-rw-r--r--src/emap/lang.c234
-rw-r--r--src/emap/lang.h15
-rw-r--r--src/emap/mail.c36
-rw-r--r--src/emap/mail.h9
-rw-r--r--src/emap/map.c133
-rw-r--r--src/emap/map.h10
-rw-r--r--src/emap/mob.c48
-rw-r--r--src/emap/mob.h9
-rw-r--r--src/emap/npc.c127
-rw-r--r--src/emap/npc.h14
-rw-r--r--src/emap/parse.c220
-rw-r--r--src/emap/parse.h20
-rw-r--r--src/emap/pc.c309
-rw-r--r--src/emap/pc.h42
-rw-r--r--src/emap/permission.c18
-rw-r--r--src/emap/permission.h10
-rw-r--r--src/emap/quest.c132
-rw-r--r--src/emap/quest.h9
-rw-r--r--src/emap/script.c1148
-rw-r--r--src/emap/script.h46
-rw-r--r--src/emap/scriptdefines.h55
-rw-r--r--src/emap/send.c305
-rw-r--r--src/emap/send.h31
-rw-r--r--src/emap/skill.c44
-rw-r--r--src/emap/skill.h12
-rw-r--r--src/emap/status.c70
-rw-r--r--src/emap/status.h12
-rw-r--r--src/emap/struct/itemdext.h33
-rw-r--r--src/emap/struct/mapdext.h17
-rw-r--r--src/emap/struct/npcdext.h12
-rw-r--r--src/emap/struct/sessionext.h15
-rw-r--r--src/emap/unit.c163
-rw-r--r--src/emap/unit.h10
-rw-r--r--src/emap/utils/formatutils.c116
-rw-r--r--src/emap/utils/formatutils.h9
50 files changed, 4584 insertions, 0 deletions
diff --git a/src/emap/atcommand.c b/src/emap/atcommand.c
new file mode 100644
index 0000000..c697b22
--- /dev/null
+++ b/src/emap/atcommand.c
@@ -0,0 +1,84 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "common/timer.h"
+#include "map/atcommand.h"
+#include "map/clif.h"
+#include "map/map.h"
+#include "map/pc.h"
+#include "map/skill.h"
+#include "emap/atcommand.h"
+#include "emap/lang.h"
+
+const char* eatcommand_msgsd(struct map_session_data *sd, int *msgPtr)
+{
+ const int msg_number = *msgPtr;
+ if (!(msg_number >= 0 && msg_number < MAX_MSG))
+ {
+ hookStop();
+ return "??";
+ }
+ if (*msgPtr == 1435)
+ {
+ hookStop();
+ // service message, must be not translated
+ return "You're now in the '#%s' channel for '%s'";
+ }
+ else if (*msgPtr == 1403)
+ {
+ hookStop();
+ // service message, must be not translated
+ return "You're now in the '#%s' channel for '-'";
+ }
+ hookStop();
+ return lang_pctrans(atcommand->msg_table[0][msg_number], sd);
+}
+
+const char* eatcommand_msgfd(int *fdPtr, int *msgPtr)
+{
+ const int msg_number = *msgPtr;
+ const int fd = *fdPtr;
+ struct map_session_data *sd = session_isValid(fd) ? session[fd]->session_data : NULL;
+ if (!(msg_number >= 0 && msg_number < MAX_MSG))
+ {
+ hookStop();
+ return "??";
+ }
+ hookStop();
+ return lang_pctrans(atcommand->msg_table[0][msg_number], sd);
+}
+
+ACMD2(setSkill)
+{
+ int skill_id = 0;
+ int skill_level = 0;
+
+ if (!message || !*message || sscanf(message, "%5d %2d", &skill_id, &skill_level) < 2)
+ {
+ const char* text = info->help;
+
+ if (text)
+ clif->messageln (fd, text);
+
+ return false;
+ }
+ if (!skill->get_index(skill_id))
+ {
+ clif->message(fd, msg_fd(fd,198)); // This skill number doesn't exist.
+ return false;
+ }
+
+ pc->skill(sd, skill_id, skill_level, 0);
+ clif->message(fd, msg_fd(fd,70)); // You have learned the skill.
+
+ return true;
+}
diff --git a/src/emap/atcommand.h b/src/emap/atcommand.h
new file mode 100644
index 0000000..ab970c6
--- /dev/null
+++ b/src/emap/atcommand.h
@@ -0,0 +1,14 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_ATCOMMAND
+#define EVOL_MAP_ATCOMMAND
+
+const char* eatcommand_msgsd(struct map_session_data *sd, int *msgPtr);
+const char* eatcommand_msgfd(int *fdPtr, int *msgPtr);
+
+#define ACMD2(x) bool atcommand_ ## x (const int fd, struct map_session_data* sd, const char* command __attribute__ ((unused)), const char* message, struct AtCommandInfo *info)
+
+ACMD2(setSkill);
+
+#endif // EVOL_MAP_ATCOMMAND
diff --git a/src/emap/clif.c b/src/emap/clif.c
new file mode 100644
index 0000000..7651f09
--- /dev/null
+++ b/src/emap/clif.c
@@ -0,0 +1,377 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "common/cbasetypes.h"
+#include "map/guild.h"
+#include "map/mob.h"
+#include "map/npc.h"
+#include "map/pc.h"
+#include "map/quest.h"
+
+#include "emap/clif.h"
+#include "emap/lang.h"
+#include "emap/send.h"
+#include "emap/data/mapd.h"
+#include "emap/data/session.h"
+#include "emap/struct/mapdext.h"
+#include "emap/struct/sessionext.h"
+
+void eclif_quest_send_list(TBL_PC *sd)
+{
+ if (!sd)
+ {
+ hookStop();
+ return;
+ }
+
+ int fd = sd->fd;
+ int i;
+ int info_len = 15;
+ int len = sd->avail_quests * info_len + 8;
+ WFIFOHEAD(fd,len);
+ WFIFOW(fd, 0) = 0x97a;
+ WFIFOW(fd, 2) = len;
+ WFIFOL(fd, 4) = sd->avail_quests;
+
+ for (i = 0; i < sd->avail_quests; i++ )
+ {
+ struct quest_db *qi = quest->db(sd->quest_log[i].quest_id);
+ if (!qi)
+ continue;
+ WFIFOL(fd, i * info_len + 8) = sd->quest_log[i].quest_id;
+ WFIFOB(fd, i * info_len + 12) = sd->quest_log[i].count[0]; // was state
+ WFIFOL(fd, i * info_len + 13) = sd->quest_log[i].time - qi->time;
+ WFIFOL(fd, i * info_len + 17) = sd->quest_log[i].time;
+ WFIFOW(fd, i * info_len + 21) = 0;
+ }
+
+ WFIFOSET(fd, len);
+ hookStop();
+}
+
+void eclif_quest_add(TBL_PC *sd, struct quest *qd)
+{
+ if (!sd)
+ {
+ hookStop();
+ return;
+ }
+ int fd = sd->fd;
+ struct quest_db *qi = quest->db(qd->quest_id);
+
+ if (!qi)
+ {
+ hookStop();
+ return;
+ }
+
+ WFIFOHEAD(fd, 107);
+ WFIFOW(fd, 0) = 0x2b3;
+ WFIFOL(fd, 2) = qd->quest_id;
+ WFIFOB(fd, 6) = qd->count[0]; // was state;
+ WFIFOB(fd, 7) = qd->time - qi->time;
+ WFIFOL(fd, 11) = qd->time;
+ WFIFOW(fd, 15) = 0;
+ WFIFOSET(fd, 107);
+ hookStop();
+}
+
+void eclif_charnameack(int *fdPtr, struct block_list *bl)
+{
+ if (!bl)
+ {
+ hookStop();
+ return;
+ }
+ if (bl->type == BL_NPC)
+ {
+ int fd = *fdPtr;
+ TBL_PC* sd = (TBL_PC*)session[fd]->session_data;
+ if (!sd)
+ {
+ hookStop();
+ return;
+ }
+ const char *tr = lang_pctrans(((TBL_NPC*)bl)->name, sd);
+ const int trLen = strlen(tr);
+ const int len = 8 + trLen;
+ // if no recipient specified just update nearby clients
+ if (fd == 0)
+ {
+ char *buf;
+ CREATE(buf, char, len);
+ WBUFW(buf, 0) = 0xB01;
+ WBUFW(buf, 2) = len;
+ WBUFL(buf, 4) = bl->id;
+ memcpy(WBUFP(buf, 8), tr, trLen);
+ clif->send(buf, len, bl, AREA);
+ aFree(buf);
+ }
+ else
+ {
+ WFIFOHEAD(fd, len);
+ WFIFOW(fd, 0) = 0xB01;
+ WFIFOW(fd, 2) = len;
+ WFIFOL(fd, 4) = bl->id;
+ memcpy(WFIFOP(fd, 8), tr, trLen);
+ WFIFOSET(fd, len);
+ }
+ hookStop();
+ }
+ else if (bl->type == BL_MOB)
+ {
+ struct mob_data *md = (struct mob_data *)bl;
+ if (!md)
+ {
+ hookStop();
+ return;
+ }
+ if (md->guardian_data && md->guardian_data->g)
+ return; // allow default code to work
+ int fd = *fdPtr;
+ TBL_PC* sd = (TBL_PC*)session[fd]->session_data;
+ if (!sd)
+ {
+ hookStop();
+ return;
+ }
+
+ char tmpBuf[25];
+ char *ptr = tmpBuf;
+ int f;
+ memcpy(tmpBuf, md->name, 24);
+ tmpBuf[24] = 0;
+ for (f = 23; f > 1; f --)
+ {
+ if (tmpBuf[f] == ' ')
+ tmpBuf[f] = 0;
+ else
+ break;
+ }
+ for (f = 0; f < 24; f ++)
+ {
+ if (*ptr == ' ')
+ ptr ++;
+ else
+ break;
+ }
+ const char *tr = lang_pctrans(ptr, sd);
+ const int trLen = strlen(tr);
+ const int len = 8 + trLen;
+
+ // if no recipient specified just update nearby clients
+ if (fd == 0)
+ {
+ char *buf;
+ CREATE(buf, char, len);
+ WBUFW(buf, 0) = 0xB01;
+ WBUFW(buf, 2) = len;
+ WBUFL(buf, 4) = bl->id;
+ memcpy(WBUFP(buf, 8), tr, trLen);
+ clif->send(buf, len, bl, AREA);
+ aFree(buf);
+ }
+ else
+ {
+ WFIFOHEAD(fd, len);
+ WFIFOW(fd, 0) = 0xB01;
+ WFIFOW(fd, 2) = len;
+ WFIFOL(fd, 4) = bl->id;
+ memcpy(WFIFOP(fd, 8), tr, trLen);
+ WFIFOSET(fd, len);
+ }
+ hookStop();
+ }
+}
+
+#define equipPos(index, field) \
+ equip = sd->equip_index[index]; \
+ if (equip >= 0) \
+ { \
+ item = sd->inventory_data[equip]; \
+ if (item && item->look) \
+ send_changelook(fd, id, field, item->look); \
+ }
+
+static void eclif_send_additional_slots(TBL_PC* sd, TBL_PC* sd2)
+{
+ if (!sd || !sd2)
+ return;
+
+ const int id = sd->bl.id;
+ const int fd = sd2->fd;
+
+ struct item_data *item;
+ short equip;
+ struct MapdExt *data = mapd_get(sd->bl.m);
+ if (!data || data->invisible)
+ return;
+
+ equipPos(EQI_HEAD_LOW, LOOK_HEAD_BOTTOM);
+ equipPos(EQI_HEAD_TOP, LOOK_HEAD_TOP);
+ equipPos(EQI_HEAD_MID, LOOK_HEAD_MID);
+ equipPos(EQI_GARMENT, LOOK_ROBE);
+ equipPos(EQI_SHOES, LOOK_SHOES);
+ equipPos(EQI_COSTUME_TOP, 13);
+ equipPos(EQI_COSTUME_MID, 14);
+ equipPos(EQI_COSTUME_LOW, 15);
+ equipPos(EQI_COSTUME_GARMENT, 16);
+ equipPos(EQI_ARMOR, 17);
+ //skipping SHADOW slots
+}
+
+void eclif_getareachar_unit_post(TBL_PC* sd, struct block_list *bl)
+{
+ if (!bl)
+ return;
+ if (bl->type == BL_PC)
+ {
+ eclif_send_additional_slots(sd, (TBL_PC *)bl);
+ eclif_send_additional_slots((TBL_PC *)bl, sd);
+ }
+}
+
+void eclif_authok_post(TBL_PC *sd)
+{
+ if (!sd)
+ return;
+
+ eclif_send_additional_slots(sd, sd);
+ send_pc_info(&sd->bl, &sd->bl, SELF);
+ struct MapdExt *data = mapd_get(sd->bl.m);
+ int mask = data ? data->mask : 1;
+ send_mapmask(sd->fd, mask);
+}
+
+void eclif_changemap_post(TBL_PC *sd, short *m,
+ int *x __attribute__ ((unused)), int *y __attribute__ ((unused)))
+{
+ if (!sd)
+ return;
+ struct MapdExt *data = mapd_get(*m);
+ int mask = data ? data->mask : 1;
+ send_mapmask(sd->fd, mask);
+}
+
+void eclif_handle_invisible_map(struct block_list *bl, enum send_target target __attribute__ ((unused)))
+{
+ if (!bl || bl->type != BL_PC)
+ return;
+ struct MapdExt *data = mapd_get(bl->m);
+ if (data && data->invisible)
+ hookStop();
+}
+
+void eclif_sendlook(struct block_list *bl,
+ int *id __attribute__ ((unused)),
+ int *type __attribute__ ((unused)),
+ int *val __attribute__ ((unused)),
+ int *val2 __attribute__ ((unused)),
+ enum send_target *target)
+{
+ if (*target == SELF)
+ return;
+ eclif_handle_invisible_map(bl, *target);
+}
+
+bool eclif_send(const void* buf __attribute__ ((unused)),
+ int *len __attribute__ ((unused)),
+ struct block_list* bl,
+ enum send_target *type)
+{
+ if (*type == SELF)
+ return true;
+ eclif_handle_invisible_map(bl, *type);
+ return true;
+}
+
+void eclif_set_unit_idle(struct block_list* bl, TBL_PC *tsd, enum send_target *target)
+{
+ if (tsd && bl && bl->id == tsd->bl.id && *target == SELF)
+ return;
+
+ eclif_handle_invisible_map(bl, *target);
+}
+
+int eclif_send_actual(int *fd, void *buf, int *len)
+{
+ if (*len >= 2)
+ {
+ const int packet = RBUFW (buf, 0);
+ if (packet >= 0xb02 && packet <= 0xb10)
+ {
+ struct SessionExt *data = session_get(*fd);
+ if (!data)
+ return 0;
+ if (data->clientVersion < 3)
+ { // not sending new packets to old clients
+// ShowWarning("skip packet %d\n", packet);
+ hookStop();
+ return 0;
+ }
+ }
+ if (packet >= 0xb03 && packet <= 0xb0a)
+ {
+ struct SessionExt *data = session_get(*fd);
+ if (!data)
+ return 0;
+ if (data->clientVersion < 4)
+ { // not sending new packets to old clients
+// ShowWarning("skip packet %d\n", packet);
+ hookStop();
+ return 0;
+ }
+ }
+ if (packet == 0xb0b)
+ {
+ struct SessionExt *data = session_get(*fd);
+ if (!data)
+ return 0;
+ if (data->clientVersion < 5)
+ { // not sending new packets to old clients
+// ShowWarning("skip packet %d\n", packet);
+ hookStop();
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+void eclif_set_unit_idle_post(struct block_list* bl, TBL_PC *tsd,
+ enum send_target *target)
+{
+ if (!bl || !tsd)
+ return;
+
+ if (bl->type == BL_MOB)
+ send_mob_info(bl, &tsd->bl, *target);
+ else if (bl->type == BL_PC)
+ send_pc_info(bl, &tsd->bl, *target);
+ else if (bl->type == BL_NPC)
+ send_npc_info(bl, &tsd->bl, *target);
+}
+
+void eclif_set_unit_walking(struct block_list* bl, TBL_PC *tsd,
+ struct unit_data* ud, enum send_target *target)
+{
+ TBL_PC *sd = BL_CAST(BL_PC, ud->bl);
+ if (!sd || !pc_isinvisible(sd))
+ send_advmoving(ud, tsd ? &tsd->bl : bl, *target);
+}
+
+void eclif_move(struct unit_data *ud)
+{
+ TBL_PC *sd = BL_CAST(BL_PC, ud->bl);
+ if (!sd || !pc_isinvisible(sd))
+ send_advmoving(ud, ud->bl, AREA_WOS);
+}
diff --git a/src/emap/clif.h b/src/emap/clif.h
new file mode 100644
index 0000000..5fd155b
--- /dev/null
+++ b/src/emap/clif.h
@@ -0,0 +1,26 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_CLIF
+#define EVOL_MAP_CLIF
+
+void eclif_quest_send_list(TBL_PC *sd);
+void eclif_quest_add(TBL_PC *sd, struct quest *qd);
+void eclif_charnameack(int *fdPtr, struct block_list *bl);
+void eclif_getareachar_unit_post(TBL_PC* sd, struct block_list *bl);
+void eclif_sendlook(struct block_list *bl, int *id, int *type,
+ int *val, int *val2, enum send_target *target);
+bool eclif_send(const void* buf, int *len, struct block_list* bl, enum send_target *type);
+void eclif_set_unit_idle(struct block_list* bl, TBL_PC *tsd,
+ enum send_target *target);
+int eclif_send_actual(int *fd, void *buf, int *len);
+
+void eclif_authok_post(TBL_PC *sd);
+void eclif_changemap_post(TBL_PC *sd, short *m, int *x, int *y);
+void eclif_set_unit_idle_post(struct block_list* bl, TBL_PC *tsd,
+ enum send_target *target);
+void eclif_set_unit_walking(struct block_list* bl, TBL_PC *tsd,
+ struct unit_data* ud, enum send_target *target);
+void eclif_move(struct unit_data *ud);
+
+#endif // EVOL_MAP_CLIF
diff --git a/src/emap/data/itemd.c b/src/emap/data/itemd.c
new file mode 100644
index 0000000..4b171b2
--- /dev/null
+++ b/src/emap/data/itemd.c
@@ -0,0 +1,68 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "map/battle.h"
+#include "map/itemdb.h"
+
+#include "emap/data/itemd.h"
+#include "emap/struct/itemdext.h"
+
+struct ItemdExt *itemd_get_by_item(struct item *item)
+{
+ if (!item)
+ return NULL;
+ const int nameid = item->nameid;
+ struct item_data *item_data = itemdb->exists(nameid);
+ return itemd_get(item_data);
+}
+
+struct ItemdExt *itemd_get(struct item_data *item)
+{
+ if (!item)
+ return NULL;
+
+ struct ItemdExt *data = getFromITEMDATA(item, 0);
+ if (!data)
+ {
+ data = itemd_create();
+ addToITEMDATA(item, data, 0, true);
+ }
+ return data;
+}
+
+struct ItemdExt *itemd_create(void)
+{
+ struct ItemdExt *data = NULL;
+ CREATE(data, struct ItemdExt, 1);
+ if (!data)
+ return NULL;
+ data->floorLifeTime = battle->bc->flooritem_lifetime;
+ data->allowPickup = true;
+ data->requiredStr = 0;
+ data->requiredAgi = 0;
+ data->requiredVit = 0;
+ data->requiredInt = 0;
+ data->requiredDex = 0;
+ data->requiredLuk = 0;
+ data->requiredMaxHp = 0;
+ data->requiredMaxSp = 0;
+ data->requiredAtk = 0;
+ data->requiredMAtkMin = 0;
+ data->requiredMAtkMax = 0;
+ data->requiredDef = 0;
+ data->requiredMDef = 0;
+ data->useEffect = -1;
+ data->useFailEffect = -1;
+ data->unequipEffect = -1;
+ data->unequipFailEffect = -1;
+ return data;
+}
diff --git a/src/emap/data/itemd.h b/src/emap/data/itemd.h
new file mode 100644
index 0000000..d3c529b
--- /dev/null
+++ b/src/emap/data/itemd.h
@@ -0,0 +1,13 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_ITEMD
+#define EVOL_MAP_ITEMD
+
+struct ItemdExt;
+
+struct ItemdExt *itemd_get_by_item(struct item *item);
+struct ItemdExt *itemd_get(struct item_data *item);
+struct ItemdExt *itemd_create(void);
+
+#endif // EVOL_MAP_MAPD
diff --git a/src/emap/data/mapd.c b/src/emap/data/mapd.c
new file mode 100644
index 0000000..cb1a506
--- /dev/null
+++ b/src/emap/data/mapd.c
@@ -0,0 +1,40 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "map/map.h"
+
+#include "emap/data/mapd.h"
+#include "emap/struct/mapdext.h"
+
+struct MapdExt *mapd_get(int m)
+{
+ struct map_data *md = &map->list[m];
+ struct MapdExt *data = getFromMAPD(md, 0);
+ if (!data)
+ {
+ data = mapd_create();
+ addToMAPD(md, data, 0, true);
+ }
+ return data;
+}
+
+struct MapdExt *mapd_create(void)
+{
+ struct MapdExt *data = NULL;
+ CREATE(data, struct MapdExt, 1);
+ if (!data)
+ return NULL;
+ data->mask = 1;
+ data->invisible = false;
+ data->flag.nopve = 0;
+ return data;
+}
diff --git a/src/emap/data/mapd.h b/src/emap/data/mapd.h
new file mode 100644
index 0000000..a0878ae
--- /dev/null
+++ b/src/emap/data/mapd.h
@@ -0,0 +1,12 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_MAPD
+#define EVOL_MAP_MAPD
+
+struct MapdExt;
+
+struct MapdExt *mapd_get(int fd);
+struct MapdExt *mapd_create(void);
+
+#endif // EVOL_MAP_MAPD
diff --git a/src/emap/data/npcd.c b/src/emap/data/npcd.c
new file mode 100644
index 0000000..183db46
--- /dev/null
+++ b/src/emap/data/npcd.c
@@ -0,0 +1,38 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "map/battle.h"
+#include "map/npc.h"
+
+#include "emap/data/npcd.h"
+#include "emap/struct/npcdext.h"
+
+struct NpcdExt *npcd_get(TBL_NPC *nd)
+{
+ struct NpcdExt *data = getFromNPCD(nd, 0);
+ if (!data)
+ {
+ data = npcd_create();
+ addToNPCD(nd, data, 0, true);
+ }
+ return data;
+}
+
+struct NpcdExt *npcd_create(void)
+{
+ struct NpcdExt *data = NULL;
+ CREATE(data, struct NpcdExt, 1);
+ if (!data)
+ return NULL;
+ data->init = false;
+ return data;
+}
diff --git a/src/emap/data/npcd.h b/src/emap/data/npcd.h
new file mode 100644
index 0000000..52f3b76
--- /dev/null
+++ b/src/emap/data/npcd.h
@@ -0,0 +1,12 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_NPCD
+#define EVOL_MAP_NPCD
+
+struct NpcdExt;
+
+struct NpcdExt *npcd_get(TBL_NPC *nd);
+struct NpcdExt *npcd_create(void);
+
+#endif // EVOL_MAP_NPCD
diff --git a/src/emap/data/session.c b/src/emap/data/session.c
new file mode 100644
index 0000000..c3c3ffa
--- /dev/null
+++ b/src/emap/data/session.c
@@ -0,0 +1,48 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "map/pc.h"
+
+#include "emap/data/session.h"
+#include "emap/struct/sessionext.h"
+
+struct SessionExt *session_get(int fd)
+{
+ struct SessionExt *data = getFromSession(session[fd], 0);
+ if (!data)
+ {
+ data = session_create();
+ addToSession(session[fd], data, 0, true);
+ }
+ return data;
+}
+
+struct SessionExt *session_get_bysd(TBL_PC *sd)
+{
+ if (!sd)
+ return NULL;
+
+ return session_get(sd->fd);
+}
+
+struct SessionExt *session_create(void)
+{
+ struct SessionExt *data = NULL;
+ CREATE(data, struct SessionExt, 1);
+ if (!data)
+ return NULL;
+ data->clientVersion = 0;
+ data->language = 0;
+ data->state = 0;
+ data->onlinelistlasttime = 0;
+ return data;
+}
diff --git a/src/emap/data/session.h b/src/emap/data/session.h
new file mode 100644
index 0000000..040b408
--- /dev/null
+++ b/src/emap/data/session.h
@@ -0,0 +1,13 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_SESSION
+#define EVOL_MAP_SESSION
+
+struct SessionExt;
+
+struct SessionExt *session_get(int fd);
+struct SessionExt *session_get_bysd(TBL_PC *sd);
+struct SessionExt *session_create(void);
+
+#endif // EVOL_MAP_SESSION
diff --git a/src/emap/init.c b/src/emap/init.c
new file mode 100644
index 0000000..c74c441
--- /dev/null
+++ b/src/emap/init.c
@@ -0,0 +1,244 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "map/channel.h"
+#include "map/chat.h"
+#include "map/chrif.h"
+#include "map/clif.h"
+#include "map/duel.h"
+#include "map/elemental.h"
+#include "map/homunculus.h"
+#include "map/guild.h"
+#include "map/instance.h"
+#include "map/intif.h"
+#include "map/irc-bot.h"
+#include "map/itemdb.h"
+#include "map/mail.h"
+#include "map/mapreg.h"
+#include "map/mercenary.h"
+#include "map/mob.h"
+#include "map/npc.h"
+#include "map/party.h"
+#include "map/pet.h"
+#include "map/pc.h"
+#include "map/script.h"
+#include "map/storage.h"
+#include "map/trade.h"
+#include "map/quest.h"
+
+#include "ecommon/config.h"
+#include "ecommon/init.h"
+#include "emap/atcommand.h"
+#include "emap/clif.h"
+#include "emap/itemdb.h"
+#include "emap/lang.h"
+#include "emap/mail.h"
+#include "emap/map.h"
+#include "emap/mob.h"
+#include "emap/npc.h"
+#include "emap/unit.h"
+#include "emap/parse.h"
+#include "emap/permission.h"
+#include "emap/pc.h"
+#include "emap/quest.h"
+#include "emap/script.h"
+#include "emap/skill.h"
+#include "emap/status.h"
+
+#include "common/HPMDataCheck.h" /* should always be the last file included! (if you don't make it last, it'll intentionally break compile time) */
+
+extern int langScriptId;
+
+HPExport struct hplugin_info pinfo =
+{
+ "evol_map",
+ SERVER_TYPE_MAP,
+ "0.1",
+ HPM_VERSION
+};
+
+HPExport void plugin_init (void)
+{
+// HPM_map_add_group_permission = GET_SYMBOL("addGroupPermission");
+
+ status_init();
+
+ addAtcommand("setskill", setSkill);
+
+ addScriptCommand("setcamnpc", "*", setCamNpc);
+ addScriptCommand("setcam", "ii", setCam);
+ addScriptCommand("movecam", "ii", moveCam);
+ addScriptCommand("restorecam", "", restoreCam);
+ addScriptCommand("npctalk3", "s", npcTalk3);
+ addScriptCommand("closedialog", "", closeDialog);
+ addScriptCommand("shop", "s", shop);
+ addScriptCommand("getitemlink", "s", getItemLink);
+ addScriptCommand("l", "s*", l);
+ addScriptCommand("lg", "s*", lg);
+ addScriptCommand("requestlang", "v", requestLang);
+ addScriptCommand("requestitem", "v", requestItem);
+ addScriptCommand("requestitems", "v*", requestItems);
+ addScriptCommand("getq", "i", getq);
+ addScriptCommand("setq", "ii", setq);
+ addScriptCommand("setnpcdir", "*", setNpcDir);
+ addScriptCommand("rif", "is*", rif);
+ addScriptCommand("countitemcolor", "v*", countItemColor);
+ addScriptCommand("misceffect", "i*", miscEffect);
+ addScriptCommand("setmapmask", "si", setMapMask);
+ addScriptCommand("addmapmask", "si", addMapMask);
+ addScriptCommand("removemapmask", "si", removeMapMask);
+ addScriptCommand("getmapmask", "s", getMapMask);
+ addScriptCommand("setnpcsex", "*", setNpcSex);
+ addScriptCommand("showavatar", "*", showAvatar);
+ addScriptCommand("setavatardir", "i", setAvatarDir);
+ addScriptCommand("setavataraction", "i", setAvatarAction);
+ addScriptCommand("clear", "", clear);
+ addScriptCommand("changemusic", "ss", changeMusic);
+ addScriptCommand("setnpcdialogtitle", "s", setNpcDialogTitle);
+ addScriptCommand("getmapname", "", getMapName);
+ addScriptCommand("unequipbyid", "i", unequipById);
+ addScriptCommand("ispcdead", "", isPcDead);
+ addScriptCommand("areatimer", "siiiii*", areaTimer);
+ addScriptCommand("getareadropitem", "siiiiv*", getAreaDropItem);
+ addScriptCommand("setmount", "?", setMount);
+ addScriptCommand("clientcommand", "s", clientCommand);
+ addScriptCommand("isunitwalking", "?", isUnitWalking);
+
+ do_init_langs();
+
+ addPacket(0x7530, 22, map_parse_version, hpClif_Parse);
+ addPacket(0xb07, 26, map_parse_join_channel, hpClif_Parse);
+ addPacket(0xb09, 26, map_parse_part_channel, hpClif_Parse);
+ addPacket(0xb0c, -1, map_parse_pet_say, hpClif_Parse);
+ addPacket(0xb0d, 3, map_parse_pet_emote, hpClif_Parse);
+ addPacket(0xb0e, 4, map_parse_set_status, hpClif_Parse);
+ addPacket(0xb0f, 2, map_parse_get_online_list, hpClif_Parse);
+ addPacket(0xb11, 10, map_parse_pet_move, hpClif_Parse);
+ addPacket(0xb12, 9, map_parse_pet_dir, hpClif_Parse);
+ addPacket(0xb13, -1, map_parse_homun_say, hpClif_Parse);
+ addPacket(0xb14, 3, map_parse_homun_emote, hpClif_Parse);
+ addPacket(0xb15, 9, map_parse_homun_dir, hpClif_Parse);
+
+ addHookPre("atcommand->msgfd", eatcommand_msgfd);
+ addHookPre("atcommand->msgsd", eatcommand_msgsd);
+ addHookPre("pc->readparam", epc_readparam_pre);
+ addHookPre("pc->setregistry", epc_setregistry);
+ addHookPre("pc->equipitem_pos", epc_equipitem_pos);
+ addHookPre("pc->unequipitem_pos", epc_unequipitem_pos);
+ addHookPre("pc->can_attack", epc_can_attack);
+ addHookPre("pc->takeitem", epc_takeitem);
+ addHookPre("pc->validate_levels", epc_validate_levels);
+ addHookPre("pc->check_job_name", epc_check_job_name);
+ addHookPre("mob->deleteslave_sub", emob_deleteslave_sub);
+ addHookPre("npc->parse_unknown_mapflag", enpc_parse_unknown_mapflag);
+ addHookPre("npc->buysellsel", enpc_buysellsel);
+ addHookPre("npc->db_checkid", enpc_db_checkid);
+ addHookPre("clif->quest_send_list", eclif_quest_send_list);
+ addHookPre("clif->quest_add", eclif_quest_add);
+ addHookPre("clif->charnameack", eclif_charnameack);
+ addHookPre("clif->sendlook", eclif_sendlook);
+ addHookPre("clif->send", eclif_send);
+ addHookPre("clif->set_unit_idle", eclif_set_unit_idle);
+ addHookPre("clif->send_actual", eclif_send_actual);
+ addHookPre("itemdb->is_item_usable", eitemdb_is_item_usable);
+ addHookPre("itemdb->readdb_additional_fields", eitemdb_readdb_additional_fields);
+ addHookPre("unit->can_move", eunit_can_move);
+ addHookPre("unit->walktoxy", eunit_walktoxy);
+ addHookPre("mail->invalid_operation", email_invalid_operation);
+
+ addHookPost("clif->getareachar_unit", eclif_getareachar_unit_post);
+ addHookPost("clif->authok", eclif_authok_post);
+ addHookPost("clif->changemap", eclif_changemap_post);
+ addHookPost("clif->set_unit_idle", eclif_set_unit_idle_post);
+ addHookPost("status->set_viewdata", estatus_set_viewdata_post);
+ addHookPost("status->read_job_db_sub", estatus_read_job_db_sub);
+ addHookPost("status->calc_pc_", estatus_calc_pc_);
+ addHookPost("clif->set_unit_walking", eclif_set_unit_walking);
+ addHookPost("clif->move", eclif_move);
+ addHookPost("map->addflooritem", emap_addflooritem_post);
+ addHookPost("skill->check_condition_castend", eskill_check_condition_castend_post);
+ addHookPost("pc->isequip", epc_isuseequip_post);
+ addHookPost("pc->isUseitem", epc_isuseequip_post);
+ addHookPost("pc->useitem", epc_useitem_post);
+ addHookPost("pc->equipitem", epc_equipitem_post);
+ addHookPost("pc->unequipitem", epc_unequipitem_post);
+ addHookPost("pc->setnewpc", epc_setnewpc);
+
+ langScriptId = script->add_str("Lang");
+}
+
+HPExport void server_preinit (void)
+{
+ interfaces_init_common();
+
+ atcommand = GET_SYMBOL("atcommand");
+ battle = GET_SYMBOL("battle");
+ bg = GET_SYMBOL("battlegrounds");
+ buyingstore = GET_SYMBOL("buyingstore");
+ clif = GET_SYMBOL("clif");
+ chrif = GET_SYMBOL("chrif");
+ guild = GET_SYMBOL("guild");
+ gstorage = GET_SYMBOL("gstorage");
+ homun = GET_SYMBOL("homun");
+ map = GET_SYMBOL("map");
+ ircbot = GET_SYMBOL("ircbot");
+ itemdb = GET_SYMBOL("itemdb");
+ logs = GET_SYMBOL("logs");
+ mail = GET_SYMBOL("mail");
+ instance = GET_SYMBOL("instance");
+ script = GET_SYMBOL("script");
+ searchstore = GET_SYMBOL("searchstore");
+ skill = GET_SYMBOL("skill");
+ vending = GET_SYMBOL("vending");
+ pc = GET_SYMBOL("pc");
+ pcg = GET_SYMBOL("pc_groups");
+ party = GET_SYMBOL("party");
+ storage = GET_SYMBOL("storage");
+ trade = GET_SYMBOL("trade");
+ status = GET_SYMBOL("status");
+ chat = GET_SYMBOL("chat");
+ duel = GET_SYMBOL("duel");
+ elemental = GET_SYMBOL("elemental");
+ intif = GET_SYMBOL("intif");
+ mercenary = GET_SYMBOL("mercenary");
+ mob = GET_SYMBOL("mob");
+ unit = GET_SYMBOL("unit");
+ npc = GET_SYMBOL("npc");
+ mapreg = GET_SYMBOL("mapreg");
+ pet = GET_SYMBOL("pet");
+ path = GET_SYMBOL("path");
+ quest = GET_SYMBOL("quest");
+ npc_chat = GET_SYMBOL("npc_chat");
+ libpcre = GET_SYMBOL("libpcre");
+ mapit = GET_SYMBOL("mapit");
+ mapindex = GET_SYMBOL("mapindex");
+ channel = GET_SYMBOL("channel");
+
+ setDefaultMap();
+ addMapInterConf("default_map", config_default_map);
+ addMapInterConf("default_x", config_default_x);
+ addMapInterConf("default_y", config_default_y);
+
+ addHookPre("quest->read_db_sub", equest_read_db_sub);
+ addGroupPermission("send_gm", permission_send_gm_flag);
+ addGroupPermission("show_client_version", permission_show_client_version_flag);
+}
+
+HPExport void server_online (void)
+{
+}
+
+HPExport void plugin_final (void)
+{
+ do_final_langs();
+ commonClean();
+}
diff --git a/src/emap/itemdb.c b/src/emap/itemdb.c
new file mode 100644
index 0000000..34905a9
--- /dev/null
+++ b/src/emap/itemdb.c
@@ -0,0 +1,91 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "map/itemdb.h"
+#include "map/map.h"
+#include "map/npc.h"
+#include "map/pc.h"
+
+#include "emap/data/itemd.h"
+#include "emap/struct/itemdext.h"
+#include "emap/npc.h"
+
+bool eitemdb_is_item_usable(struct item_data *item)
+{
+ hookStop();
+ if (!item)
+ return false;
+ return item->type == IT_HEALING || item->type == IT_USABLE || item->type == IT_CASH || item->type == IT_PETEGG;
+}
+
+void eitemdb_readdb_additional_fields(int *itemid,
+ config_setting_t *it,
+ int *n __attribute__ ((unused)),
+ const char *source __attribute__ ((unused)))
+{
+ struct item_data *item = itemdb->exists(*itemid);
+ int i32 = 0;
+ if (!item)
+ {
+ hookStop();
+ return;
+ }
+ struct ItemdExt *data = itemd_get(item);
+ if (!data)
+ {
+ hookStop();
+ return;
+ }
+
+ config_setting_t *t = NULL;
+
+ if (libconfig->setting_lookup_int(it, "FloorLifeTime", &i32) && i32 >= 0)
+ data->floorLifeTime = i32;
+ if ((t = libconfig->setting_get_member(it, "AllowPickup")))
+ data->allowPickup = libconfig->setting_get_bool(t) ? 1 : 0;
+ if (libconfig->setting_lookup_int(it, "RequiredStr", &i32) && i32 >= 0)
+ data->requiredStr = i32;
+ if (libconfig->setting_lookup_int(it, "RequiredAgi", &i32) && i32 >= 0)
+ data->requiredAgi = i32;
+ if (libconfig->setting_lookup_int(it, "RequiredVit", &i32) && i32 >= 0)
+ data->requiredVit = i32;
+ if (libconfig->setting_lookup_int(it, "RequiredInt", &i32) && i32 >= 0)
+ data->requiredInt = i32;
+ if (libconfig->setting_lookup_int(it, "RequiredDex", &i32) && i32 >= 0)
+ data->requiredDex = i32;
+ if (libconfig->setting_lookup_int(it, "RequiredLuk", &i32) && i32 >= 0)
+ data->requiredLuk = i32;
+ if (libconfig->setting_lookup_int(it, "RequiredMaxHp", &i32) && i32 >= 0)
+ data->requiredMaxHp = i32;
+ if (libconfig->setting_lookup_int(it, "RequiredMaxSp", &i32) && i32 >= 0)
+ data->requiredMaxSp = i32;
+ if (libconfig->setting_lookup_int(it, "RequiredAtk", &i32) && i32 >= 0)
+ data->requiredAtk = i32;
+ if (libconfig->setting_lookup_int(it, "RequiredMAtkMin", &i32) && i32 >= 0)
+ data->requiredMAtkMin = i32;
+ if (libconfig->setting_lookup_int(it, "RequiredMAtkMax", &i32) && i32 >= 0)
+ data->requiredMAtkMax = i32;
+ if (libconfig->setting_lookup_int(it, "RequiredDef", &i32) && i32 >= 0)
+ data->requiredDef = i32;
+ if (libconfig->setting_lookup_int(it, "RequiredMDef", &i32) && i32 >= 0)
+ data->requiredMDef = i32;
+
+ if (itemdb->lookup_const(it, "UseEffect", &i32))
+ data->useEffect = i32;
+ if (itemdb->lookup_const(it, "UseFailEffect", &i32))
+ data->useFailEffect = i32;
+ if (itemdb->lookup_const(it, "UnequipEffect", &i32))
+ data->unequipEffect = i32;
+ if (itemdb->lookup_const(it, "UnequipFailEffect", &i32))
+ data->unequipFailEffect = i32;
+ hookStop();
+}
diff --git a/src/emap/itemdb.h b/src/emap/itemdb.h
new file mode 100644
index 0000000..5e35d57
--- /dev/null
+++ b/src/emap/itemdb.h
@@ -0,0 +1,11 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_ITEMDB
+#define EVOL_MAP_ITEMDB
+
+bool eitemdb_is_item_usable(struct item_data *item);
+
+void eitemdb_readdb_additional_fields(int *itemid, config_setting_t *it, int *n, const char *source);
+
+#endif // EVOL_MAP_ITEMDB
diff --git a/src/emap/lang.c b/src/emap/lang.c
new file mode 100644
index 0000000..d6a1910
--- /dev/null
+++ b/src/emap/lang.c
@@ -0,0 +1,234 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "map/npc.h"
+#include "map/pc.h"
+
+#include "emap/lang.h"
+#include "emap/data/session.h"
+#include "emap/struct/sessionext.h"
+
+#define MAX_LANGS 100
+
+struct DBMap *translate_db = NULL;
+char *lang_langs[MAX_LANGS];
+int lang_num = 0;
+
+static int langsdb_readdb (void);
+static int langsdb_readlangs (void);
+
+void do_init_langs (void)
+{
+ translate_db = strdb_alloc(DB_OPT_RELEASE_BOTH, 1000);
+
+ langsdb_readlangs ();
+ langsdb_readdb ();
+}
+
+static int delete_lang_sub(DBKey key __attribute__ ((unused)),
+ DBData *data,
+ va_list args __attribute__ ((unused)))
+{
+ int f;
+ char **strings = DB->data2ptr(data);
+ for (f = 0; f < lang_num; f ++)
+ {
+ aFree(strings[f]);
+ strings[f] = NULL;
+ }
+ return 0;
+}
+
+void do_final_langs(void)
+{
+ translate_db->destroy(translate_db, delete_lang_sub);
+ int f;
+ for (f = 0; f < lang_num; f ++)
+ aFree(lang_langs[f]);
+}
+
+static int langsdb_readlangs (void)
+{
+ FILE *fp;
+ lang_num = 0;
+ fp = fopen("langs/langs.txt", "r");
+ if (fp == NULL)
+ {
+ printf ("can't read langs/langs.txt\n");
+ return 1;
+ }
+ char line[100];
+ char text[101];
+ while (fgets (line, 99, fp))
+ {
+ if (sscanf(line, "%99s\n", text) < 1)
+ continue;
+
+ lang_langs[lang_num] = aStrdup (text);
+ lang_num ++;
+ }
+ fclose(fp);
+ return 0;
+}
+
+static int langsdb_readdb (void)
+{
+ char line[1020], line1[1020], line2[1020];
+ char filename[1000];
+ char **strings = NULL;
+ char *idx;
+ int i;
+ int sz;
+ for (i = 0; i < lang_num; i ++)
+ {
+ strcpy (filename, "langs/lang_");
+ strcat (filename, lang_langs[i]);
+ strcat (filename, ".txt");
+
+ FILE *fp = fopen(filename, "r");
+ if (fp == NULL)
+ {
+ printf ("can't read %s\n", filename);
+ return 1;
+ }
+
+ if (!fgets (line, 1010, fp))
+ {
+ printf ("can't read %s\n", filename);
+ continue;
+ }
+
+ line1[0] = 0;
+ line2[0] = 0;
+ while (fgets (line, 1010, fp))
+ {
+ if (*line)
+ {
+ idx = strrchr (line, '\n');
+ if (idx)
+ *idx = 0;
+ }
+
+ if (!*line)
+ {
+ line1[0] = 0;
+ line2[0] = 0;
+ continue;
+ }
+ else if (!*line1)
+ {
+ strcpy (line1, line);
+ continue;
+ }
+ strcpy (line2, line);
+
+ strings = (char **)strdb_get(translate_db, line1);
+ if (!strings)
+ {
+ strings = aCalloc (lang_num, sizeof(int*));
+ sz = strlen(line1) + 1;
+ strings[0] = aCalloc (sz < 24 ? 24 : sz, sizeof(char));
+ strcpy (strings[0], line2);
+ strdb_put(translate_db, aStrdup (line1), strings);
+ }
+ else
+ {
+ sz = strlen(line2) + 1;
+ strings[i] = aCalloc (sz < 24 ? 24 : sz, sizeof(char));
+ strcpy (strings[i], line2);
+ }
+
+ *line1 = 0;
+ *line2 = 0;
+ }
+ fclose (fp);
+ }
+ return 0;
+}
+
+const char* lang_trans(const char *str, int lng, int flg)
+{
+ if (!str)
+ return 0;
+
+ if (lng < 0 || lng >= lang_num)
+ return str;
+
+ char **strings = (char **)strdb_get(translate_db, str);
+ if (!strings)
+ {
+ if (flg)
+ printf ("no translations for: %s\n", str);
+ return str;
+ }
+
+ if (!strings[lng])
+ {
+ if (flg)
+ printf ("no lang string (%s) for: %s\n", lang_langs[lng], str);
+ return str;
+ }
+
+ return strings[lng];
+}
+
+const char* lang_pctrans(const char *str, TBL_PC *sd)
+{
+ int lng = 0;
+ int flg = 1;
+ if (!str)
+ return 0;
+
+ if (*str == '#')
+ flg = 0;
+ if (sd)
+ {
+ struct SessionExt *data = session_get_bysd(sd);
+ if (data)
+ lng = data->language;
+ }
+
+ return lang_trans(str, lng, flg);
+}
+
+int lang_getId(const char *str)
+{
+ char *str1 = aStrdup(str);
+ char *str2 = NULL;
+ int f;
+
+ if ((str2 = strchr(str, '.')))
+ *str2 = 0;
+
+ for (f = 0; f < MAX_LANGS && lang_langs[f]; f ++)
+ {
+ if (!strcmp(str, lang_langs[f]))
+ {
+ aFree (str1);
+ return f;
+ }
+ }
+
+ if ((str2 = strchr(str1, '_')))
+ *str2 = 0;
+
+ for (f = 0; f < MAX_LANGS && lang_langs[f]; f ++)
+ {
+ if (strstr(lang_langs[f], str1) == lang_langs[f])
+ {
+ aFree (str1);
+ return f;
+ }
+ }
+ aFree (str1);
+ return -1;
+}
diff --git a/src/emap/lang.h b/src/emap/lang.h
new file mode 100644
index 0000000..4afc6b9
--- /dev/null
+++ b/src/emap/lang.h
@@ -0,0 +1,15 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_LANG
+#define EVOL_MAP_LANG
+
+extern struct DBMap *translate_db;
+
+void do_init_langs (void);
+void do_final_langs(void);
+const char* lang_trans(const char *str, int lng, int flg);
+const char* lang_pctrans(const char *str, TBL_PC *sd);
+int lang_getId(const char *str);
+
+#endif // EVOL_MAP_LANG
diff --git a/src/emap/mail.c b/src/emap/mail.c
new file mode 100644
index 0000000..a3d92c8
--- /dev/null
+++ b/src/emap/mail.c
@@ -0,0 +1,36 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/db.h"
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "common/timer.h"
+#include "map/battle.h"
+#include "map/itemdb.h"
+#include "map/map.h"
+#include "map/pc.h"
+
+bool email_invalid_operation(struct map_session_data *sd)
+{
+ if (!sd)
+ {
+ hookStop();
+ return true;
+ }
+
+ if (!map->list[sd->bl.m].flag.town)
+ {
+ ShowWarning("clif->parse_Mail: char '%s' trying to do invalid mail operations.\n", sd->status.name);
+ hookStop();
+ return true;
+ }
+ hookStop();
+ return false;
+}
diff --git a/src/emap/mail.h b/src/emap/mail.h
new file mode 100644
index 0000000..2c3aca2
--- /dev/null
+++ b/src/emap/mail.h
@@ -0,0 +1,9 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_MAIL
+#define EVOL_MAP_MAIL
+
+bool email_invalid_operation(struct map_session_data *sd);
+
+#endif // EVOL_MAP_MAIL
diff --git a/src/emap/map.c b/src/emap/map.c
new file mode 100644
index 0000000..55f4245
--- /dev/null
+++ b/src/emap/map.c
@@ -0,0 +1,133 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/db.h"
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "common/timer.h"
+#include "map/battle.h"
+#include "map/itemdb.h"
+#include "map/map.h"
+#include "map/pc.h"
+
+#include "emap/permission.h"
+#include "emap/send.h"
+#include "emap/data/itemd.h"
+#include "emap/data/session.h"
+#include "emap/struct/itemdext.h"
+#include "emap/struct/sessionext.h"
+
+int emap_addflooritem_post(int retVal,
+ struct item *item,
+ int *amount __attribute__ ((unused)),
+ int16 *m __attribute__ ((unused)),
+ int16 *x __attribute__ ((unused)),
+ int16 *y __attribute__ ((unused)),
+ int *first_charid __attribute__ ((unused)),
+ int *second_charid __attribute__ ((unused)),
+ int *third_charid __attribute__ ((unused)),
+ int *flags __attribute__ ((unused)))
+{
+ TBL_ITEM* fitem = (TBL_ITEM*)idb_get(map->id_db, retVal);
+ if (fitem && fitem->cleartimer != INVALID_TIMER)
+ {
+ int timeout = battle->bc->flooritem_lifetime;
+ struct ItemdExt *data = itemd_get_by_item(item);
+ if (data)
+ timeout = data->floorLifeTime;
+ timer->delete(fitem->cleartimer, map->clearflooritem_timer);
+ if (timeout >= 0)
+ fitem->cleartimer = timer->add(timer->gettick() + timeout, map->clearflooritem_timer, fitem->bl.id, 0);
+ }
+ return retVal;
+}
+
+void emap_online_list(int fd)
+{
+ char *buf = aCalloc (1, 20000);
+ char *ptr = buf;
+ TBL_PC* sd;
+
+ struct SessionExt *data1 = session_get(fd);
+ if (!data1)
+ {
+ aFree(buf);
+ return;
+ }
+
+ const time_t t = time(NULL);
+ if (data1->onlinelistlasttime + 15 >= t)
+ { // not more than 1 per 15 seconds
+ data1->onlinelistlasttime = t;
+ aFree(buf);
+ return;
+ }
+
+ TBL_PC* ssd = (TBL_PC*)session[fd]->session_data;
+ if (!ssd)
+ {
+ aFree(buf);
+ return;
+ }
+
+ const bool showVersion = pc_has_permission(ssd, permission_show_client_version_flag);
+ const int gpoupLevel = pc_get_group_level(ssd);
+ data1->onlinelistlasttime = t;
+
+ DBIterator* iter = db_iterator(map->pc_db);
+
+ for (sd = dbi_first(iter); dbi_exists(iter); sd = dbi_next(iter))
+ {
+ if (!sd)
+ continue;
+
+ if (ptr - buf > 19500)
+ break;
+
+ if (pc_isinvisible(sd) && gpoupLevel < pc_get_group_level(sd))
+ continue;
+
+ struct SessionExt *data = session_get_bysd(sd);
+ if (!data)
+ continue;
+
+ uint8 state = data->state;
+ if (sd->status.sex == 1)
+ state |= 128;
+ else
+ state = (state | 128) ^ 128;
+
+ if (pc_has_permission(sd, permission_send_gm_flag))
+ state |= 64;
+ else
+ state = (state | 64) ^ 64;
+
+ *ptr = state;
+ ptr ++;
+
+ *ptr = sd->status.base_level;
+ ptr ++;
+
+ if (showVersion)
+ *ptr = data->clientVersion;
+ else
+ *ptr = 0;
+ ptr ++;
+
+ strcpy(ptr, sd->status.name);
+ ptr += strlen(sd->status.name);
+ *ptr = 0;
+ ptr ++;
+
+ }
+ dbi_destroy(iter);
+ send_online_list(fd, buf, ptr - buf);
+ aFree(buf);
+}
diff --git a/src/emap/map.h b/src/emap/map.h
new file mode 100644
index 0000000..3b9afce
--- /dev/null
+++ b/src/emap/map.h
@@ -0,0 +1,10 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_MAP
+#define EVOL_MAP_MAP
+
+int emap_addflooritem_post(int retVal, struct item *item, int *amount, int16 *m, int16 *x, int16 *y, int *first_charid, int *second_charid, int *third_charid, int *flags);
+void emap_online_list(int fd);
+
+#endif // EVOL_MAP_MAP
diff --git a/src/emap/mob.c b/src/emap/mob.c
new file mode 100644
index 0000000..c4c8bcf
--- /dev/null
+++ b/src/emap/mob.c
@@ -0,0 +1,48 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "common/timer.h"
+#include "map/battle.h"
+#include "map/itemdb.h"
+#include "map/mob.h"
+
+int emob_deleteslave_sub(struct block_list *bl, va_list ap)
+{
+ if (!bl)
+ {
+ hookStop();
+ return 0;
+ }
+ TBL_MOB *md = (TBL_MOB *)bl;
+ if (!md)
+ {
+ hookStop();
+ return 0;
+ }
+
+ const int id = va_arg(ap, int);
+ if (md->master_id > 0 && md->master_id == id)
+ {
+ if (md->db->status.mode & 0x8000)
+ {
+ md->master_id = 0;
+ md->master_dist = 0;
+ }
+ else
+ {
+ status_kill(bl);
+ }
+ }
+
+ hookStop();
+ return 0;
+}
diff --git a/src/emap/mob.h b/src/emap/mob.h
new file mode 100644
index 0000000..d0d9e87
--- /dev/null
+++ b/src/emap/mob.h
@@ -0,0 +1,9 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_MOB
+#define EVOL_MAP_MOB
+
+int emob_deleteslave_sub(struct block_list *bl, va_list ap);
+
+#endif // EVOL_MAP_MOB
diff --git a/src/emap/npc.c b/src/emap/npc.c
new file mode 100644
index 0000000..16fe2bb
--- /dev/null
+++ b/src/emap/npc.c
@@ -0,0 +1,127 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "map/map.h"
+#include "map/npc.h"
+#include "map/pc.h"
+
+#include "emap/data/mapd.h"
+#include "emap/data/npcd.h"
+#include "emap/struct/mapdext.h"
+#include "emap/struct/npcdext.h"
+#include "emap/npc.h"
+
+void enpc_parse_unknown_mapflag(const char *name, char *w3, char *w4, const char* start,
+ const char* buffer, const char* filepath, int *retval)
+{
+ if (!strcmpi(w3, "invisible"))
+ {
+ int16 m = map->mapname2mapid(name);
+ struct MapdExt *data = mapd_get(m);
+ if (data)
+ data->invisible = true;
+ }
+ else if (!strcmpi(w3, "mask"))
+ {
+ int16 m = map->mapname2mapid(name);
+ struct MapdExt *data = mapd_get(m);
+ if (data)
+ data->mask = atoi(w4);
+ }
+ else if (!strcmpi(w3, "nopve"))
+ {
+ int16 m = map->mapname2mapid(name);
+ struct MapdExt *data = mapd_get(m);
+ if (data)
+ data->flag.nopve = 1;
+ }
+ else
+ {
+ ShowError("npc_parse_mapflag: unrecognized mapflag '%s' in file '%s', line '%d'.\n", w3, filepath, strline(buffer,start-buffer));
+ if (retval)
+ *retval = EXIT_FAILURE;
+ }
+ hookStop();
+}
+
+int enpc_buysellsel(TBL_PC* sd, int *id, int *type)
+{
+ TBL_NPC *nd;
+
+ if (!sd)
+ return 1;
+
+ if ((nd = npc->checknear(sd, map->id2bl(*id))) == NULL)
+ {
+ hookStop();
+ return 1;
+ }
+
+ if (nd->option & OPTION_INVISIBLE) // can't buy if npc is not visible (hack?)
+ {
+ hookStop();
+ return 1;
+ }
+
+ if (*type == 0 && nd->subtype == SCRIPT && nd->u.scr.shop && nd->u.scr.shop->type == NST_MARKET)
+ {
+ clif->npc_market_open(sd, nd);
+ hookStop();
+ return 0;
+ }
+
+ if (nd->subtype != SHOP && !(nd->subtype == SCRIPT && nd->u.scr.shop && nd->u.scr.shop->items))
+ {
+ if (nd->subtype == SCRIPT)
+ ShowError("npc_buysellsel: trader '%s' has no shop list!\n", nd->exname);
+ else
+ ShowError("npc_buysellsel: no such shop npc %d (%s)\n", *id, nd->exname);
+
+ if (sd->npc_id == *id)
+ sd->npc_id = 0;
+ hookStop();
+ return 1;
+ }
+
+ if (nd->class_ < 0 && !sd->state.callshop)
+ { // not called through a script and is not a visible NPC so an invalid call
+ hookStop();
+ return 1;
+ }
+
+ // reset the callshop state for future calls
+ sd->state.callshop = 0;
+ sd->npc_shopid = *id;
+
+ if (*type == 0)
+ clif->buylist(sd, nd);
+ else
+ clif->selllist(sd);
+
+ hookStop();
+ return 0;
+}
+
+bool enpc_db_checkid(int *idPtr)
+{
+ const int id = *idPtr;
+ hookStop();
+
+ if (id == HIDDEN_WARP_CLASS || id == INVISIBLE_CLASS) // Special IDs not included in the valid ranges
+ return true;
+ if (id >= 45 && id < MAX_NPC_CLASS) // Second subrange
+ return true;
+ if (id >= MAX_NPC_CLASS2_START && id < MAX_NPC_CLASS2_END) // Second range
+ return true;
+ // Anything else is invalid
+ return false;
+}
diff --git a/src/emap/npc.h b/src/emap/npc.h
new file mode 100644
index 0000000..4f584fe
--- /dev/null
+++ b/src/emap/npc.h
@@ -0,0 +1,14 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_NPC
+#define EVOL_MAP_NPC
+
+void enpc_parse_unknown_mapflag(const char *name, char *w3, char *w4, const char* start,
+ const char* buffer, const char* filepath, int *retval);
+
+int enpc_buysellsel(TBL_PC* sd, int *id, int *type);
+
+bool enpc_db_checkid(int *idPtr);
+
+#endif // EVOL_MAP_NPC
diff --git a/src/emap/parse.c b/src/emap/parse.c
new file mode 100644
index 0000000..c5179cd
--- /dev/null
+++ b/src/emap/parse.c
@@ -0,0 +1,220 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "map/channel.h"
+#include "map/clif.h"
+#include "map/homunculus.h"
+#include "map/mercenary.h"
+#include "map/pc.h"
+#include "map/pet.h"
+#include "map/unit.h"
+
+#include "emap/parse.h"
+#include "emap/send.h"
+#include "emap/map.h"
+#include "emap/data/session.h"
+#include "emap/struct/sessionext.h"
+
+void map_parse_version(int fd)
+{
+ struct SessionExt *data = session_get(fd);
+ if (!data)
+ return;
+ data->clientVersion = RFIFOL(fd, 2);
+}
+
+void map_parse_join_channel(int fd)
+{
+ char name[24];
+ char *p;
+ TBL_PC* sd = (TBL_PC*)session[fd]->session_data;
+ int res = 0;
+ if (!sd)
+ return;
+
+ safestrncpy(name, (char*)RFIFOP(fd, 2), 24);
+ if (name[0] == '#')
+ p = name + 1;
+ else
+ p = name;
+
+ struct channel_data *chan = channel->search(p, sd);
+
+ if (chan)
+ {
+ int k;
+ ARR_FIND(0, sd->channel_count, k, sd->channels[k] == chan);
+ if (k < sd->channel_count || channel->join(chan, sd, NULL, true) == HCS_STATUS_OK)
+ res = 1;
+ else
+ res = 0;
+ }
+
+ send_join_ack(fd, name, res);
+}
+
+void map_parse_part_channel(int fd)
+{
+ char name[24];
+ char *p;
+ TBL_PC* sd = (TBL_PC*)session[fd]->session_data;
+ int k;
+ if (!sd)
+ return;
+
+ safestrncpy(name, (char*)RFIFOP(fd, 2), 24);
+ if (name[0] == '#')
+ p = name + 1;
+ else
+ p = name;
+
+ for (k = 0; k < sd->channel_count; k ++)
+ {
+ if (strcmpi(p, sd->channels[k]->name) == 0)
+ break;
+ }
+
+ if (k == sd->channel_count)
+ return;
+
+ if (sd->channels[k]->type == HCS_TYPE_ALLY)
+ {
+ do
+ {
+ for (k = 0; k < sd->channel_count; k++)
+ {
+ if (sd->channels[k]->type == HCS_TYPE_ALLY)
+ {
+ channel->leave(sd->channels[k], sd);
+ break;
+ }
+ }
+ }
+ while (k != sd->channel_count);
+ }
+ else
+ {
+ channel->leave(sd->channels[k], sd);
+ }
+}
+
+void map_parse_pet_say(int fd)
+{
+ char message[500];
+
+ TBL_PC* sd = (TBL_PC*)session[fd]->session_data;
+ if (!sd || !sd->pd)
+ return;
+
+ const int len = RFIFOW(fd, 2);
+ if (len > 500 || len < 6)
+ return;
+ safestrncpy(message, (char*)RFIFOP(fd, 4), len - 4);
+ send_slave_say(sd, &sd->pd->bl, sd->pd->pet.name, message);
+}
+
+void map_parse_pet_emote(int fd)
+{
+ TBL_PC* sd = (TBL_PC*)session[fd]->session_data;
+ if (!sd || !sd->pd)
+ return;
+ const time_t t = time(NULL);
+ if (sd->emotionlasttime + 1 >= t)
+ { // not more than 1 per second
+ sd->emotionlasttime = t;
+ return;
+ }
+
+ sd->emotionlasttime = t;
+ clif->emotion(&sd->pd->bl, RFIFOB(fd, 2));
+}
+
+void map_parse_set_status(int fd)
+{
+ struct SessionExt *data = session_get(fd);
+ if (!data)
+ return;
+ data->state = RFIFOB(fd, 2);
+}
+
+void map_parse_get_online_list(int fd)
+{
+ emap_online_list(fd);
+}
+
+void map_parse_pet_move(int fd)
+{
+ TBL_PC* sd = (TBL_PC*)session[fd]->session_data;
+ if (!sd || !sd->pd)
+ return;
+ short x = RFIFOW(fd, 6);
+ short y = RFIFOW(fd, 8);
+
+ struct block_list *pdBl = &sd->pd->bl;
+ if (map->getcell(pdBl->m, x, y, CELL_CHKPASS))
+ unit->walktoxy(pdBl, x, y, 0);
+}
+
+void map_parse_pet_dir(int fd)
+{
+ TBL_PC* sd = (TBL_PC*)session[fd]->session_data;
+ if (!sd || !sd->pd)
+ return;
+ unit->setdir(&sd->pd->bl, RFIFOB(fd, 8));
+}
+
+void map_parse_homun_say(int fd)
+{
+ char message[500];
+
+ TBL_PC* sd = (TBL_PC*)session[fd]->session_data;
+ if (!sd)
+ return;
+ const int len = RFIFOW(fd, 2);
+ if (len > 500 || len < 6)
+ return;
+ safestrncpy(message, (char*)RFIFOP(fd, 4), len - 4);
+ if (sd->md && sd->md->db)
+ send_slave_say(sd, &sd->md->bl, sd->md->db->name, message);
+ else if (sd->hd && homun_alive(sd->hd))
+ send_slave_say(sd, &sd->hd->bl, sd->hd->homunculus.name, message);
+}
+
+void map_parse_homun_emote(int fd)
+{
+ TBL_PC* sd = (TBL_PC*)session[fd]->session_data;
+ if (!sd)
+ return;
+ const time_t t = time(NULL);
+ if (sd->emotionlasttime + 1 >= t)
+ { // not more than 1 per second
+ sd->emotionlasttime = t;
+ return;
+ }
+
+ sd->emotionlasttime = t;
+ if (sd->md && sd->md->db)
+ clif->emotion(&sd->md->bl, RFIFOB(fd, 2));
+ else if (sd->hd && homun_alive(sd->hd))
+ clif->emotion(&sd->hd->bl, RFIFOB(fd, 2));
+}
+
+void map_parse_homun_dir(int fd)
+{
+ TBL_PC* sd = (TBL_PC*)session[fd]->session_data;
+ if (!sd || !sd->pd)
+ return;
+ if (sd->md && sd->md->db)
+ unit->setdir(&sd->md->bl, RFIFOB(fd, 8));
+ else if (sd->hd && homun_alive(sd->hd))
+ unit->setdir(&sd->hd->bl, RFIFOB(fd, 8));
+}
diff --git a/src/emap/parse.h b/src/emap/parse.h
new file mode 100644
index 0000000..8d137ad
--- /dev/null
+++ b/src/emap/parse.h
@@ -0,0 +1,20 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_PARSE
+#define EVOL_MAP_PARSE
+
+void map_parse_version(int fd);
+void map_parse_join_channel(int fd);
+void map_parse_part_channel(int fd);
+void map_parse_pet_say(int fd);
+void map_parse_pet_emote(int fd);
+void map_parse_set_status(int fd);
+void map_parse_get_online_list(int fd);
+void map_parse_pet_move(int fd);
+void map_parse_pet_dir(int fd);
+void map_parse_homun_say(int fd);
+void map_parse_homun_emote(int fd);
+void map_parse_homun_dir(int fd);
+
+#endif // EVOL_MAP_PARSE
diff --git a/src/emap/pc.c b/src/emap/pc.c
new file mode 100644
index 0000000..59ac6e2
--- /dev/null
+++ b/src/emap/pc.c
@@ -0,0 +1,309 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "map/itemdb.h"
+#include "map/pc.h"
+
+#include "emap/pc.h"
+#include "emap/data/itemd.h"
+#include "emap/data/mapd.h"
+#include "emap/data/session.h"
+#include "emap/struct/itemdext.h"
+#include "emap/struct/mapdext.h"
+#include "emap/struct/sessionext.h"
+
+int langScriptId;
+
+int epc_readparam_pre(TBL_PC* sd, int *type)
+{
+ if (*type == Const_ClientVersion)
+ {
+ struct SessionExt *data = session_get_bysd(sd);
+ hookStop();
+ if (!data)
+ return 0;
+ return data->clientVersion;
+ }
+ return 0;
+}
+
+int epc_setregistry(TBL_PC *sd, int64 *reg, int *val)
+{
+ if (*reg == langScriptId)
+ {
+ struct SessionExt *data = session_get_bysd(sd);
+ if (!data)
+ return 0;
+
+ data->language = *val;
+ }
+
+ return 0;
+}
+
+#define equipPos(mask, field, lookf) \
+ if (pos & mask) \
+ { \
+ if (id) \
+ sd->status.field = id->look; \
+ else \
+ sd->status.field = 0; \
+ clif->changelook(&sd->bl, lookf, sd->status.field); \
+ hookStop(); \
+ }
+
+#define equipPos2(mask, lookf) \
+ if (pos & mask) \
+ { \
+ if (id) \
+ clif->changelook(&sd->bl, lookf, id->look); \
+ else \
+ clif->changelook(&sd->bl, lookf, 0); \
+ hookStop(); \
+ }
+
+void epc_equipitem_pos(TBL_PC *sd, struct item_data *id, int *posPtr)
+{
+ int pos = *posPtr;
+
+ if (!id)
+ return;
+
+ equipPos(EQP_HEAD_LOW, head_bottom, LOOK_HEAD_BOTTOM);
+ equipPos(EQP_HEAD_TOP, head_top, LOOK_HEAD_TOP);
+ equipPos(EQP_HEAD_MID, head_mid, LOOK_HEAD_MID);
+ equipPos(EQP_GARMENT, robe, LOOK_ROBE);
+ //skip EQP_ARMOR
+ equipPos2(EQP_SHOES, LOOK_SHOES);
+ equipPos2(EQP_COSTUME_HEAD_TOP, 13);
+ equipPos2(EQP_COSTUME_HEAD_MID, 14);
+ equipPos2(EQP_COSTUME_HEAD_LOW, 15);
+ equipPos2(EQP_COSTUME_GARMENT, 16);
+ equipPos2(EQP_ARMOR, 17);
+ //skipping SHADOW slots
+}
+
+#undef equipPos
+#undef equipPos2
+
+#define unequipPos(mask, field, lookf) \
+ if (pos & mask) \
+ { \
+ sd->status.field = 0; \
+ clif->changelook(&sd->bl, lookf, sd->status.field); \
+ hookStop(); \
+ }
+
+#define unequipPos2(mask, lookf) \
+ if (pos & mask) \
+ { \
+ clif->changelook(&sd->bl, lookf, 0); \
+ hookStop(); \
+ }
+
+void epc_unequipitem_pos(TBL_PC *sd,
+ int *nPtr __attribute__ ((unused)),
+ int *posPtr)
+{
+ if (!sd)
+ return;
+
+ int pos = *posPtr;
+
+ unequipPos(EQP_HEAD_LOW, head_bottom, LOOK_HEAD_BOTTOM);
+ unequipPos(EQP_HEAD_TOP, head_top, LOOK_HEAD_TOP);
+ unequipPos(EQP_HEAD_MID, head_mid, LOOK_HEAD_MID);
+ unequipPos(EQP_GARMENT, robe, LOOK_ROBE);
+ unequipPos2(EQP_SHOES, LOOK_SHOES);
+ unequipPos2(EQP_COSTUME_HEAD_TOP, 13);
+ unequipPos2(EQP_COSTUME_HEAD_MID, 14);
+ unequipPos2(EQP_COSTUME_HEAD_LOW, 15);
+ unequipPos2(EQP_COSTUME_GARMENT, 16);
+ unequipPos2(EQP_ARMOR, 17);
+ //skipping SHADOW slots
+}
+
+#undef unequipPos
+#undef unequipPos2
+
+bool epc_can_attack (TBL_PC *sd, int *target_id)
+{
+ if (!sd)
+ return false;
+
+ struct MapdExt *data = mapd_get(sd->bl.m);
+ if (!data)
+ return true;
+ if (data->flag.nopve)
+ {
+ if (map->id2md(*target_id))
+ {
+ hookStop();
+ return false;
+ }
+ }
+ return true;
+}
+
+int epc_takeitem(TBL_PC *sd __attribute__ ((unused)),
+ TBL_ITEM *fitem)
+{
+ if (!fitem)
+ return 0;
+
+ struct ItemdExt *data = itemd_get_by_item(&fitem->item_data);
+ if (!data)
+ return 1;
+
+ if (!data->allowPickup)
+ {
+ hookStop();
+ return 0;
+ }
+ return 1;
+}
+
+void epc_validate_levels(void)
+{
+ int i;
+ for (i = 0; i < 7; i++) {
+ if (!pc->db_checkid(i)) continue;
+ if (i == JOB_WEDDING || i == JOB_XMAS || i == JOB_SUMMER)
+ continue; //Classes that do not need exp tables.
+ int j = pc->class2idx(i);
+ if (!pc->max_level[j][0])
+ ShowWarning("Class %d does not has a base exp table.\n", i);
+ if (!pc->max_level[j][1])
+ ShowWarning("Class %d does not has a job exp table.\n", i);
+ }
+ hookStop();
+}
+
+int epc_isuseequip_post(int retVal, struct map_session_data *sd, int *nPtr)
+{
+ const int n = *nPtr;
+ if (retVal)
+ {
+ if (!sd)
+ return 0;
+
+ if (n < 0 || n >= MAX_INVENTORY)
+ return 0;
+
+ struct ItemdExt *data = itemd_get(sd->inventory_data[n]);
+ if (!data)
+ return retVal;
+
+ if (sd->battle_status.str < data->requiredStr ||
+ sd->battle_status.agi < data->requiredAgi ||
+ sd->battle_status.vit < data->requiredVit ||
+ sd->battle_status.int_ < data->requiredInt ||
+ sd->battle_status.dex < data->requiredDex ||
+ sd->battle_status.luk < data->requiredLuk ||
+ sd->battle_status.max_hp < data->requiredMaxHp ||
+ sd->battle_status.max_sp < data->requiredMaxSp ||
+ sd->battle_status.batk < data->requiredAtk ||
+ sd->battle_status.matk_min < data->requiredMAtkMin ||
+ sd->battle_status.matk_max < data->requiredMAtkMax ||
+ sd->battle_status.def < data->requiredDef ||
+ sd->battle_status.mdef < data->requiredMDef
+ )
+ {
+ return 0;
+ }
+ }
+ return retVal;
+}
+
+int epc_useitem_post(int retVal, struct map_session_data *sd, int *nPtr)
+{
+ const int n = *nPtr;
+ if (!sd)
+ return retVal;
+
+ if (n < 0 || n >= MAX_INVENTORY)
+ return retVal;
+
+ struct ItemdExt *data = itemd_get(sd->inventory_data[n]);
+ if (!data)
+ return retVal;
+
+ const int effect = retVal ? data->useEffect : data->useFailEffect;
+ if (effect != -1)
+ clif->specialeffect(&sd->bl, effect, AREA);
+ return retVal;
+}
+
+static void equippost_effect(struct map_session_data *const sd, const int n, const bool retVal, const bool equip)
+{
+ if (!sd)
+ return;
+
+ if (n < 0 || n >= MAX_INVENTORY)
+ return;
+
+ struct ItemdExt *data = itemd_get(sd->inventory_data[n]);
+ if (!data)
+ return;
+
+ int effect;
+ if (equip)
+ effect = retVal ? data->useEffect : data->useFailEffect;
+ else
+ effect = retVal ? data->unequipEffect : data->unequipFailEffect;
+
+ if (effect != -1)
+ clif->specialeffect(&sd->bl, effect, AREA);
+ return;
+}
+
+int epc_equipitem_post(int retVal, struct map_session_data *sd,
+ int *nPtr, int *data __attribute__ ((unused)))
+{
+ equippost_effect(sd, *nPtr, retVal, true);
+ return retVal;
+}
+
+int epc_unequipitem_post(int retVal, struct map_session_data *sd,
+ int *nPtr, int *data __attribute__ ((unused)))
+{
+ equippost_effect(sd, *nPtr, retVal, false);
+ return retVal;
+}
+
+int epc_check_job_name(const char *name)
+{
+ int val = -1;
+ if (script->get_constant(name, &val))
+ {
+ hookStop();
+ return val;
+ }
+ hookStop();
+ return -1;
+}
+
+int epc_setnewpc(int retVal, struct map_session_data *sd,
+ int *account_id __attribute__ ((unused)),
+ int *char_id __attribute__ ((unused)),
+ int *login_id1 __attribute__ ((unused)),
+ unsigned int *client_tick __attribute__ ((unused)),
+ int *sex __attribute__ ((unused)),
+ int *fd __attribute__ ((unused)))
+{
+ if (sd)
+ {
+ sd->battle_status.speed = 150;
+ sd->base_status.speed = 150;
+ }
+ return retVal;
+}
diff --git a/src/emap/pc.h b/src/emap/pc.h
new file mode 100644
index 0000000..e850b81
--- /dev/null
+++ b/src/emap/pc.h
@@ -0,0 +1,42 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_PC
+#define EVOL_MAP_PC
+
+enum VarConst
+{
+ Const_ClientVersion = 10000
+};
+
+int epc_readparam_pre(TBL_PC* sd, int *type);
+
+int epc_setregistry(TBL_PC *sd, int64 *reg, int *val);
+
+void epc_equipitem_pos(TBL_PC *sd, struct item_data *id, int *posPtr);
+
+void epc_unequipitem_pos(TBL_PC *sd, int *nPtr, int *posPtr);
+
+bool epc_can_attack (TBL_PC *sd, int *target_id);
+
+int epc_takeitem(TBL_PC *sd, TBL_ITEM *fitem);
+
+void epc_validate_levels(void);
+
+int epc_isuseequip_post(int retVal, struct map_session_data *sd, int *nPtr);
+
+int epc_useitem_post(int retVal, struct map_session_data *sd, int *nPtr);
+
+int epc_equipitem_post(int retVal, struct map_session_data *sd,
+ int *nPtr, int *data);
+
+int epc_unequipitem_post(int retVal, struct map_session_data *sd,
+ int *nPtr, int *data);
+
+int epc_check_job_name(const char *name);
+
+int epc_setnewpc(int retVal, struct map_session_data *sd,
+ int *account_id, int *char_id, int *login_id1,
+ unsigned int *client_tick, int *sex, int *fd);
+
+#endif // EVOL_MAP_PC
diff --git a/src/emap/permission.c b/src/emap/permission.c
new file mode 100644
index 0000000..b05b04b
--- /dev/null
+++ b/src/emap/permission.c
@@ -0,0 +1,18 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "map/map.h"
+#include "map/npc.h"
+#include "map/status.h"
+
+unsigned int permission_send_gm_flag = UINT_MAX - 1;
+unsigned int permission_show_client_version_flag = UINT_MAX - 2;
diff --git a/src/emap/permission.h b/src/emap/permission.h
new file mode 100644
index 0000000..a585c98
--- /dev/null
+++ b/src/emap/permission.h
@@ -0,0 +1,10 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_PERMISSION
+#define EVOL_MAP_PERMISSION
+
+extern unsigned int permission_send_gm_flag;
+extern unsigned int permission_show_client_version_flag;
+
+#endif // EVOL_MAP_PERMISSION
diff --git a/src/emap/quest.c b/src/emap/quest.c
new file mode 100644
index 0000000..5ad82f6
--- /dev/null
+++ b/src/emap/quest.c
@@ -0,0 +1,132 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "map/itemdb.h"
+#include "map/quest.h"
+
+#include "emap/quest.h"
+
+/**
+ * Reads and parses an entry from the quest_db.
+ *
+ * @param cs The config setting containing the entry.
+ * @param n The sequential index of the current config setting.
+ * @param source The source configuration file.
+ * @return The parsed quest entry.
+ * @retval NULL in case of errors.
+ */
+struct quest_db *equest_read_db_sub(config_setting_t *cs, int *nPtr, const char *source)
+{
+ struct quest_db *entry = NULL;
+ config_setting_t *t = NULL;
+ int i32 = 0, quest_id;
+ const char *str = NULL;
+ const int n = *nPtr;
+
+ /*
+ * Id: Quest ID [int]
+ * Name: Quest Name [string]
+ * TimeLimit: Time Limit (seconds) [int, optional]
+ * Targets: ( [array, optional]
+ * {
+ * MobId: Mob ID [int]
+ * Count: [int]
+ * },
+ * ... (can repeated up to MAX_QUEST_OBJECTIVES times)
+ * )
+ * Drops: (
+ * {
+ * ItemId: Item ID to drop [int]
+ * Rate: Drop rate [int]
+ * MobId: Mob ID to match [int, optional]
+ * },
+ * ... (can be repeated)
+ * )
+ */
+
+ if (!libconfig->setting_lookup_int(cs, "Id", &quest_id)) {
+ ShowWarning("quest_read_db: Missing id in \"%s\", entry #%d, skipping.\n", source, n);
+ hookStop();
+ return NULL;
+ }
+ if (quest_id < 0 || quest_id >= MAX_QUEST_DB) {
+ ShowWarning("quest_read_db: Invalid quest ID '%d' in \"%s\", entry #%d (min: 0, max: %d), skipping.\n", quest_id, source, n, MAX_QUEST_DB);
+ hookStop();
+ return NULL;
+ }
+
+ if (!libconfig->setting_lookup_string(cs, "Name", &str) || !*str) {
+ ShowWarning("quest_read_db_sub: Missing Name in quest %d of \"%s\", skipping.\n", quest_id, source);
+ hookStop();
+ return NULL;
+ }
+
+ CREATE(entry, struct quest_db, 1);
+ entry->id = quest_id;
+ //safestrncpy(entry->name, str, sizeof(entry->name));
+
+ if (libconfig->setting_lookup_int(cs, "TimeLimit", &i32)) // This is an unsigned value, do not check for >= 0
+ entry->time = (unsigned int)i32;
+
+ if ((t=libconfig->setting_get_member(cs, "Targets")) && config_setting_is_list(t)) {
+/*
+ int i, len = libconfig->setting_length(t);
+ for (i = 0; i < len && entry->objectives_count < MAX_QUEST_OBJECTIVES; i++) {
+ // Note: We ensure that objectives_count < MAX_QUEST_OBJECTIVES because
+ // quest_log (as well as the client) expect this maximum size.
+ config_setting_t *tt = libconfig->setting_get_elem(t, i);
+ int mob_id = 0, count = 0;
+ if (!tt)
+ break;
+ if (!config_setting_is_group(tt))
+ continue;
+ if (!libconfig->setting_lookup_int(tt, "MobId", &mob_id) || mob_id <= 0)
+ continue;
+ if (!libconfig->setting_lookup_int(tt, "Count", &count) || count <= 0)
+ continue;
+ RECREATE(entry->objectives, struct quest_objective, ++entry->objectives_count);
+ entry->objectives[entry->objectives_count-1].mob = mob_id;
+ entry->objectives[entry->objectives_count-1].count = count;
+ }
+*/
+ entry->objectives_count = 1;
+ RECREATE(entry->objectives, struct quest_objective, 1);
+ entry->objectives[0].mob = 1;
+ entry->objectives[0].count = 0;
+ }
+
+ if ((t=libconfig->setting_get_member(cs, "Drops")) && config_setting_is_list(t)) {
+ int i, len = libconfig->setting_length(t);
+ for (i = 0; i < len; i++) {
+ config_setting_t *tt = libconfig->setting_get_elem(t, i);
+ int mob_id = 0, nameid = 0, rate = 0;
+ if (!tt)
+ break;
+ if (!config_setting_is_group(tt))
+ continue;
+ if (!libconfig->setting_lookup_int(tt, "MobId", &mob_id))
+ mob_id = 0; // Zero = any monster
+ if (mob_id < 0)
+ continue;
+ if (!libconfig->setting_lookup_int(tt, "ItemId", &nameid) || !itemdb->exists(nameid))
+ continue;
+ if (!libconfig->setting_lookup_int(tt, "Rate", &rate) || rate <= 0)
+ continue;
+ RECREATE(entry->dropitem, struct quest_dropitem, ++entry->dropitem_count);
+ entry->dropitem[entry->dropitem_count-1].mob_id = mob_id;
+ entry->dropitem[entry->dropitem_count-1].nameid = nameid;
+ entry->dropitem[entry->dropitem_count-1].rate = rate;
+ }
+ }
+ hookStop();
+ return entry;
+}
diff --git a/src/emap/quest.h b/src/emap/quest.h
new file mode 100644
index 0000000..c947bcc
--- /dev/null
+++ b/src/emap/quest.h
@@ -0,0 +1,9 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_QUEST
+#define EVOL_MAP_QUEST
+
+struct quest_db *equest_read_db_sub(config_setting_t *cs, int *nPtr, const char *source);
+
+#endif // EVOL_MAP_QUEST
diff --git a/src/emap/script.c b/src/emap/script.c
new file mode 100644
index 0000000..d492430
--- /dev/null
+++ b/src/emap/script.c
@@ -0,0 +1,1148 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "common/timer.h"
+#include "map/chrif.h"
+#include "map/clif.h"
+#include "map/npc.h"
+#include "map/pc.h"
+#include "map/script.h"
+#include "map/quest.h"
+#include "map/unit.h"
+
+#include "emap/script.h"
+#include "emap/clif.h"
+#include "emap/lang.h"
+#include "emap/scriptdefines.h"
+#include "emap/send.h"
+#include "emap/data/mapd.h"
+#include "emap/data/npcd.h"
+#include "emap/data/session.h"
+#include "emap/struct/mapdext.h"
+#include "emap/struct/npcdext.h"
+#include "emap/struct/sessionext.h"
+#include "emap/utils/formatutils.h"
+
+BUILDIN(l)
+{
+ format_sub(st, 1);
+ return true;
+}
+
+BUILDIN(lg)
+{
+ format_sub(st, 2);
+ return true;
+}
+
+BUILDIN(setCamNpc)
+{
+ getSD();
+ TBL_NPC *nd = NULL;
+
+ int x = 0;
+ int y = 0;
+
+ if (script_hasdata(st, 2))
+ {
+ nd = npc->name2id (script_getstr(st, 2));
+ }
+ else
+ {
+ if (!st->oid)
+ {
+ ShowWarning("npc not attached\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ nd = (TBL_NPC *) map->id2bl (st->oid);
+ }
+ if (!nd)
+ {
+ ShowWarning("npc not found\n");
+ script->reportsrc(st);
+ return false;
+ }
+ if (sd->bl.m != nd->bl.m)
+ {
+ ShowWarning("npc and player located in other maps\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ if (script_hasdata(st, 3) && script_hasdata(st, 4))
+ {
+ x = script_getnum(st, 3);
+ y = script_getnum(st, 4);
+ }
+
+ send_npccommand2(script->rid2sd (st), st->oid, 2, nd->bl.id, x, y);
+
+ return true;
+}
+
+BUILDIN(setCam)
+{
+ send_npccommand2(script->rid2sd (st), st->oid, 2, 0,
+ script_getnum(st, 2), script_getnum(st, 3));
+
+ return true;
+}
+
+BUILDIN(moveCam)
+{
+ send_npccommand2(script->rid2sd (st), st->oid, 4, 0,
+ script_getnum(st, 2), script_getnum(st, 3));
+
+ return true;
+}
+
+BUILDIN(restoreCam)
+{
+ getSD();
+ send_npccommand(sd, st->oid, 3);
+ return true;
+}
+
+BUILDIN(npcTalk3)
+{
+ const char *str;
+ char *msg;
+ TBL_NPC *nd = NULL;
+
+ getSD();
+
+ if (script_hasdata(st, 3))
+ {
+ nd = npc->name2id (script_getstr(st, 2));
+ str = script_getstr(st, 3);
+ }
+ else
+ {
+ nd = (TBL_NPC *) map->id2bl (st->oid);
+ str = script_getstr(st, 2);
+ }
+
+ if (!nd)
+ {
+ ShowWarning("npc not found\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ if (!str)
+ {
+ ShowWarning("error in string\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ if (sd)
+ msg = (char*)lang_pctrans (nd->name, sd);
+ else
+ msg = nd->name;
+
+ if (!msg)
+ {
+ ShowWarning("error in string\n");
+ script->reportsrc(st);
+ return false;
+ }
+ if (strlen(str) + strlen(msg) > 450)
+ {
+ ShowWarning("text message too big\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ if (nd)
+ {
+ char message[500];
+ char name[500];
+ strcpy (name, msg);
+ strtok(name, "#");
+ strcpy (message, name);
+ strcat (message, " : ");
+ strcat (message, str);
+ send_local_message (sd->fd, &(nd->bl), message);
+ }
+
+ return true;
+}
+
+BUILDIN(closeDialog)
+{
+ getSD();
+ send_npccommand(script->rid2sd (st), st->oid, 5);
+ return true;
+}
+
+BUILDIN(shop)
+{
+ getSD();
+ TBL_NPC *nd = npc->name2id (script_getstr(st, 2));
+ if (!nd)
+ {
+ ShowWarning("shop npc not found\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ st->state = sd->state.dialog == 1 ? CLOSE : END;
+ clif->scriptclose(sd, st->oid);
+
+ clif->npcbuysell (sd, nd->bl.id);
+ return true;
+}
+
+BUILDIN(getItemLink)
+{
+ struct item_data *i_data;
+ char *item_name;
+ int item_id = 0;
+
+ if (script_isstringtype(st, 2))
+ {
+ i_data = itemdb->search_name (script_getstr(st, 2));
+ }
+ else
+ {
+ item_id = script_getnum (st, 2);
+ i_data = itemdb->search (item_id);
+ }
+
+ item_name = (char *) aCalloc (100, sizeof (char));
+ TBL_PC *sd = script->rid2sd(st);
+
+ if (sd)
+ {
+ int version = 0;
+ struct SessionExt *data = session_get_bysd(sd);
+ if (data)
+ version = data->clientVersion;
+
+ if (i_data && version >= 7)
+ sprintf(item_name, "[@@%u|@@]", (unsigned)i_data->nameid);
+ else if (i_data)
+ sprintf(item_name, "[@@%u|%s@@]", (unsigned)i_data->nameid, lang_pctrans (i_data->jname, sd));
+ else if (item_id > 0)
+ sprintf(item_name, "[@@%u|Unknown Item@@]", (unsigned)item_id);
+ else
+ sprintf(item_name, "[Unknown Item]");
+ }
+ else
+ {
+ if (i_data)
+ sprintf(item_name, "[%s]", lang_pctrans (i_data->jname, sd));
+ else
+ sprintf(item_name, "[Unknown Item]");
+ }
+
+ script_pushstr(st, item_name);
+
+ return true;
+}
+
+BUILDIN(requestLang)
+{
+ getSD();
+ struct script_data* data;
+ int64 uid;
+ const char* name;
+
+ data = script_getdata(st, 2);
+ if (!data_isreference(data))
+ {
+ ShowError("script:requestlang: not a variable\n");
+ script->reportsrc(st);
+ st->state = END;
+ return false;
+ }
+ uid = reference_getuid(data);
+ name = reference_getname(data);
+
+ if (is_string_variable(name))
+ {
+ ShowError("script:requestlang: not a variable\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ if (!sd->state.menu_or_input)
+ {
+ // first invocation, display npc input box
+ sd->state.menu_or_input = 1;
+ st->state = RERUNLINE;
+
+ // send lang request
+ send_npccommand(script->rid2sd(st), st->oid, 0);
+ clif->scriptinputstr(sd, st->oid);
+ }
+ else
+ {
+ // take received text/value and store it in the designated variable
+ sd->state.menu_or_input = 0;
+
+ int lng = -1;
+ if (*sd->npc_str)
+ lng = lang_getId(sd->npc_str);
+ script->set_reg(st, sd, uid, name, (void*)h64BPTRSIZE(lng), script_getref(st,2));
+ st->state = RUN;
+ }
+ return true;
+}
+
+BUILDIN(requestItem)
+{
+ getSD();
+ struct script_data* data;
+ int64 uid;
+ const char* name;
+
+ data = script_getdata(st, 2);
+ if (!data_isreference(data))
+ {
+ ShowError("script:requestitem: not a variable\n");
+ script->reportsrc(st);
+ st->state = END;
+ return false;
+ }
+ uid = reference_getuid(data);
+ name = reference_getname(data);
+
+ if (is_string_variable(name))
+ {
+ ShowError("script:requestlang: not a variable\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ if (!sd->state.menu_or_input)
+ {
+ // first invocation, display npc input box
+ sd->state.menu_or_input = 1;
+ st->state = RERUNLINE;
+
+ // send item request
+ send_npccommand(script->rid2sd(st), st->oid, 10);
+ }
+ else
+ {
+ // take received text/value and store it in the designated variable
+ sd->state.menu_or_input = 0;
+
+ int item = 0;
+
+ if (!sd->npc_str)
+ {
+ ShowWarning("npc string not found\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ if (sscanf (sd->npc_str, "%5d", &item) < 1)
+ {
+ ShowWarning("input data is not item id\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ script->set_reg(st, sd, uid, name, (void*)h64BPTRSIZE(item), script_getref(st,2));
+ st->state = RUN;
+ }
+ return true;
+}
+
+BUILDIN(requestItems)
+{
+ getSD();
+ struct script_data* data;
+ int64 uid;
+ const char* name;
+
+ data = script_getdata(st, 2);
+ if (!data_isreference(data))
+ {
+ ShowError("script:requestitem: not a variable\n");
+ script->reportsrc(st);
+ st->state = END;
+ return false;
+ }
+ uid = reference_getuid(data);
+ name = reference_getname(data);
+
+ if (!is_string_variable(name))
+ {
+ ShowWarning("parameter is not variable\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ int count = 1;
+
+ if (script_hasdata(st, 3))
+ {
+ count = script_getnum(st, 3);
+ if (count < 0)
+ count = 1;
+ }
+
+ if (!sd->state.menu_or_input)
+ {
+ // first invocation, display npc input box
+ sd->state.menu_or_input = 1;
+ st->state = RERUNLINE;
+
+ // send item request with limit count
+ send_npccommand2(script->rid2sd (st), st->oid, 10, count, 0, 0);
+ }
+ else
+ {
+ // take received text/value and store it in the designated variable
+ sd->state.menu_or_input = 0;
+
+ if (!sd->npc_str)
+ {
+ ShowWarning("npc string not found\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ script->set_reg(st, sd, uid, name, (void*)sd->npc_str, script_getref(st, 2));
+ st->state = RUN;
+ }
+ return true;
+}
+
+BUILDIN(setq)
+{
+ int i;
+ getSD();
+
+ int quest_id = script_getnum(st, 2);
+ int quest_value = script_getnum(st, 3);
+
+ if (quest->check(sd, quest_id, HAVEQUEST) < 0)
+ quest->add(sd, quest_id);
+ ARR_FIND(0, sd->num_quests, i, sd->quest_log[i].quest_id == quest_id);
+ if (i == sd->num_quests)
+ {
+ ShowError("Quest with id=%d not found\n", quest_id);
+ script->reportsrc(st);
+ return false;
+ }
+
+ sd->quest_log[i].count[0] = quest_value;
+ sd->save_quest = true;
+ if (map->save_settings & 64)
+ chrif->save(sd,0);
+
+ eclif_quest_add(sd, &sd->quest_log[i]);
+ return true;
+}
+
+BUILDIN(getq)
+{
+ int i;
+ getSDReturn(0);
+
+ int quest_id = script_getnum(st, 2);
+ if (quest->check(sd, quest_id, HAVEQUEST) < 0)
+ {
+ script_pushint(st, 0);
+ return true;
+ }
+ ARR_FIND(0, sd->num_quests, i, sd->quest_log[i].quest_id == quest_id);
+ if (i == sd->num_quests)
+ {
+ script_pushint(st, 0);
+ return true;
+ }
+ script_pushint(st, sd->quest_log[i].count[0]);
+ return true;
+}
+
+BUILDIN(setNpcDir)
+{
+ int newdir;
+ TBL_NPC *nd = 0;
+
+ if (script_hasdata(st, 3))
+ {
+ nd = npc->name2id (script_getstr(st, 2));
+ newdir = script_getnum(st, 3);
+ }
+ else if (script_hasdata(st, 2))
+ {
+ if (!st->oid)
+ {
+ ShowWarning("npc not found\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ nd = (TBL_NPC *) map->id2bl (st->oid);
+ newdir = script_getnum(st, 2);
+ }
+ if (!nd)
+ {
+ ShowWarning("npc not found\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ if (newdir < 0)
+ newdir = 0;
+ else if (newdir > 7)
+ newdir = 7;
+
+ nd->dir = newdir;
+ npc->enable (nd->name, 1);
+
+ return true;
+}
+
+BUILDIN(rif)
+{
+ const char *str = 0;
+ if (script_getnum(st, 2))
+ {
+ str = script_getstr(st, 3);
+ if (str)
+ script_pushstr(st, aStrdup(str));
+ else
+ script_pushconststr(st, (char *)"");
+ }
+ else if (script_hasdata(st, 4))
+ {
+ str = script_getstr(st, 4);
+ if (str)
+ script_pushstr(st, aStrdup(str));
+ else
+ script_pushconststr(st, (char *)"");
+ }
+ else
+ {
+ script_pushconststr(st, (char *)"");
+ }
+
+ return true;
+}
+
+BUILDIN(countItemColor)
+{
+ int nameid, i;
+ int count = 0;
+ struct item_data* id = NULL;
+
+ TBL_PC* sd = script->rid2sd(st);
+ if (!sd)
+ {
+ ShowWarning("player not attached\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ if (script_isstringtype(st, 2))
+ {
+ // item name
+ id = itemdb->search_name(script_getstr(st, 2));
+ }
+ else
+ {
+ // item id
+ id = itemdb->exists(script_getnum(st, 2));
+ }
+
+ if (id == NULL)
+ {
+ ShowError("buildin_countitem: Invalid item '%s'.\n", script_getstr(st,2)); // returns string, regardless of what it was
+ script->reportsrc(st);
+ script_pushint(st,0);
+ return false;
+ }
+
+ nameid = id->nameid;
+
+ for(i = 0; i < MAX_INVENTORY; i++)
+ {
+ if(sd->status.inventory[i].nameid == nameid)
+ count += sd->status.inventory[i].amount;
+ }
+
+ script_pushint(st, count);
+ return true;
+}
+
+BUILDIN(miscEffect)
+{
+ int type = script_getnum(st, 2);
+ struct block_list *bl = NULL;
+
+ if (script_hasdata(st, 3))
+ {
+ if (script_isstring(st, 3))
+ {
+ TBL_PC *sd = map->nick2sd(script_getstr(st, 3));
+ if (sd)
+ bl = &sd->bl;
+ }
+ else if (script_isint(st, 3))
+ {
+ bl = map->id2bl(script_getnum(st, 3));
+ }
+ }
+
+ if (!bl)
+ {
+ TBL_PC *sd = script->rid2sd (st);
+ if (sd)
+ bl = &sd->bl;
+ }
+ if (bl)
+ clif->specialeffect(bl, type, AREA);
+ return true;
+}
+
+BUILDIN(setMapMask)
+{
+ const char *const mapName = script_getstr(st, 2);
+ if (!mapName)
+ {
+ ShowWarning("invalid map name\n");
+ script->reportsrc(st);
+ return false;
+ }
+ const int m = map->mapname2mapid(mapName);
+ if (m < 0)
+ {
+ ShowWarning("map not found\n");
+ script->reportsrc(st);
+ return false;
+ }
+ getMapData(m);
+
+ const int val = script_getnum(st, 3);
+ const unsigned int old = mapData->mask;
+ mapData->mask = val;
+ if (old != mapData->mask)
+ send_mapmask_brodcast(m, mapData->mask);
+ return true;
+}
+
+BUILDIN(getMapMask)
+{
+ const char *const mapName = script_getstr(st, 2);
+ if (!mapName)
+ {
+ script_pushint(st, 0);
+ ShowWarning("invalid map name\n");
+ script->reportsrc(st);
+ return false;
+ }
+ const int m = map->mapname2mapid(mapName);
+ if (m < 0)
+ {
+ script_pushint(st, 0);
+ ShowWarning("map not found\n");
+ script->reportsrc(st);
+ return false;
+ }
+ getMapDataReturn(m, 0);
+ script_pushint(st, mapData->mask);
+ return true;
+}
+
+BUILDIN(addMapMask)
+{
+ const char *const mapName = script_getstr(st, 2);
+ if (!mapName)
+ {
+ ShowWarning("invalid map name\n");
+ script->reportsrc(st);
+ return false;
+ }
+ const int m = map->mapname2mapid(mapName);
+ if (m < 0)
+ {
+ ShowWarning("map not found\n");
+ script->reportsrc(st);
+ return false;
+ }
+ getMapData(m);
+ const int val = script_getnum(st, 3);
+ const unsigned int old = mapData->mask;
+ mapData->mask |= val;
+ if (old != mapData->mask)
+ send_mapmask_brodcast(m, mapData->mask);
+
+ return true;
+}
+
+BUILDIN(removeMapMask)
+{
+ const char *const mapName = script_getstr(st, 2);
+ if (!mapName)
+ {
+ ShowWarning("invalid map name\n");
+ script->reportsrc(st);
+ return true;
+ }
+ const int m = map->mapname2mapid(mapName);
+ if (m < 0)
+ {
+ ShowWarning("map not found\n");
+ script->reportsrc(st);
+ return false;
+ }
+ getMapData(m);
+ const int val = script_getnum(st, 3);
+ const unsigned int old = mapData->mask;
+ mapData->mask |= val;
+ mapData->mask ^= val;
+ if (old != mapData->mask)
+ send_mapmask_brodcast(m, mapData->mask);
+ return true;
+}
+
+BUILDIN(setNpcSex)
+{
+ TBL_NPC *nd = NULL;
+ int sex = 0;
+ if (script_hasdata(st, 3))
+ {
+ nd = npc->name2id (script_getstr(st, 2));
+ sex = script_getnum(st, 3);
+ }
+ else if (script_hasdata(st, 2))
+ {
+ sex = script_getnum(st, 2);
+ }
+ else
+ {
+ ShowWarning("no parameters provided\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ if (!nd && !st->oid)
+ {
+ ShowWarning("npc not found\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ if (!nd)
+ nd = (TBL_NPC *) map->id2bl(st->oid);
+
+ if (!nd || !nd->vd)
+ {
+ ShowWarning("npc not found\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ clif->clearunit_area(&nd->bl, CLR_OUTSIGHT);
+ nd->vd->sex = sex;
+ clif->spawn(&nd->bl);
+ return true;
+}
+
+BUILDIN(showAvatar)
+{
+ int id = 0;
+ if (script_hasdata(st, 2))
+ id = script_getnum(st, 2);
+
+ send_npccommand2(script->rid2sd (st), st->oid, 6, id, 0, 0);
+ return true;
+}
+
+BUILDIN(setAvatarDir)
+{
+ int newdir = script_getnum(st, 2);
+
+ if (newdir < 0)
+ newdir = 0;
+ else if (newdir > 7)
+ newdir = 7;
+
+ send_npccommand2(script->rid2sd (st), st->oid, 7, newdir, 0, 0);
+ return true;
+}
+
+BUILDIN(setAvatarAction)
+{
+ send_npccommand2(script->rid2sd (st), st->oid, 8, script_getnum(st, 2), 0, 0);
+ return true;
+}
+
+BUILDIN(clear)
+{
+ send_npccommand(script->rid2sd (st), st->oid, 9);
+ return true;
+}
+
+BUILDIN(changeMusic)
+{
+ const char *const mapName = script_getstr(st, 2);
+ const char *const music = script_getstr(st, 3);
+ if (!music)
+ {
+ ShowWarning("invalid music file\n");
+ script->reportsrc(st);
+ return false;
+ }
+ if (!mapName)
+ {
+ ShowWarning("invalid map file\n");
+ script->reportsrc(st);
+ return false;
+ }
+ const int m = map->mapname2mapid(mapName);
+ if (m < 0)
+ {
+ ShowWarning("map not found\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ send_changemusic_brodcast(m, music);
+ return true;
+}
+
+BUILDIN(setNpcDialogTitle)
+{
+ const char *const name = script_getstr(st, 2);
+ if (!name)
+ {
+ ShowWarning("invalid window title\n");
+ script->reportsrc(st);
+ return false;
+ }
+ TBL_PC *sd = script->rid2sd (st);
+ if (!sd)
+ {
+ ShowWarning("player not attached\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ send_changenpc_title(sd, st->oid, name);
+ return true;
+}
+
+BUILDIN(getMapName)
+{
+ TBL_PC *sd = script->rid2sd(st);
+ if (!sd)
+ {
+ script_pushstr(st, aStrdup(""));
+ ShowWarning("player not attached\n");
+ script->reportsrc(st);
+ return false;
+ }
+ if (sd->bl.m == -1)
+ {
+ script_pushstr(st, aStrdup(""));
+ ShowWarning("invalid map\n");
+ script->reportsrc(st);
+ return false;
+ }
+ script_pushstr(st, aStrdup(map->list[sd->bl.m].name));
+ return true;
+}
+
+BUILDIN(unequipById)
+{
+ int nameid = 0;
+ int i;
+ struct item_data *item_data;
+ TBL_PC *sd = script->rid2sd(st);
+
+ if (sd == NULL)
+ {
+ ShowWarning("player not attached\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ nameid = script_getnum(st, 2);
+ if((item_data = itemdb->exists(nameid)) == NULL)
+ {
+ ShowWarning("item %d not found\n", nameid);
+ script->reportsrc(st);
+ return false;
+ }
+ for (i = 0; i < EQI_MAX; i++)
+ {
+ const int idx = sd->equip_index[i];
+ if (idx >= 0)
+ {
+ if (sd->status.inventory[idx].nameid == nameid)
+ pc->unequipitem(sd, idx, 1 | 2);
+ }
+ }
+ return true;
+}
+
+BUILDIN(isPcDead)
+{
+ TBL_PC *sd = script->rid2sd(st);
+
+ if (sd == NULL)
+ {
+ ShowWarning("player not attached\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ script_pushint(st, pc_isdead(sd) ? 1 : 0);
+ return true;
+}
+
+static int areatimer_sub(struct block_list *bl, va_list ap)
+{
+ int tick;
+ char *event;
+ TBL_PC *sd;
+
+ tick = va_arg(ap, int);
+ event = va_arg(ap, char*);
+
+ sd = (TBL_PC *)bl;
+ if (!pc->addeventtimer(sd, tick, event))
+ {
+ if (sd)
+ ShowWarning("buildin_addtimer: Event timer is full, can't add new event timer. (cid:%d timer:%s)\n", sd->status.char_id, event);
+ }
+ return 0;
+}
+
+BUILDIN(areaTimer)
+{
+ const char *const mapname = script_getstr(st, 2);
+ const int x1 = script_getnum(st, 3);
+ const int y1 = script_getnum(st, 4);
+ const int x2 = script_getnum(st, 5);
+ const int y2 = script_getnum(st, 6);
+ const int time = script_getnum(st, 7);
+ const char *const eventName = script_getstr(st, 8);
+ int m;
+
+ if ((m = map->mapname2mapid(mapname)) < 0)
+ {
+ ShowWarning("map not found\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ map->foreachinarea(areatimer_sub, m, x1, y1, x2, y2, BL_PC, time, eventName);
+
+ return true;
+}
+
+static int buildin_getareadropitem_sub_del(struct block_list *bl, va_list ap)
+{
+ if (!bl)
+ return 0;
+
+ const int item = va_arg(ap, int);
+ int *const amount = va_arg(ap, int *);
+ TBL_ITEM *drop = (TBL_ITEM *)bl;
+
+ if (drop->item_data.nameid == item)
+ {
+ (*amount) += drop->item_data.amount;
+ map->clearflooritem(&drop->bl);
+ }
+
+ return 0;
+}
+
+BUILDIN(getAreaDropItem)
+{
+ const char *const str = script_getstr(st, 2);
+ int16 m;
+ int x0 = script_getnum(st, 3);
+ int y0 = script_getnum(st, 4);
+ int x1 = script_getnum(st, 5);
+ int y1 = script_getnum(st, 6);
+ int item;
+ int amount = 0;
+
+ if (script_isstringtype(st, 7))
+ {
+ const char *name = script_getstr(st, 7);
+ struct item_data *item_data = itemdb->search_name(name);
+ item = UNKNOWN_ITEM_ID;
+ if (item_data)
+ item = item_data->nameid;
+ }
+ else
+ {
+ item = script_getnum(st, 7);
+ }
+
+ if ((m = map->mapname2mapid(str)) < 0)
+ {
+ script_pushint(st, -1);
+ ShowWarning("map not found\n");
+ script->reportsrc(st);
+ return false;
+ }
+
+ if (script_hasdata(st, 8) && script_getnum(st, 8))
+ {
+ map->foreachinarea(buildin_getareadropitem_sub_del,
+ m, x0, y0, x1, y1, BL_ITEM, item, &amount);
+ }
+ else
+ {
+ map->foreachinarea(script->buildin_getareadropitem_sub,
+ m, x0, y0, x1, y1, BL_ITEM, item, &amount);
+ }
+ script_pushint(st, amount);
+ return true;
+}
+
+enum setmount_type
+{
+ SETMOUNT_TYPE_NONE = 0,
+ SETMOUNT_TYPE_PECO = 1,
+ SETMOUNT_TYPE_WUG = 2,
+ SETMOUNT_TYPE_MADO = 3,
+ SETMOUNT_TYPE_DRAGON_GREEN = 4,
+ SETMOUNT_TYPE_DRAGON_BROWN = 5,
+ SETMOUNT_TYPE_DRAGON_GRAY = 6,
+ SETMOUNT_TYPE_DRAGON_BLUE = 7,
+ SETMOUNT_TYPE_DRAGON_RED = 8,
+ SETMOUNT_TYPE_MAX,
+ SETMOUNT_TYPE_DRAGON = SETMOUNT_TYPE_DRAGON_GREEN,
+};
+
+BUILDIN(setMount)
+{
+ int flag = SETMOUNT_TYPE_NONE;
+ TBL_PC* sd = script->rid2sd(st);
+
+ if (sd == NULL)
+ return true; // no player attached, report source
+
+ if (script_hasdata(st, 2))
+ flag = script_getnum(st, 2);
+
+ // Sanity checks and auto-detection
+ if (flag >= SETMOUNT_TYPE_DRAGON_GREEN && flag <= SETMOUNT_TYPE_DRAGON_RED)
+ {
+ if (pc->checkskill(sd, RK_DRAGONTRAINING))
+ {
+ // Rune Knight (Dragon)
+ unsigned int option;
+ option = ( flag == SETMOUNT_TYPE_DRAGON_GREEN ? OPTION_DRAGON1 :
+ flag == SETMOUNT_TYPE_DRAGON_BROWN ? OPTION_DRAGON2 :
+ flag == SETMOUNT_TYPE_DRAGON_GRAY ? OPTION_DRAGON3 :
+ flag == SETMOUNT_TYPE_DRAGON_BLUE ? OPTION_DRAGON4 :
+ flag == SETMOUNT_TYPE_DRAGON_RED ? OPTION_DRAGON5 :
+ OPTION_DRAGON1); // default value
+ pc->setridingdragon(sd, option);
+ }
+ }
+ else if (flag == SETMOUNT_TYPE_WUG)
+ {
+ // Ranger (Warg)
+ if (pc->checkskill(sd, RA_WUGRIDER))
+ pc->setridingwug(sd, true);
+ }
+ else if (flag == SETMOUNT_TYPE_MADO)
+ {
+ // Mechanic (Mado Gear)
+ if (pc->checkskill(sd, NC_MADOLICENCE))
+ pc->setmadogear(sd, true);
+ }
+ else if (flag == SETMOUNT_TYPE_PECO)
+ {
+ // Knight / Crusader (Peco Peco)
+ if (pc->checkskill(sd, KN_RIDING))
+ pc->setridingpeco(sd, true);
+ }
+ else if (flag == SETMOUNT_TYPE_NONE && pc_hasmount(sd))
+ {
+ if (pc_isridingdragon(sd))
+ {
+ pc->setridingdragon(sd, 0);
+ }
+ if (pc_isridingwug(sd))
+ {
+ pc->setridingwug(sd, false);
+ }
+ if (pc_ismadogear(sd))
+ {
+ pc->setmadogear(sd, false);
+ }
+ if (pc_isridingpeco(sd))
+ {
+ pc->setridingpeco(sd, false);
+ }
+ }
+
+ return true;
+}
+
+BUILDIN(clientCommand)
+{
+ TBL_PC* sd = script->rid2sd(st);
+
+ if (sd == NULL)
+ {
+ ShowWarning("player not attached\n");
+ script->reportsrc(st);
+ return false;
+ }
+ const char *const command = script_getstr(st, 2);
+ if (!command)
+ {
+ ShowWarning("invalid client command\n");
+ script->reportsrc(st);
+ return false;
+ }
+ send_client_command(sd, command);
+ return true;
+}
+
+BUILDIN(isUnitWalking)
+{
+ int id = 0;
+ if (script_hasdata(st, 2))
+ id = script_getnum(st, 2);
+ else
+ id = st->oid;
+ struct block_list *bl = map->id2bl(id);
+ if (!bl)
+ {
+ ShowWarning("invalid unit id\n");
+ script->reportsrc(st);
+ script_pushint(st, 0);
+ return false;
+ }
+ struct unit_data *ud = unit->bl2ud(bl);
+ if (!ud)
+ {
+ ShowWarning("invalid unit data\n");
+ script->reportsrc(st);
+ script_pushint(st, 0);
+ return false;
+ }
+ script_pushint(st, ud->walktimer != INVALID_TIMER);
+ return true;
+}
diff --git a/src/emap/script.h b/src/emap/script.h
new file mode 100644
index 0000000..41c96ee
--- /dev/null
+++ b/src/emap/script.h
@@ -0,0 +1,46 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_SCRIPT
+#define EVOL_MAP_SCRIPT
+
+BUILDIN(l);
+BUILDIN(lg);
+BUILDIN(setCamNpc);
+BUILDIN(setCam);
+BUILDIN(moveCam);
+BUILDIN(restoreCam);
+BUILDIN(npcTalk3);
+BUILDIN(closeDialog);
+BUILDIN(shop);
+BUILDIN(getItemLink);
+BUILDIN(requestLang);
+BUILDIN(requestItem);
+BUILDIN(requestItems);
+BUILDIN(getq);
+BUILDIN(setq);
+BUILDIN(setNpcDir);
+BUILDIN(rif);
+BUILDIN(countItemColor);
+BUILDIN(miscEffect);
+BUILDIN(setMapMask);
+BUILDIN(getMapMask);
+BUILDIN(addMapMask);
+BUILDIN(removeMapMask);
+BUILDIN(setNpcSex);
+BUILDIN(showAvatar);
+BUILDIN(setAvatarDir);
+BUILDIN(setAvatarAction);
+BUILDIN(clear);
+BUILDIN(changeMusic);
+BUILDIN(setNpcDialogTitle);
+BUILDIN(getMapName);
+BUILDIN(unequipById);
+BUILDIN(isPcDead);
+BUILDIN(areaTimer);
+BUILDIN(getAreaDropItem);
+BUILDIN(setMount);
+BUILDIN(clientCommand);
+BUILDIN(isUnitWalking);
+
+#endif // EVOL_MAP_SCRIPT
diff --git a/src/emap/scriptdefines.h b/src/emap/scriptdefines.h
new file mode 100644
index 0000000..1a6cf14
--- /dev/null
+++ b/src/emap/scriptdefines.h
@@ -0,0 +1,55 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_SCRIPTDEFINES
+#define EVOL_MAP_SCRIPTDEFINES
+
+#define getSessionDataReturn(def) \
+ if (!st->rid) \
+ { \
+ script_pushint(st, def); \
+ return true; \
+ } \
+ TBL_PC *sd = script->rid2sd(st); \
+ if (!sd) \
+ { \
+ script_pushint(st, def); \
+ return true; \
+ } \
+ struct SessionExt *data = session_get(sd->fd)
+
+#define getSessionData() \
+ if (!st->rid) \
+ return true; \
+ TBL_PC *sd = script->rid2sd(st); \
+ if (!sd) \
+ return true; \
+ struct SessionExt *data = session_get(sd->fd)
+
+#define getMapData(m) \
+ struct MapdExt *mapData = mapd_get(m); \
+ if (!mapData) \
+ return true;
+
+#define getMapDataReturn(m, def) \
+ struct MapdExt *mapData = mapd_get(m); \
+ if (!mapData) \
+ { \
+ script_pushint(st, def); \
+ return true; \
+ }
+
+#define getSD() \
+ TBL_PC *sd = script->rid2sd(st); \
+ if (!sd) \
+ return true
+
+#define getSDReturn(def) \
+ TBL_PC *sd = script->rid2sd(st); \
+ if (!sd) \
+ { \
+ script_pushint(st, def); \
+ return true; \
+ }
+
+#endif // EVOL_MAP_SCRIPTDEFINES
diff --git a/src/emap/send.c b/src/emap/send.c
new file mode 100644
index 0000000..6f3f257
--- /dev/null
+++ b/src/emap/send.c
@@ -0,0 +1,305 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "map/clif.h"
+#include "map/mob.h"
+#include "map/npc.h"
+#include "map/pc.h"
+#include "map/pet.h"
+#include "map/unit.h"
+
+#include "emap/send.h"
+#include "emap/permission.h"
+#include "emap/data/session.h"
+#include "emap/struct/sessionext.h"
+
+void send_npccommand (TBL_PC *sd, int npcId, int cmd)
+{
+ if (!sd)
+ return;
+
+ int fd = sd->fd;
+ WFIFOHEAD (fd, 16);
+ WFIFOW (fd, 0) = 0xB00;
+ WFIFOL (fd, 2) = npcId;
+ WFIFOW (fd, 6) = cmd;
+ WFIFOL (fd, 8) = 0;
+ WFIFOW (fd, 12) = 0;
+ WFIFOW (fd, 14) = 0;
+ WFIFOSET (fd, 16);
+}
+
+// 0 - get client lang
+void send_npccommand2 (TBL_PC *sd, int npcId, int cmd, int id, int x, int y)
+{
+ if (!sd)
+ return;
+
+ int fd = sd->fd;
+ WFIFOHEAD (fd, 16);
+ WFIFOW (fd, 0) = 0xB00;
+ WFIFOL (fd, 2) = npcId;
+ WFIFOW (fd, 6) = cmd;
+ WFIFOL (fd, 8) = id;
+ WFIFOW (fd, 12) = x;
+ WFIFOW (fd, 14) = y;
+ WFIFOSET (fd, 16);
+}
+
+void send_local_message(int fd, struct block_list* bl, const char* msg)
+{
+ if (!msg || !bl)
+ return;
+ unsigned short msg_len = strlen(msg) + 1;
+ uint8 buf[256];
+
+ int len = sizeof(buf) - 8;
+ if (msg_len > len)
+ {
+ ShowWarning("clif_message: Truncating too long message '%s' (len=%u).\n", msg, msg_len);
+ msg_len = len;
+ }
+
+ WFIFOHEAD (fd, msg_len + 8);
+ WFIFOW (fd, 0) = 0x8d;
+ WFIFOW (fd, 2) = msg_len + 8;
+ WFIFOL (fd, 4) = bl->id;
+ safestrncpy((char*)WFIFOP(fd, 8), msg, msg_len);
+ WFIFOSET (fd, msg_len + 8);
+}
+
+void send_changelook(int fd, int id, int type, int val)
+{
+ WFIFOHEAD (fd, 11);
+ WFIFOW (fd, 0) = 0x1d7;
+ WFIFOL (fd, 2) = id;
+ WFIFOB (fd, 6) = type;
+ WFIFOW (fd, 7) = val;
+ WFIFOW (fd, 9) = 0;
+ WFIFOSET (fd, 11);
+}
+
+void send_mapmask(int fd, int mask)
+{
+ WFIFOHEAD (fd, 10);
+ WFIFOW (fd, 0) = 0xb02;
+ WFIFOL (fd, 2) = mask;
+ WFIFOL (fd, 6) = 0;
+ WFIFOSET (fd, 10);
+}
+
+void send_mapmask_brodcast(const int map, const int mask)
+{
+ struct block_list bl;
+ char buf[10];
+
+ bl.m = map;
+ WBUFW (buf, 0) = 0xb02;
+ WBUFL (buf, 2) = mask;
+ WBUFL (buf, 6) = 0;
+ clif->send(buf, 10, &bl, ALL_SAMEMAP);
+}
+
+void send_mob_info(struct block_list* bl1, struct block_list* bl2,
+ enum send_target target)
+{
+ if (!bl1 || bl1->type != BL_MOB)
+ return;
+
+ char buf[12];
+ TBL_MOB *md = (TBL_MOB *)bl1;
+
+ WBUFW (buf, 0) = 0xb03;
+ WBUFW (buf, 2) = 12; // len
+ WBUFL (buf, 4) = md->bl.id;
+ WBUFL (buf, 8) = md->status.rhw.range;
+
+ clif->send(&buf, sizeof(buf), bl2, target);
+}
+
+void send_pc_info(struct block_list* bl1,
+ struct block_list* bl2,
+ enum send_target target)
+{
+ if (!bl1 || bl1->type != BL_PC)
+ return;
+
+ char buf[12];
+ TBL_PC *sd = (TBL_PC *)bl1;
+ struct SessionExt *data = session_get_bysd(sd);
+ if (!data)
+ return;
+
+ TBL_PC *tsd = (TBL_PC *)bl2;
+ if (tsd)
+ {
+ struct SessionExt *tdata = session_get_bysd(tsd);
+ if (!tdata || tdata->clientVersion < 4)
+ return;
+ }
+
+ WBUFW (buf, 0) = 0xb0a;
+ WBUFW (buf, 2) = 12; // len
+ WBUFL (buf, 4) = sd->bl.id;
+ if (pc_has_permission(sd, permission_send_gm_flag))
+ WBUFL (buf, 8) = sd->group_id;
+ else
+ WBUFL (buf, 8) = 0;
+
+ clif->send(&buf, sizeof(buf), bl2, target);
+}
+
+void send_npc_info(struct block_list* bl1,
+ struct block_list* bl2,
+ enum send_target target)
+{
+ if (!bl1 || bl1->type != BL_NPC)
+ return;
+
+ TBL_PC *tsd = (TBL_PC *)bl2;
+ if (tsd)
+ {
+ struct SessionExt *tdata = session_get_bysd(tsd);
+ if (!tdata || tdata->clientVersion < 5)
+ return;
+ }
+
+ TBL_NPC *const nd = (TBL_NPC*)bl1;
+
+ char buf[12];
+ WBUFW (buf, 0) = 0xb0b;
+ WBUFW (buf, 2) = 12; // len
+ WBUFL (buf, 4) = nd->bl.id;
+ WBUFL (buf, 8) = nd->area_size;
+
+ clif->send(&buf, sizeof(buf), bl2, target);
+}
+
+void send_advmoving(struct unit_data* ud, struct block_list *tbl, enum send_target target)
+{
+ if (!ud)
+ return;
+
+ struct block_list *bl = ud->bl;
+
+ if (ud->walkpath.path_len <= ud->walkpath.path_pos)
+ return;
+ const bool haveMoves = (ud->walkpath.path_len > ud->walkpath.path_pos);
+
+ int i = 14;
+ const int len = ud->walkpath.path_len - ud->walkpath.path_pos;
+ if (haveMoves)
+ i += len;
+
+ char *buf;
+ CREATE(buf, char, i);
+ WBUFW (buf, 0) = 0xb04;
+ WBUFW (buf, 2) = i;
+ WBUFL (buf, 4) = bl->id;
+ WBUFW (buf, 8) = status->get_speed(bl);
+ WBUFW (buf, 10) = bl->x;
+ WBUFW (buf, 12) = bl->y;
+ if (haveMoves)
+ memcpy(buf + 14, ud->walkpath.path + ud->walkpath.path_pos, len);
+ clif->send(buf, i, tbl, target);
+ aFree(buf);
+}
+
+void send_changemusic_brodcast(const int map, const char *music)
+{
+ if (!music)
+ return;
+
+ struct block_list bl;
+ const int sz = strlen (music) + 5;
+ char *buf;
+
+ CREATE(buf, char, sz);
+ bl.m = map;
+ WBUFW (buf, 0) = 0xb05;
+ WBUFW (buf, 2) = sz;
+ strcpy ((char *)WBUFP (buf, 4), music);
+ clif->send (buf, sz, &bl, ALL_SAMEMAP);
+ aFree(buf);
+}
+
+void send_changenpc_title (TBL_PC *sd, const int npcId, const char *name)
+{
+ if (!sd || !name)
+ return;
+
+ const int fd = sd->fd;
+ const int len = strlen (name);
+ const int sz = len + 5 + 4 + 2;
+ WFIFOHEAD (fd, sz);
+ WFIFOW (fd, 0) = 0xb06;
+ WFIFOW (fd, 2) = sz;
+ WFIFOL (fd, 4) = npcId;
+ WFIFOW (fd, 8) = len;
+ strcpy ((char*)WFIFOP (fd, 10), name);
+ WFIFOSET (fd, sz);
+}
+
+void send_join_ack(int fd, const char *const name, int flag)
+{
+ if (!name)
+ return;
+
+ WFIFOHEAD (fd, 27);
+ WFIFOW (fd, 0) = 0xb08;
+ safestrncpy ((char*)WFIFOP (fd, 2), name, 24);
+ WFIFOB (fd, 26) = flag;
+ WFIFOSET (fd, 27);
+}
+
+void send_slave_say(TBL_PC *sd,
+ struct block_list *bl,
+ const char *const name,
+ const char *const message)
+{
+ const int len = 24 + 7 + strlen(message);
+ char *buf = NULL;
+ CREATE(buf, char, len);
+
+ snprintf(buf, len, "%s's %s : %s", sd->status.name, name, message);
+ buf[len - 1] = 0;
+ clif->GlobalMessage(bl, buf);
+ aFree(buf);
+}
+
+void send_online_list(int fd, const char *buf, unsigned size)
+{
+ if (!buf)
+ return;
+ const unsigned int len = size + 4 + 1;
+ WFIFOHEAD (fd, len);
+ WFIFOW (fd, 0) = 0xb10;
+ WFIFOW (fd, 2) = len;
+ memcpy (WFIFOP (fd, 4), buf, size);
+ WFIFOB (fd, size + 4) = 0;
+ WFIFOSET (fd, len);
+}
+
+void send_client_command(TBL_PC *sd, const char *const command)
+{
+ struct SessionExt *data = session_get_bysd(sd);
+ if (!data || data->clientVersion < 8)
+ return;
+
+ const unsigned int len = strlen(command);
+ const int fd = sd->fd;
+ WFIFOHEAD (fd, len);
+ WFIFOW (fd, 0) = 0xb16;
+ WFIFOW (fd, 2) = len + 4;
+ memcpy (WFIFOP (fd, 4), command, len);
+ WFIFOSET (fd, len + 4);
+}
diff --git a/src/emap/send.h b/src/emap/send.h
new file mode 100644
index 0000000..efa89ad
--- /dev/null
+++ b/src/emap/send.h
@@ -0,0 +1,31 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_PC
+#define EVOL_MAP_PC
+
+void send_npccommand (TBL_PC *sd, int npcId, int cmd);
+void send_npccommand2 (TBL_PC *sd, int npcId, int cmd, int id, int x, int y);
+void send_local_message(int fd, struct block_list* bl, const char* msg);
+void send_changelook(int fd, int id, int type, int val);
+void send_mapmask(int fd, int mask);
+void send_mapmask_brodcast(const int map, const int mask);
+void send_mob_info(struct block_list* bl1, struct block_list* bl2, enum send_target target);
+void send_advmoving(struct unit_data* ud, struct block_list *tbl, enum send_target target);
+void send_changemusic_brodcast(const int map, const char *music);
+void send_changenpc_title (TBL_PC *sd, const int npcId, const char *name);
+void send_join_ack(int fd, const char *const name, int flag);
+void send_pc_info(struct block_list* bl1,
+ struct block_list* bl2,
+ enum send_target target);
+void send_npc_info(struct block_list* bl1,
+ struct block_list* bl2,
+ enum send_target target);
+void send_slave_say(TBL_PC *sd,
+ struct block_list *bl,
+ const char *const name,
+ const char *const message);
+void send_online_list(int fd, const char *buf, unsigned size);
+void send_client_command(TBL_PC *sd, const char *const command);
+
+#endif // EVOL_MAP_PC
diff --git a/src/emap/skill.c b/src/emap/skill.c
new file mode 100644
index 0000000..b909feb
--- /dev/null
+++ b/src/emap/skill.c
@@ -0,0 +1,44 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/db.h"
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "common/timer.h"
+#include "map/pc.h"
+#include "map/npc.h"
+#include "map/script.h"
+
+int eskill_check_condition_castend_post(int retVal,
+ TBL_PC* sd,
+ uint16 *skill_id,
+ uint16 *skill_lv)
+{
+ if (retVal && sd)
+ {
+ struct linkdb_node **label_linkdb = strdb_get(npc->ev_label_db, "OnSkillInvoke");
+ if (label_linkdb == NULL)
+ return retVal;
+
+ struct linkdb_node *node = *label_linkdb;
+ while (node)
+ {
+ struct event_data* ev = node->data;
+ if (ev)
+ {
+ pc->setreg(sd, script->add_str("@skillId"), *skill_id);
+ pc->setreg(sd, script->add_str("@skillLv"), *skill_lv);
+ script->run(ev->nd->u.scr.script, ev->pos, sd->bl.id, ev->nd->bl.id);
+ }
+ node = node->next;
+ }
+ }
+ return retVal;
+}
diff --git a/src/emap/skill.h b/src/emap/skill.h
new file mode 100644
index 0000000..132e909
--- /dev/null
+++ b/src/emap/skill.h
@@ -0,0 +1,12 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_SKILL
+#define EVOL_MAP_SKILL
+
+int eskill_check_condition_castend_post(int retVal,
+ TBL_PC* sd,
+ uint16 *skill_id,
+ uint16 *skill_lv);
+
+#endif // EVOL_MAP_SKILL
diff --git a/src/emap/status.c b/src/emap/status.c
new file mode 100644
index 0000000..6f853d5
--- /dev/null
+++ b/src/emap/status.c
@@ -0,0 +1,70 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "map/itemdb.h"
+#include "map/map.h"
+#include "map/npc.h"
+#include "map/pc.h"
+#include "map/status.h"
+
+#include "emap/data/npcd.h"
+#include "emap/struct/npcdext.h"
+
+int class_move_speed[CLASS_COUNT];
+
+void status_init(void)
+{
+ int f;
+ for (f = 0; f < CLASS_COUNT; f ++)
+ class_move_speed[f] = 150;
+}
+
+void estatus_set_viewdata_post(struct block_list *bl,
+ int *class_ __attribute__ ((unused)))
+{
+ if (!bl)
+ return;
+ if (bl->type != BL_NPC)
+ return;
+ TBL_NPC *const npc = (TBL_NPC*)bl;
+ struct NpcdExt *data = npcd_get(npc);
+ if (data && data->init == false && npc->vd)
+ {
+ data->init = true;
+ npc->vd->sex = 3;
+ }
+}
+
+void estatus_read_job_db_sub(int *idxPtr,
+ const char *name __attribute__ ((unused)),
+ config_setting_t *jdb)
+{
+ int i32 = 0;
+ const int idx = *idxPtr;
+ if (itemdb->lookup_const(jdb, "MoveSpeed", &i32))
+ class_move_speed[idx] = i32;
+}
+
+int estatus_calc_pc_(int retVal,
+ struct map_session_data *sd,
+ enum e_status_calc_opt *opt __attribute__ ((unused)))
+{
+ if (!sd)
+ return retVal;
+
+ if (!sd->state.permanent_speed)
+ {
+ const int idx = pc->class2idx(sd->status.class_);
+ sd->base_status.speed = class_move_speed[idx];
+ }
+ return retVal;
+}
diff --git a/src/emap/status.h b/src/emap/status.h
new file mode 100644
index 0000000..fb0198b
--- /dev/null
+++ b/src/emap/status.h
@@ -0,0 +1,12 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_STATUS
+#define EVOL_MAP_STATUS
+
+void status_init(void);
+void estatus_set_viewdata_post(struct block_list *bl, int *class_);
+void estatus_read_job_db_sub(int *idxPtr, const char *name, config_setting_t *jdb);
+int estatus_calc_pc_(int retVal, struct map_session_data* sd, enum e_status_calc_opt *opt);
+
+#endif // EVOL_MAP_STATUS
diff --git a/src/emap/struct/itemdext.h b/src/emap/struct/itemdext.h
new file mode 100644
index 0000000..8d4a555
--- /dev/null
+++ b/src/emap/struct/itemdext.h
@@ -0,0 +1,33 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_ITEMDEXT
+#define EVOL_MAP_ITEMDEXT
+
+struct ItemdExt
+{
+ int floorLifeTime;
+
+ int requiredStr;
+ int requiredAgi;
+ int requiredVit;
+ int requiredInt;
+ int requiredDex;
+ int requiredLuk;
+ int requiredMaxHp;
+ int requiredMaxSp;
+ int requiredAtk;
+ int requiredMAtkMin;
+ int requiredMAtkMax;
+ int requiredDef;
+ int requiredMDef;
+
+ int useEffect;
+ int useFailEffect;
+ int unequipEffect;
+ int unequipFailEffect;
+
+ bool allowPickup;
+};
+
+#endif // EVOL_MAP_ITEMDEXT
diff --git a/src/emap/struct/mapdext.h b/src/emap/struct/mapdext.h
new file mode 100644
index 0000000..15fee7f
--- /dev/null
+++ b/src/emap/struct/mapdext.h
@@ -0,0 +1,17 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_MAPDEXT
+#define EVOL_MAP_MAPDEXT
+
+struct MapdExt
+{
+ unsigned int mask;
+ bool invisible;
+ struct MapdExtFlag
+ {
+ unsigned nopve : 1;
+ } flag;
+};
+
+#endif // EVOL_MAP_MAPDEXT
diff --git a/src/emap/struct/npcdext.h b/src/emap/struct/npcdext.h
new file mode 100644
index 0000000..2158f2c
--- /dev/null
+++ b/src/emap/struct/npcdext.h
@@ -0,0 +1,12 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_NPCDEXT
+#define EVOL_MAP_NPCDEXT
+
+struct NpcdExt
+{
+ bool init;
+};
+
+#endif // EVOL_MAP_NPCDEXT
diff --git a/src/emap/struct/sessionext.h b/src/emap/struct/sessionext.h
new file mode 100644
index 0000000..a592e50
--- /dev/null
+++ b/src/emap/struct/sessionext.h
@@ -0,0 +1,15 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_SESSIONEXT
+#define EVOL_MAP_SESSIONEXT
+
+struct SessionExt
+{
+ time_t onlinelistlasttime;
+ int clientVersion;
+ int language;
+ uint8 state;
+};
+
+#endif // EVOL_MAP_SESSIONEXT
diff --git a/src/emap/unit.c b/src/emap/unit.c
new file mode 100644
index 0000000..54dca56
--- /dev/null
+++ b/src/emap/unit.c
@@ -0,0 +1,163 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "common/timer.h"
+#include "map/unit.h"
+#include "map/map.h"
+#include "map/mob.h"
+#include "map/pc.h"
+#include "map/skill.h"
+#include "map/status.h"
+
+#include "emap/unit.h"
+
+int eunit_can_move(struct block_list *bl)
+{
+ TBL_PC *sd;
+ struct unit_data *ud;
+ struct status_change *sc;
+
+ if (!bl)
+ {
+ hookStop();
+ return 0;
+ }
+ ud = unit->bl2ud(bl);
+ sc = status->get_sc(bl);
+ sd = BL_CAST(BL_PC, bl);
+
+ if (!ud)
+ {
+ hookStop();
+ return 0;
+ }
+
+ if (ud->skilltimer != INVALID_TIMER
+ && ud->skill_id != LG_EXEEDBREAK
+ && (!sd
+ || !pc->checkskill(sd, SA_FREECAST)
+ || skill->get_inf2(ud->skill_id)&INF2_GUILD_SKILL))
+ {
+ hookStop();
+ return 0; // prevent moving while casting
+ }
+
+ if (DIFF_TICK(ud->canmove_tick, timer->gettick()) > 0)
+ {
+ hookStop();
+ return 0;
+ }
+
+ if (sd && (
+ sd->state.vending ||
+ sd->state.buyingstore ||
+ sd->state.blockedmove))
+ {
+ hookStop();
+ return 0; //Can't move
+ }
+
+ // Status changes that block movement
+ if (sc)
+ {
+ if (sc->count && (
+ sc->data[SC_ANKLESNARE]
+ || sc->data[SC_AUTOCOUNTER]
+ || sc->data[SC_TRICKDEAD]
+ || sc->data[SC_BLADESTOP]
+ || sc->data[SC_BLADESTOP_WAIT]
+ || (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_SELF) // cannot move while gospel is in effect
+ || (sc->data[SC_BASILICA] && sc->data[SC_BASILICA]->val4 == bl->id) // Basilica caster cannot move
+ || sc->data[SC_STOP]
+ || sc->data[SC_FALLENEMPIRE]
+ || sc->data[SC_RG_CCONFINE_M]
+ || sc->data[SC_RG_CCONFINE_S]
+ || sc->data[SC_GS_MADNESSCANCEL]
+ || (sc->data[SC_GRAVITATION] && sc->data[SC_GRAVITATION]->val3 == BCT_SELF)
+ || sc->data[SC_WHITEIMPRISON]
+ || sc->data[SC_ELECTRICSHOCKER]
+ || sc->data[SC_WUGBITE]
+ || sc->data[SC_THORNS_TRAP]
+ || ( sc->data[SC_MAGNETICFIELD] && !sc->data[SC_HOVERING] )
+ || sc->data[SC__MANHOLE]
+ || sc->data[SC_CURSEDCIRCLE_ATKER]
+ || sc->data[SC_CURSEDCIRCLE_TARGET]
+ || (sc->data[SC_COLD] && bl->type != BL_MOB)
+ || sc->data[SC_DEEP_SLEEP]
+ || (sc->data[SC_CAMOUFLAGE] && sc->data[SC_CAMOUFLAGE]->val1 < 3 && !(sc->data[SC_CAMOUFLAGE]->val3&1))
+ || sc->data[SC_MEIKYOUSISUI]
+ || sc->data[SC_KG_KAGEHUMI]
+ || sc->data[SC_NEEDLE_OF_PARALYZE]
+ || sc->data[SC_VACUUM_EXTREME]
+ || (sc->data[SC_FEAR] && sc->data[SC_FEAR]->val2 > 0)
+ || (sc->data[SC_SPIDERWEB] && sc->data[SC_SPIDERWEB]->val1)
+ || (sc->data[SC_CLOAKING] && sc->data[SC_CLOAKING]->val1 < 3 && !(sc->data[SC_CLOAKING]->val4&1)) //Need wall at level 1-2
+ || (
+ sc->data[SC_DANCING] && sc->data[SC_DANCING]->val4
+ && (
+ !sc->data[SC_LONGING]
+ || (sc->data[SC_DANCING]->val1&0xFFFF) == CG_MOONLIT
+ || (sc->data[SC_DANCING]->val1&0xFFFF) == CG_HERMODE))))
+ {
+ hookStop();
+ return 0;
+ }
+ if (sc->opt1 > 0
+ && sc->opt1 != OPT1_STONEWAIT
+ && sc->opt1 != OPT1_BURNING
+ && !(sc->opt1 == OPT1_CRYSTALIZE
+ && bl->type == BL_MOB))
+ {
+ hookStop();
+ return 0;
+ }
+
+ if ((sc->option & OPTION_HIDE) && (!sd || pc->checkskill(sd, RG_TUNNELDRIVE) <= 0))
+ {
+ hookStop();
+ return 0;
+ }
+ }
+
+ // Icewall walk block special trapped monster mode
+ if(bl->type == BL_MOB)
+ {
+ TBL_MOB *md = BL_CAST(BL_MOB, bl);
+ if(md && ((md->status.mode&MD_BOSS && battle->bc->boss_icewall_walk_block == 1 && map->getcell(bl->m,bl->x,bl->y,CELL_CHKICEWALL))
+ || (!(md->status.mode&MD_BOSS) && battle->bc->mob_icewall_walk_block == 1 && map->getcell(bl->m,bl->x,bl->y,CELL_CHKICEWALL))))
+ {
+ md->walktoxy_fail_count = 1; //Make sure rudeattacked skills are invoked
+ hookStop();
+ return 0;
+ }
+ }
+
+ hookStop();
+ return 1;
+}
+
+int eunit_walktoxy(struct block_list *bl __attribute__ ((unused)),
+ short *x __attribute__ ((unused)),
+ short *y __attribute__ ((unused)),
+ int *flagPtr)
+{
+ // reset flag "Search for an unoccupied cell and cancel if none available"
+ // this reduce CPU usage and allow mobs to walk on each other.
+ if ((*flagPtr)&8)
+ *flagPtr = ((*flagPtr) | 8) ^ 8;
+
+ TBL_PC *sd = BL_CAST(BL_PC, bl);
+ if (sd && pc_issit(sd))
+ pc->setstand(sd);
+
+ return 1;
+}
diff --git a/src/emap/unit.h b/src/emap/unit.h
new file mode 100644
index 0000000..675bf0e
--- /dev/null
+++ b/src/emap/unit.h
@@ -0,0 +1,10 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_UNIT
+#define EVOL_MAP_UNIT
+
+int eunit_can_move(struct block_list *bl);
+int eunit_walktoxy(struct block_list *bl, short *x, short *y, int *flagPtr);
+
+#endif // EVOL_MAP_UNIT
diff --git a/src/emap/utils/formatutils.c b/src/emap/utils/formatutils.c
new file mode 100644
index 0000000..70a7541
--- /dev/null
+++ b/src/emap/utils/formatutils.c
@@ -0,0 +1,116 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common/HPMi.h"
+#include "common/malloc.h"
+#include "common/mmo.h"
+#include "common/socket.h"
+#include "common/strlib.h"
+#include "map/script.h"
+
+#include "map/chrif.h"
+#include "map/clif.h"
+#include "map/npc.h"
+#include "map/pc.h"
+#include "map/script.h"
+#include "map/quest.h"
+
+#include "emap/utils/formatutils.h"
+#include "emap/lang.h"
+
+int format_sub(struct script_state* st, int translate)
+{
+ TBL_PC *sd = NULL;
+ if (translate)
+ sd = script->rid2sd(st);
+
+ if (!script_hasdata(st, 3))
+ {
+ if (sd)
+ {
+ if (translate == 2)
+ {
+ char *buf = aCalloc (strlen(script_getstr(st, 2)) + 3, sizeof(char));
+ strcpy (buf, script_getstr(st, 2));
+ if (sd->status.sex)
+ strcat (buf, "#1");
+ else
+ strcat (buf, "#0");
+ script_pushstr(st, aStrdup(lang_pctrans(buf, sd)));
+ aFree (buf);
+ }
+ else
+ {
+ script_pushstr(st, aStrdup(lang_pctrans(script_getstr(st, 2), sd)));
+ }
+ }
+ else
+ {
+ script_pushstr(st, aStrdup(script_getstr(st, 2)));
+ }
+ return 1;
+ }
+
+ char *line = (char *) aCalloc (550, sizeof (char));
+ int idx = 3;
+ if (sd)
+ {
+ if (translate == 2)
+ {
+ const char *str = NULL;
+ char *buf = NULL;
+ if (sd->status.sex)
+ {
+ str = script_getstr(st, 3);
+ buf = aCalloc (strlen(str) + 3, sizeof(char));
+ strcpy (buf, str);
+ strcat (buf, "#1");
+ }
+ else
+ {
+ str = script_getstr(st, 2);
+ buf = aCalloc (strlen(str) + 3, sizeof(char));
+ strcpy (buf, str);
+ strcat (buf, "#0");
+ }
+ strcpy(line, lang_pctrans(buf, sd));
+ aFree (buf);
+ idx = 4;
+ }
+ else
+ {
+ strcpy(line, lang_pctrans(script_getstr(st, 2), sd));
+ }
+ }
+ else
+ {
+ strcpy(line, script_getstr(st, 2));
+ }
+
+ char *ptr = line;
+ int sz = strlen(line);
+ while (script_hasdata(st, idx))
+ {
+ char *tmp = strstr(ptr, "@@");
+ if (!tmp)
+ break;
+ const char *item = script_getstr(st, idx);
+ int len = strlen(item);
+ if (len > 50)
+ break;
+ sz += len - 2;
+ if (sz > 490)
+ break;
+ memmove(tmp + len, tmp + 2, strlen(tmp + 2));
+ memcpy(tmp, item, len);
+ ptr = tmp + len;
+ idx ++;
+ }
+
+ script_pushstr(st, line);
+ return 0;
+}
diff --git a/src/emap/utils/formatutils.h b/src/emap/utils/formatutils.h
new file mode 100644
index 0000000..361ad84
--- /dev/null
+++ b/src/emap/utils/formatutils.h
@@ -0,0 +1,9 @@
+// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// Copyright (c) 2014 Evol developers
+
+#ifndef EVOL_MAP_UTILS_FORMATUTILS
+#define EVOL_MAP_UTILS_FORMATUTILS
+
+int format_sub(struct script_state* st, int translate);
+
+#endif // EVOL_MAP_UTILS_FORMATUTILS