diff options
Diffstat (limited to 'src/emap')
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 |