summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ecommon/init.c10
-rw-r--r--src/emap/atcommand.c88
-rw-r--r--src/emap/atcommand.h2
-rw-r--r--src/emap/console.c13
-rw-r--r--src/emap/console.h1
-rw-r--r--src/emap/data/mobd.c2
-rw-r--r--src/emap/enum/esitype.h11
-rw-r--r--src/emap/homunculus.c4
-rw-r--r--src/emap/init.c34
-rw-r--r--src/emap/itemdb.c8
-rw-r--r--src/emap/mob.c4
-rw-r--r--src/emap/pc.c114
-rw-r--r--src/emap/pc.h7
-rw-r--r--src/emap/script_buildins.c626
-rw-r--r--src/emap/script_buildins.h22
-rw-r--r--src/emap/skill.c77
-rw-r--r--src/emap/skill.h11
-rw-r--r--src/emap/status.c14
-rw-r--r--src/emap/struct/mobdext.h2
19 files changed, 1017 insertions, 33 deletions
diff --git a/src/ecommon/init.c b/src/ecommon/init.c
index 753fcf1..664522c 100644
--- a/src/ecommon/init.c
+++ b/src/ecommon/init.c
@@ -49,12 +49,14 @@ void commonClean(void)
void common_online(void)
{
- checkVar(MAX_SKILL_DB, 1532);
- checkVar(MAX_SKILL_ID, 20022);
+ checkVar(MAX_STORAGE, 500);
+ checkVar(MAX_INVENTORY, 120);
+ checkVar(MAX_SKILL_DB, 1572);
+ checkVar(MAX_SKILL_ID, 20062);
checkVar(SC_MAX, 658);
- checkVar(SI_MAX, 971);
+ checkVar(SI_MAX, 991);
checkVar(OLD_MAX_SKILL_DB, 1510);
- checkVar(MAX_EVOL_SKILLS, 22);
+ checkVar(MAX_EVOL_SKILLS, 62);
checkVar(EVOL_FIRST_SKILL, 20000);
checkVar(MAX_SKILL_TREE, 110);
checkVar(BASE_GUILD_SIZE, 100);
diff --git a/src/emap/atcommand.c b/src/emap/atcommand.c
index f71698f..de35411 100644
--- a/src/emap/atcommand.c
+++ b/src/emap/atcommand.c
@@ -7,6 +7,7 @@
#include <stdlib.h>
#include <string.h>
+#include "common/cbasetypes.h"
#include "common/HPMi.h"
#include "common/memmgr.h"
#include "common/mmo.h"
@@ -16,6 +17,7 @@
#include "map/atcommand.h"
#include "map/clif.h"
#include "map/map.h"
+#include "map/pet.h"
#include "map/pc.h"
#include "map/skill.h"
@@ -289,3 +291,89 @@ ACMD1(getName)
return true;
}
+
+// TMW2
+/*==========================================
+ * @refresh (like @jumpto <<yourself>>)
+ *------------------------------------------*/
+ACMD0(refresh)
+{
+ clif->refresh(sd);
+ return true;
+}
+
+/*==========================================
+ * @item command (usage: @item <name/id_of_item> <quantity>) (modified by [Yor] for pet_egg)
+ * @itembound command (usage: @itembound <name/id_of_item> <quantity> <bound type>) (revised by [Mhalicot])
+ *------------------------------------------*/
+ACMD0(tmw2item)
+{
+ char item_name[100];
+ int number = 0, item_id, flag = 0, bound = 0;
+ struct item item_tmp;
+ struct item_data *item_data;
+ int get_count, i;
+
+ memset(item_name, '\0', sizeof(item_name));
+
+ if (!*message
+ || ( sscanf(message, "\"%99[^\"]\" %12d", item_name, &number) < 1
+ && sscanf(message, "%99s %12d", item_name, &number) < 1
+ )) {
+ clif->message(fd, msg_fd(fd,983)); // Please enter an item name or ID (usage: @item <item name/ID> <quantity>).
+ return false;
+ }
+
+ if (number <= 0)
+ number = 1;
+
+ if ((item_data = itemdb->search_name(item_name)) == NULL &&
+ (item_data = itemdb->exists(atoi(item_name))) == NULL)
+ {
+ clif->message(fd, msg_fd(fd,19)); // Invalid item ID or name.
+ return false;
+ }
+
+ item_id = item_data->nameid;
+ get_count = number;
+
+ // TMW2: Check for restrictions
+ // Strange Coins ; <BronzeGift ~ SupremeGift> ; Legendary Weapons ; Fruits ; DeathPenalty
+ if( item_id == 828 ||
+ (item_id >= 589 && item_id <= 593) ||
+ (item_id >= 3600 && item_id <= 3610) ||
+ (item_id >= 8000 && item_id <= 8006) ||
+ item_id == 7420 ) {
+ clif->message(fd, msg_fd(fd,19)); // Invalid item ID or name
+ clif->message(fd, msg_fd(fd,1481)); // TMW2 Restriction
+ return false;
+ }
+
+ //Check if it's stackable.
+ if (!itemdb->isstackable2(item_data)) {
+ if( bound && (item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) ) {
+ clif->message(fd, msg_fd(fd,498)); // Cannot create bounded pet eggs or pet armors.
+ return false;
+ }
+ get_count = 1;
+ }
+
+ for (i = 0; i < number; i += get_count) {
+ // if not pet egg
+ if (!pet->create_egg(sd, item_id)) {
+ memset(&item_tmp, 0, sizeof(item_tmp));
+ item_tmp.nameid = item_id;
+ item_tmp.identify = 1;
+ item_tmp.bound = (unsigned char)bound;
+
+ if ((flag = pc->additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND)))
+ clif->additem(sd, 0, 0, flag);
+ }
+ }
+
+ if (flag == 0)
+ clif->message(fd, msg_fd(fd,18)); // Item created.
+ return true;
+}
+
+
diff --git a/src/emap/atcommand.h b/src/emap/atcommand.h
index 50a92df..eb3af35 100644
--- a/src/emap/atcommand.h
+++ b/src/emap/atcommand.h
@@ -42,5 +42,7 @@ ACMD1(serverExit);
ACMD0(log);
ACMD4(tee);
ACMD4(getName);
+ACMD0(refresh);
+ACMD0(tmw2item);
#endif // EVOL_MAP_ATCOMMAND
diff --git a/src/emap/console.c b/src/emap/console.c
index 80dbab3..687da46 100644
--- a/src/emap/console.c
+++ b/src/emap/console.c
@@ -11,6 +11,9 @@
#include "common/memmgr.h"
#include "common/socket.h"
#include "map/map.h"
+#include "map/npc.h"
+#include "map/pc.h"
+#include "map/script.h"
#include "emap/console.h"
#include "emap/inter.h"
@@ -29,3 +32,13 @@ CPCMD(serverExit)
map->retval = code;
map->do_shutdown();
}
+
+CPCMD(C_doevent)
+{
+ struct map_session_data* sd;
+ sd = pc->get_dummy_sd();
+
+ //script->check_event(st, line); // Dangerous but not needed
+ npc->event(sd, line, 0);
+ return;
+}
diff --git a/src/emap/console.h b/src/emap/console.h
index 012b0af..44b47dc 100644
--- a/src/emap/console.h
+++ b/src/emap/console.h
@@ -7,5 +7,6 @@
#include "common/console.h"
CPCMD(serverExit);
+CPCMD(C_doevent);
#endif // EVOL_MAP_CONSOLE
diff --git a/src/emap/data/mobd.c b/src/emap/data/mobd.c
index e11a222..0d2209b 100644
--- a/src/emap/data/mobd.c
+++ b/src/emap/data/mobd.c
@@ -51,8 +51,10 @@ struct MobdExt *mobd_create(void)
data->weaponAttacks[f] = 10000;
for (int f = 0; f < MAX_SKILL_DB; f ++)
data->skillAttacks[f] = 10000;
+ /* Disabled in TMW2
data->collisionDx = -1;
data->collisionDy = -1;
data->collisionMask = 1;
+ */
return data;
}
diff --git a/src/emap/enum/esitype.h b/src/emap/enum/esitype.h
index d1213ad..b1d62c3 100644
--- a/src/emap/enum/esitype.h
+++ b/src/emap/enum/esitype.h
@@ -7,6 +7,17 @@
enum esi_type
{
SI_PHYSICAL_SHIELD = 966,
+ //SI_TMW2_INCSTR = 970,
+ SI_TMW2_INCAGI = 971,
+ SI_TMW2_INCVIT = 972,
+ SI_TMW2_INCINT = 973,
+ SI_TMW2_INCDEX = 974,
+ SI_TMW2_INCLUK = 975,
+ SI_TMW2_INCHIT = 976,
+ SI_TMW2_INCFLEE = 977,
+ SI_TMW2_WALKSPEED = 978,
+ SI_TMW2_INCMHPRATE = 979,
+ SI_TMW2_INCMSPRATE = 980,
};
#endif // EVOL_MAP_ENUM_ESITYPE
diff --git a/src/emap/homunculus.c b/src/emap/homunculus.c
index df9bafb..c51a24c 100644
--- a/src/emap/homunculus.c
+++ b/src/emap/homunculus.c
@@ -2,6 +2,7 @@
// Copyright (c) 2014 - 2015 Evol developers
#include "common/hercules.h"
+#include "map/homunculus.h"
#include <stdio.h>
#include <stdlib.h>
@@ -19,6 +20,7 @@ int ehomunculus_gainexp_pre(struct homun_data **hdPtr,
nullpo_ret(hd);
const int exp = *expPtr;
- send_homun_exp(hd, exp);
+ if (hd->homunculus.vaporize == HOM_ST_ACTIVE)
+ send_homun_exp(hd, exp);
return 0;
}
diff --git a/src/emap/init.c b/src/emap/init.c
index d4e8d11..c59185b 100644
--- a/src/emap/init.c
+++ b/src/emap/init.c
@@ -114,8 +114,11 @@ HPExport void plugin_init (void)
addAtcommand("tee", tee);
addAtcommand("log", log);
addAtcommand("getname", getName);
+ addAtcommand("refresh", refresh);
+ addAtcommand("item", tmw2item);
addCPCommand("serverexit", serverExit);
+ addCPCommand("doevent", C_doevent);
addScriptCommand("chatjoin", "i*", chatJoin);
addScriptCommand("setcamnpc", "*", setCamNpc);
@@ -170,7 +173,7 @@ HPExport void plugin_init (void)
addScriptCommand("setnpcdialogtitle", "s", setNpcDialogTitle);
addScriptCommand("getmapname", "", getMapName);
addScriptCommand("unequipbyid", "i", unequipById);
- addScriptCommand("ispcdead", "", isPcDead);
+ addScriptCommand("ispcdead", "?", isPcDead);
addScriptCommand("getareadropitem", "siiiiv*", getAreaDropItem);
addScriptCommand("clientcommand", "s", clientCommand);
addScriptCommand("isunitwalking", "?", isUnitWalking);
@@ -213,6 +216,28 @@ HPExport void plugin_init (void)
addScriptCommand("getitemoptionparambyindex", "ii", getItemOptionParamByIndex);
addScriptCommand("setitemoptionbyindex", "iii*", setItemOptionByIndex);
addScriptCommand("isinstance", "i", isInstance);
+ addScriptCommand("readbattleparam","i?",readBattleParam);
+
+ // TMW2 Custom Script Commands
+ addScriptCommand("getguildinfo","i",getguildinfo);
+ addScriptCommand("getguildlvl","i",getguildlvl);
+ addScriptCommand("getguildavg","i",getguildavg);
+ addScriptCommand("getguildexp","i",getguildexp);
+ addScriptCommand("getguildnxp","i",getguildnxp);
+ addScriptCommand("getguildpostax","ii",getguildpostax);
+ addScriptCommand("getguildpostitle","ii",getguildpostitle);
+ addScriptCommand("setguildrole","iiiis",setguildrole);
+ addScriptCommand("getguildmember","i?",getguildmember);
+ addScriptCommand("gethomunexp","i",gethomunexp);
+ addScriptCommand("deployhomunculus","",deployhomunculus);
+ addScriptCommand("recallhomunculus","",recallhomunculus);
+ addScriptCommand("homstatus","",homstatus);
+ addScriptCommand("readparam2","i?",readparam2);
+ addScriptCommand("npcshopattach","s?",npcshopattach);
+
+ // Overrides
+ addScriptCommand("debugmes","v*",debugmes);
+ addScriptCommand("countitem","v?",countitem);
do_init_langs();
@@ -282,6 +307,7 @@ HPExport void plugin_init (void)
addHookPre(pc, resetskill_job, epc_resetskill_job_pre);
addHookPre(pc, isDeathPenaltyJob, epc_isDeathPenaltyJob_pre);
addHookPre(pc, read_skill_job_skip, epc_read_skill_job_skip_pre);
+ addHookPre(pc, equipitem, epc_equipitem_pre);
addHookPre(mob, deleteslave_sub, emob_deleteslave_sub_pre);
addHookPre(mob, read_db_additional_fields, emob_read_db_additional_fields_pre);
addHookPre(mob, dead, emob_dead_pre);
@@ -344,6 +370,9 @@ HPExport void plugin_init (void)
addHookPre(status, calc_pc_recover_hp, estatus_calc_pc_recover_hp_pre);
addHookPre(homun, gainexp, ehomunculus_gainexp_pre);
+ // TMW2 Custom Pre Hooks
+ //addHookPre(battle, calc_weapon_attack, ebattle_calc_weapon_attack_pre);
+
addHookPost(battle, calc_weapon_attack, ebattle_calc_weapon_attack_post);
addHookPost(battle, calc_magic_attack, ebattle_calc_weapon_attack_post);
addHookPost(battle, calc_misc_attack, ebattle_calc_weapon_attack_post);
@@ -374,6 +403,8 @@ HPExport void plugin_init (void)
addHookPost(mob, spawn_dataset, emob_spawn_dataset_post);
addHookPost(skill, check_condition_castend, eskill_check_condition_castend_post);
addHookPost(skill, get_index, eskill_get_index_post);
+ addHookPost(skill, calc_heal, eskill_calc_heal_post);
+ addHookPost(skill, consume_requirement, eskill_consume_requirement_post);
addHookPost(pc, additem, epc_additem_post);
addHookPost(pc, isequip, epc_isequip_post);
addHookPost(pc, isUseitem, epc_isequip_post);
@@ -387,6 +418,7 @@ HPExport void plugin_init (void)
addHookPost(pc, takeitem, epc_takeitem_post);
addHookPost(pc, can_insert_card_into, epc_can_insert_card_into_post);
addHookPost(pc, insert_card, epc_insert_card_post);
+ addHookPost(pc, resetstate, epc_resetstate_post);
skill->castend_nodamage_id_unknown = eskill_castend_nodamage_id_unknown;
skill->additional_effect_unknown = eskill_additional_effect_unknown;
diff --git a/src/emap/itemdb.c b/src/emap/itemdb.c
index d9ff7d8..e60783b 100644
--- a/src/emap/itemdb.c
+++ b/src/emap/itemdb.c
@@ -196,6 +196,14 @@ void eitemdb_readdb_additional_fields_pre(int *itemid,
if (itemdb->lookup_const(it, "MinRange", &i32))
data->minRange = i32;
+
+ // TMW2 fixes
+ if (item->type == IT_WEAPON || item->type == IT_ARMOR) {
+ if (item->view_sprite == 0) {
+ item->view_sprite=*itemid;
+ }
+ }
+
hookStop();
}
diff --git a/src/emap/mob.c b/src/emap/mob.c
index fbc75b6..3391620 100644
--- a/src/emap/mob.c
+++ b/src/emap/mob.c
@@ -260,6 +260,7 @@ void emob_read_db_additional_fields_pre(struct mob_db **entryPtr,
}
}
+ /* Disabled in TMW2
if ((tt = libconfig->setting_get_member(*itPtr, "SpawnCollisionSize")))
{
if (config_setting_is_aggregate(tt))
@@ -279,6 +280,7 @@ void emob_read_db_additional_fields_pre(struct mob_db **entryPtr,
if (mob->lookup_const(*itPtr, "SpawnCollisionMask", &i32))
data->collisionMask = i32;
+ */
}
uint32 emob_read_db_mode_sub_post(uint32 retVal,
@@ -296,6 +298,7 @@ uint32 emob_read_db_mode_sub_post(uint32 retVal,
struct mob_data *emob_spawn_dataset_post(struct mob_data *retVal,
struct spawn_data *data __attribute__ ((unused)))
{
+ /* Disabled in TMW2
if (retVal)
{
struct MobdExt *ext = mobd_get_by_mob(retVal);
@@ -314,6 +317,7 @@ struct mob_data *emob_spawn_dataset_post(struct mob_data *retVal,
name);
}
}
+ */
return retVal;
}
diff --git a/src/emap/pc.c b/src/emap/pc.c
index 011743e..5e8b3b0 100644
--- a/src/emap/pc.c
+++ b/src/emap/pc.c
@@ -15,12 +15,14 @@
#include "common/strlib.h"
#include "common/timer.h"
#include "map/achievement.h"
+#include "map/clif.h"
#include "map/chrif.h"
#include "map/homunculus.h"
#include "map/elemental.h"
#include "map/itemdb.h"
#include "map/npc.h"
#include "map/pc.h"
+#include "map/status.h"
#include "map/quest.h"
#include "plugins/HPMHooking.h"
@@ -293,29 +295,6 @@ int epc_isequip_post(int retVal,
if (!data)
return retVal;
- // test for missing basic stats calculation
- if (sd->regen.sregen == NULL)
- {
- 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 ||
- (data->requiredSkill && !pc->checkskill(sd, data->requiredSkill))
- )
- {
- return 0;
- }
}
return retVal;
}
@@ -1064,6 +1043,95 @@ void epc_calc_skilltree_clear_pre(struct map_session_data **sdPtr)
hookStop();
}
+// Required Stats
+int epc_equipitem_pre(struct map_session_data **sdPtr,
+ int *nPtr,
+ int *req_pos __attribute__ ((unused)))
+{
+ struct map_session_data *sd = *sdPtr;
+ if (!sd)
+ return 1;
+
+ const int n = *nPtr;
+
+ if (n < 0 || n >= sd->status.inventorySize)
+ return 1;
+
+ struct item_data *id;
+ id = sd->inventory_data[n];
+ struct ItemdExt *data = itemd_get(id);
+
+ if (!data)
+ return 1;
+
+ if (sd->status.str < data->requiredStr ||
+ sd->status.agi < data->requiredAgi ||
+ sd->status.vit < data->requiredVit ||
+ sd->status.int_ < data->requiredInt ||
+ sd->status.dex < data->requiredDex ||
+ sd->status.luk < data->requiredLuk ||
+ sd->status.max_hp < data->requiredMaxHp ||
+ sd->status.max_sp < data->requiredMaxSp ||
+ (data->requiredSkill && !pc->checkskill(sd, data->requiredSkill))
+ )
+ {
+ clif->equipitemack(sd,n,0,EIA_FAIL); // fail
+ hookStop();
+ return 0;
+ }
+
+ // Okay, continue...
+ return 0;
+}
+
+int epc_resetstate_post(int retVal,
+ struct map_session_data *sd) {
+
+ // Do nothing if it failed
+ if (!retVal)
+ return retVal;
+
+ int i;
+ struct item_data *id;
+ struct ItemdExt *data;
+
+ // Check all your equipped items
+ for (i = 0; i < EQI_MAX; i++) {
+ int index = sd->equip_index[i];
+
+ id = sd->inventory_data[index];
+
+ // Skip possibly empty slots
+ if (id == NULL)
+ continue;
+
+ data = itemd_get(id);
+
+ // Skip broken pointers
+ if (data == NULL)
+ continue;
+
+ // Check for requeriments
+ if (sd->status.str < data->requiredStr ||
+ sd->status.agi < data->requiredAgi ||
+ sd->status.vit < data->requiredVit ||
+ sd->status.int_ < data->requiredInt ||
+ sd->status.dex < data->requiredDex ||
+ sd->status.luk < data->requiredLuk ||
+ sd->status.max_hp < data->requiredMaxHp ||
+ sd->status.max_sp < data->requiredMaxSp ||
+ (data->requiredSkill && !pc->checkskill(sd, data->requiredSkill))
+ )
+ {
+ // Unequip the item
+ pc->unequipitem(sd, index, PCUNEQUIPITEM_FORCE);
+ }
+ }
+ // Now recalculate, and return whatever it had to return
+ status_calc_pc(sd,SCO_NONE);
+ return retVal;
+}
+
// disable job based bonuses
void epc_calc_skilltree_bonus_pre(struct map_session_data **sdPtr __attribute__ ((unused)),
int *classidxPtr __attribute__ ((unused)))
diff --git a/src/emap/pc.h b/src/emap/pc.h
index d5c59bf..a204917 100644
--- a/src/emap/pc.h
+++ b/src/emap/pc.h
@@ -144,4 +144,11 @@ bool epc_isDeathPenaltyJob_pre(uint16 *jobPtr);
bool epc_read_skill_job_skip_pre(short *skill_idPtr,
int *job_idPtr);
+int epc_equipitem_pre(struct map_session_data **sdPtr,
+ int *nPtr,
+ int *req_pos __attribute__ ((unused)));
+
+int epc_resetstate_post(int retVal,
+ struct map_session_data *sd);
+
#endif // EVOL_MAP_PC
diff --git a/src/emap/script_buildins.c b/src/emap/script_buildins.c
index c0a7e1b..e0e22ce 100644
--- a/src/emap/script_buildins.c
+++ b/src/emap/script_buildins.c
@@ -14,7 +14,10 @@
#include "map/achievement.h"
#include "map/chat.h"
#include "map/chrif.h"
+#include "map/guild.h"
+#include "map/homunculus.h"
#include "map/instance.h"
+#include "map/mapreg.h"
#include "map/npc.h"
#include "map/pc.h"
#include "map/refine.h"
@@ -185,7 +188,8 @@ BUILDIN(npcTalk3)
BUILDIN(closeDialog)
{
getSD();
- send_npccommand(sd, st->oid, 5);
+ //send_npccommand(sd, st->oid, 5);
+ send_npccommand(sd, st->oid, 14);
return true;
}
@@ -196,6 +200,32 @@ BUILDIN(closeClientDialog)
return true;
}
+// npcshopattach(npc) will tell the scripts to run an event
+// Enabling OnBuyItem and OnSellItem events of npc
+BUILDIN(npcshopattach)
+{
+ const char* npcname = script_getstr(st,2);
+ struct npc_data* nd = npc->name2id(npcname);
+ int flag = 1;
+
+ if( script_hasdata(st,3) )
+ flag = script_getnum(st,3);
+
+ if( !nd ) {
+ //Not found.
+ script_pushint(st,0);
+ return true;
+ }
+
+ if (flag)
+ nd->master_nd = map->id2nd(st->oid);
+ else
+ nd->master_nd = NULL;
+
+ script_pushint(st,1);
+ return true;
+}
+
BUILDIN(shop)
{
getSD();
@@ -207,8 +237,14 @@ BUILDIN(shop)
return false;
}
+ // TMW2 Shops
+ /*
+ Move this to a new function, and comment the autoclose
+ Skip the forced check of SHOP type because I don't like it.
+
st->state = sd->state.dialog == 1 ? CLOSE : END;
clif->scriptclose(sd, st->oid);
+ */
clif->npcbuysell (sd, nd->bl.id);
return true;
@@ -999,9 +1035,13 @@ BUILDIN(isPcDead)
if (sd == NULL)
{
- ShowWarning("player not attached\n");
- script->reportsrc(st);
- return false;
+ sd = script->nick2sd(st, script_getstr(st, 2));
+ if (sd == NULL)
+ {
+ ShowWarning("player not attached\n");
+ script->reportsrc(st);
+ return false;
+ }
}
script_pushint(st, pc_isdead(sd) ? 1 : 0);
@@ -2348,3 +2388,581 @@ BUILDIN(isInstance)
script_pushint(st, instance->valid(instance_id) ? 1 : 0);
return true;
}
+
+/*==========================================
+ * return the battle stats of a structure
+ * Supported values are most of UDT_* ones
+ * Not all values are supported; Only those without
+ * another assessor are (eg. MaxHP vs UDT_MAXHP)
+ *
+ * From 1 onwards: Str, Agi, Vit, Int, Dex, Luck
+ * From 7 onwards: AtkMin, AtkMax, Def, MDef, Hit, Flee
+ * From 13 onwards: MAtkMin, MatkMax
+ *------------------------------------------*/
+BUILDIN(readBattleParam)
+{
+ struct map_session_data *sd;
+ int data = script_getnum(st,2);
+
+ // Account ID/Player Name is also supported
+ if (script_hasdata(st, 3)) {
+ if (script_isstringtype(st, 3)) {
+ sd = script->nick2sd(st, script_getstr(st, 3));
+ } else {
+ sd = script->id2sd(st, script_getnum(st, 3));
+ }
+ } else {
+ sd = script->rid2sd(st);
+ }
+
+ // Error
+ if (sd == NULL) {
+ ShowError("Target is not player in readbattleparam(%d)\n", data);
+ script_pushint(st, -1);
+ return true;
+ }
+
+ switch (data) {
+ // * From 1 onwards: Str, Agi, Vit, Int, Dex, Luck
+ case UDT_STR:
+ script_pushint(st, sd->battle_status.str);
+ break;
+ case UDT_AGI:
+ script_pushint(st, sd->battle_status.agi);
+ break;
+ case UDT_VIT:
+ script_pushint(st, sd->battle_status.vit);
+ break;
+ case UDT_INT:
+ script_pushint(st, sd->battle_status.int_);
+ break;
+ case UDT_DEX:
+ script_pushint(st, sd->battle_status.dex);
+ break;
+ case UDT_LUK:
+ script_pushint(st, sd->battle_status.luk);
+ break;
+ case UDT_ATKRANGE:
+ script_pushint(st, sd->battle_status.rhw.range);
+ break;
+ case UDT_ATKMIN:
+ script_pushint(st, sd->battle_status.rhw.atk);
+ break;
+ case UDT_ATKMAX:
+ script_pushint(st, sd->battle_status.rhw.atk+sd->battle_status.batk);
+ break;
+ case UDT_DEF:
+ script_pushint(st, sd->battle_status.def);
+ break;
+ case UDT_MDEF:
+ script_pushint(st, sd->battle_status.mdef+sd->battle_status.mdef2);
+ break;
+ case UDT_HIT:
+ script_pushint(st, sd->battle_status.hit);
+ break;
+ case UDT_FLEE:
+ script_pushint(st, sd->battle_status.flee);
+ break;
+ case UDT_MATKMIN:
+ script_pushint(st, sd->battle_status.matk_min);
+ break;
+ case UDT_MATKMAX:
+ script_pushint(st, sd->battle_status.matk_max);
+ break;
+ case UDT_CRIT:
+ script_pushint(st, sd->battle_status.cri);
+ break;
+ case UDT_ELETYPE:
+ script_pushint(st, sd->battle_status.def_ele);
+ break;
+ case UDT_ADELAY:
+ script_pushint(st, sd->battle_status.adelay);
+ break;
+ case UDT_DMOTION:
+ script_pushint(st, sd->battle_status.dmotion);
+ break;
+ default:
+ ShowError("Wrong paramType in readbattleparam(%d)\nAre you sure you used the right constants?\n", data);
+ script_pushint(st, -1);
+ break;
+ }
+
+ return true;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// TMW2 Custom Commands
+///////////////////////////////////////////////////////////////////////////////
+
+/*==========================================
+ * Return the data of the @guild_id
+ * null if not found
+ *------------------------------------------*/
+BUILDIN(getguildinfo)
+{
+ int guild_id;
+ struct guild* g;
+
+ guild_id = script_getnum(st,2);
+
+ if( ( g = guild->search(guild_id) ) != NULL )
+ {
+ mapreg->setreg(reference_uid(script->add_variable("$@guildinfo_lvl"), guild_id),g->guild_lv);
+ mapreg->setreg(reference_uid(script->add_variable("$@guildinfo_avg"), guild_id),g->average_lv);
+ mapreg->setreg(reference_uid(script->add_variable("$@guildinfo_exp"), guild_id),(int)(g->exp));
+ mapreg->setreg(reference_uid(script->add_variable("$@guildinfo_nxp"), guild_id),(int)(g->next_exp));
+ }
+ else
+ {
+ //script_pushconststr(st,"null");
+ script_pushint(st,0);
+ }
+ return true;
+}
+
+/*==========================================
+ * Return the level of the @guild_id
+ * -1 if not found
+ *------------------------------------------*/
+BUILDIN(getguildlvl)
+{
+ int guild_id;
+ struct guild* g;
+
+ guild_id = script_getnum(st,2);
+
+ if( ( g = guild->search(guild_id) ) != NULL )
+ {
+ script_pushint(st,g->guild_lv);
+ }
+ else
+ {
+ script_pushint(st,-1);
+ }
+ return true;
+}
+
+
+/*==========================================
+ * Return the average player level of the @guild_id
+ * -1 if not found
+ *------------------------------------------*/
+BUILDIN(getguildavg)
+{
+ int guild_id;
+ struct guild* g;
+
+ guild_id = script_getnum(st,2);
+
+ if( ( g = guild->search(guild_id) ) != NULL )
+ {
+ script_pushint(st,g->average_lv);
+ }
+ else
+ {
+ script_pushint(st,-1);
+ }
+ return true;
+}
+
+
+/*==========================================
+ * Return the experience of the @guild_id
+ * -1 if not found
+ *------------------------------------------*/
+BUILDIN(getguildexp)
+{
+ int guild_id;
+ struct guild* g;
+
+ guild_id = script_getnum(st,2);
+
+ if( ( g = guild->search(guild_id) ) != NULL )
+ {
+ script_pushint(st,(int)(g->exp));
+ }
+ else
+ {
+ script_pushint(st,-1);
+ }
+ return true;
+}
+
+
+/*==========================================
+ * Return the experience to level up for the @guild_id
+ * -1 if not found
+ *------------------------------------------*/
+BUILDIN(getguildnxp)
+{
+ int guild_id;
+ struct guild* g;
+
+ guild_id = script_getnum(st,2);
+
+ if( ( g = guild->search(guild_id) ) != NULL )
+ {
+ script_pushint(st,(int)(g->next_exp));
+ }
+ else
+ {
+ script_pushint(st,-1);
+ }
+ return true;
+}
+
+
+/*==========================================
+ * Return the EXP tax for (guild, position)
+ * -1 if not found
+ *------------------------------------------*/
+BUILDIN(getguildpostax)
+{
+ int guild_id, gpos;
+ struct guild* g;
+
+ guild_id = script_getnum(st,2);
+ gpos = script_getnum(st,3);
+
+ if( ( g = guild->search(guild_id) ) != NULL )
+ {
+ script_pushint(st,g->position[gpos].exp_mode);
+ }
+ else
+ {
+ script_pushint(st,-1);
+ }
+ return true;
+}
+
+
+/*==========================================
+ * Return the title (guild, position)
+ * "" if not found
+ *------------------------------------------*/
+BUILDIN(getguildpostitle)
+{
+ int guild_id, gpos;
+ struct guild* g;
+
+ guild_id = script_getnum(st,2);
+ gpos = script_getnum(st,3);
+
+ if( ( g = guild->search(guild_id) ) != NULL )
+ {
+ script_pushstrcopy(st, g->position[gpos].name);
+ }
+ else
+ {
+ script_pushstr(st,"");
+ }
+ return true;
+}
+
+
+/*==========================================
+ * Change a position for the @guild_id
+ * -1 if not found
+ * This will be superseed by ManaPlus eventually
+ * and is only a quick fix until 4144 can work with GUI.
+ * Everyone knows C is easier than C++ >.>
+ * WARNING Not sanitized
+ *------------------------------------------*/
+BUILDIN(setguildrole)
+{
+ int guild_id;
+ int idx;
+ int mode;
+ int exp_mode;
+ const char *name;
+ struct guild* g;
+
+ guild_id = script_getnum(st,2);
+ idx = script_getnum(st,3);
+ mode = script_getnum(st,4);
+ exp_mode = script_getnum(st,5);
+ name = script_getstr(st,6);
+
+ if( ( g = guild->search(guild_id) ) != NULL )
+ {
+ script_pushint(st, guild->change_position(guild_id, idx, mode, exp_mode, name));
+ }
+ else
+ {
+ script_pushint(st,-1);
+ }
+ return true;
+}
+
+/*==========================================
+ * Get the information of the members of a guild by type.
+ * getguildmember <guild_id>{,<type>};
+ * @param guild_id: ID of guild
+ * @param type:
+ * 0 : name (default)
+ * 1 : character ID
+ * 2 : account ID
+ *------------------------------------------*/
+BUILDIN(getguildmember)
+{
+ struct guild *g = NULL;
+ int j = 0;
+
+ g = guild->search(script_getnum(st,2));
+
+ if (g) {
+ int i, type = 0;
+
+ if (script_hasdata(st,3))
+ type = script_getnum(st,3);
+
+ for ( i = 0; i < MAX_GUILD; i++ ) {
+ if ( g->member[i].account_id ) {
+ switch (type) {
+ case 2:
+ mapreg->setreg(reference_uid(script->add_variable("$@guildmemberaid"), j),g->member[i].account_id);
+ break;
+ case 1:
+ mapreg->setreg(reference_uid(script->add_variable("$@guildmembercid"), j), g->member[i].char_id);
+ break;
+ default:
+ mapreg->setregstr(reference_uid(script->add_variable("$@guildmembername$"), j), g->member[i].name);
+ break;
+ }
+ mapreg->setreg(reference_uid(script->add_variable("$@guildmemberpos"), j),g->member[i].position);
+ j++;
+ }
+ }
+ }
+ mapreg->setreg(script->add_variable("$@guildmembercount"), j);
+ return true;
+}
+
+/*==========================================
+ * Give homunculus exp
+ *------------------------------------------*/
+BUILDIN(gethomunexp)
+{
+ int base=0;
+ struct map_session_data *sd = script->rid2sd(st);
+ if (sd == NULL || sd->hd == NULL)
+ return true;
+
+ base = script_getnum(st,2);
+ if (base < 0)
+ return true;
+
+ // Cannot give EXP to inactive or dead homunculus
+ if (!homun_alive(sd->hd))
+ return true;
+
+ homun->gainexp(sd->hd, base);
+ return true;
+}
+
+/*==========================================
+ * Send resting homunculus in a mission
+ * Homun must be resting. Returns true on success.
+ *------------------------------------------*/
+BUILDIN(deployhomunculus)
+{
+ struct map_session_data *sd = script->rid2sd(st);
+ if (sd == NULL || sd->hd == NULL)
+ return true;
+
+ /*
+ // Homunculus must be resting
+ if (sd->hd->homunculus.vaporize != HOM_ST_REST)
+ return true;
+
+ // Add morph state.
+ //sd->hd->homunculus.vaporize=HOM_ST_MORPH;
+ */
+
+ // Using the function, I don't need it resting
+ homun->vaporize(sd, HOM_ST_MORPH);
+
+ // Return true
+ script_pushint(st,true);
+ return true;
+}
+
+/*==========================================
+ * Returns the Homunculus from a mission
+ * Homun must be morph. Returns true on success.
+ *------------------------------------------*/
+BUILDIN(recallhomunculus)
+{
+ struct map_session_data *sd = script->rid2sd(st);
+ if (sd == NULL || sd->hd == NULL)
+ return true;
+
+ // Homunculus must be vapor
+ if (sd->hd->homunculus.vaporize != HOM_ST_MORPH)
+ return true;
+
+ // Remove morph state.
+ sd->hd->homunculus.vaporize=HOM_ST_REST;
+ homun->call(sd); // Respawn homunculus.
+
+ // Return true
+ script_pushint(st,true);
+ return true;
+}
+
+
+/*==========================================
+ * Returns the Homunculus sleep status
+ *------------------------------------------*/
+BUILDIN(homstatus)
+{
+ struct map_session_data *sd = script->rid2sd(st);
+ if (sd == NULL || sd->hd == NULL)
+ return true;
+
+ // Return the status (0 - active; 1 - resting ; 2 - mission)
+ // BUT Dead homunculus is not active (send RESTING instead)
+ if (!sd->hd->homunculus.vaporize && !homun_alive(sd->hd))
+ script_pushint(st,1);
+ else
+ script_pushint(st,sd->hd->homunculus.vaporize);
+ return true;
+}
+
+
+/*==========================================
+ * return the updated stats of sd (use bonus constants)
+ * Supported values: bStr~bLuk, bMaxHP, bMaxSP, bDef, bMdef, bAtk
+ *------------------------------------------*/
+BUILDIN(readparam2)
+{
+ struct map_session_data *sd;
+ int data = script_getnum(st,2);
+
+ // Account ID/Player Name is also supported
+ if (script_hasdata(st, 3)) {
+ if (script_isstringtype(st, 3)) {
+ sd = script->nick2sd(st, script_getstr(st, 3));
+ } else {
+ sd = script->id2sd(st, script_getnum(st, 3));
+ }
+ } else {
+ sd = script->rid2sd(st);
+ }
+
+ // Error
+ if (sd == NULL) {
+ script_pushint(st, -1);
+ return true;
+ }
+
+ switch (data) {
+ case 13:
+ script_pushint(st, sd->battle_status.str);
+ break;
+ case 14:
+ script_pushint(st, sd->battle_status.agi);
+ break;
+ case 15:
+ script_pushint(st, sd->battle_status.vit);
+ break;
+ case 16:
+ script_pushint(st, sd->battle_status.int_);
+ break;
+ case 17:
+ script_pushint(st, sd->battle_status.dex);
+ break;
+ case 18:
+ script_pushint(st, sd->battle_status.luk);
+ break;
+ case 6:
+ script_pushint(st, sd->battle_status.max_hp);
+ break;
+ case 8:
+ script_pushint(st, sd->battle_status.max_sp);
+ break;
+ case 45:
+ script_pushint(st, sd->battle_status.def);
+ break;
+ case 41:
+ script_pushint(st, sd->battle_status.batk+sd->battle_status.rhw.atk);
+ break;
+ default:
+ ShowError("Wrong paramType in readparam2(%d)\nAre you sure you used bonus constants?\nSupported values: bMaxHP, bMaxSP, bStr, bAgi, bVit, bInt, bDex, bLuk, bAtk, bDef\n", data);
+ script_pushint(st, -1);
+ break;
+ }
+
+ return true;
+}
+
+/*==========================================
+ *
+ *------------------------------------------*/
+BUILDIN(debugmes)
+{
+ struct StringBuf buf;
+ StrBuf->Init(&buf);
+
+ if (!script->sprintf_helper(st, 2, &buf)) {
+ StrBuf->Destroy(&buf);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ ShowDebug("script debug : %d %d : %s\n", st->rid, st->oid, StrBuf->Value(&buf));
+ StrBuf->Destroy(&buf);
+ script_pushint(st, 1);
+ return true;
+}
+
+/*==========================================
+ *
+ *------------------------------------------*/
+BUILDIN(countitem)
+{
+ int count = 0;
+ struct item_data* id = NULL;
+ struct map_session_data *sd;
+
+ if (script_hasdata(st,3)) {
+ int account_id = script_getnum(st,3);
+ sd = script->id2sd(st, account_id); // <account id>
+ if (sd == NULL) {
+ return true;
+ }
+ } else {
+ sd = script->rid2sd(st);// attached player
+ if (sd == NULL)
+ return true;
+ }
+
+ if (sd == NULL)
+ return true;
+
+ 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_pushint(st,0);
+ return false;
+ }
+
+ int nameid = id->nameid;
+
+ for (int i = 0; i < sd->status.inventorySize; i++) {
+ if (sd->status.inventory[i].nameid == nameid)
+ count += sd->status.inventory[i].amount;
+ }
+
+ script_pushint(st,count);
+ return true;
+}
+
diff --git a/src/emap/script_buildins.h b/src/emap/script_buildins.h
index fab271e..e8fdcf7 100644
--- a/src/emap/script_buildins.h
+++ b/src/emap/script_buildins.h
@@ -13,6 +13,7 @@ BUILDIN(restoreCam);
BUILDIN(npcTalk3);
BUILDIN(closeDialog);
BUILDIN(closeClientDialog);
+BUILDIN(npcshopattach);
BUILDIN(shop);
BUILDIN(getItemLink);
BUILDIN(requestLang);
@@ -99,5 +100,26 @@ BUILDIN(getItemOptionValueByIndex);
BUILDIN(getItemOptionParamByIndex);
BUILDIN(setItemOptionByIndex);
BUILDIN(isInstance);
+BUILDIN(readBattleParam);
+
+// TMW2 Build Ins
+BUILDIN(getguildinfo);
+BUILDIN(getguildlvl);
+BUILDIN(getguildavg);
+BUILDIN(getguildexp);
+BUILDIN(getguildnxp);
+BUILDIN(getguildpostax);
+BUILDIN(getguildpostitle);
+BUILDIN(setguildrole);
+BUILDIN(getguildmember);
+BUILDIN(gethomunexp);
+BUILDIN(deployhomunculus);
+BUILDIN(recallhomunculus);
+BUILDIN(homstatus);
+BUILDIN(readparam2);
+
+// Overrides
+BUILDIN(countitem);
+BUILDIN(debugmes);
#endif // EVOL_MAP_SCRIPT_BUILDINS
diff --git a/src/emap/skill.c b/src/emap/skill.c
index 20e4a82..2cf45cc 100644
--- a/src/emap/skill.c
+++ b/src/emap/skill.c
@@ -19,6 +19,7 @@
#include "map/pc.h"
#include "map/npc.h"
#include "map/script.h"
+#include "map/skill.h"
#include "emap/skill.h"
#include "emap/skill_const.h"
@@ -259,3 +260,79 @@ void eskill_validate_additional_fields(struct config_setting_t *conf,
skilld->miscEffects[1] = i32;
}
}
+
+int eskill_calc_heal_post(int retVal,
+ struct block_list *src,
+ struct block_list *target,
+ uint16 skill_id,
+ uint16 skill_lv __attribute__ ((unused)),
+ bool heal __attribute__ ((unused))) {
+
+ // Rebuild some data I need
+ int hp = 0;
+ int skill2_lv, tmp, tmp1;
+ struct map_session_data *sd = BL_CAST(BL_PC, src);
+ struct map_session_data *tsd = BL_CAST(BL_PC, target);
+
+ // Only affects healing
+ if (sd && tsd && skill_id == AL_HEAL) {
+ ShowDebug("Skill is healing and SD is set. ACC ID %d.\n", sd->login_id2);
+ // Only if self-target
+ if (sd->login_id2 == tsd->login_id2) {
+ // Recalculate everything with VIT instead
+ hp = (status->get_lv(src) + status_get_vit(src)) / 5 * 30 * skill_lv / 10;
+ // Skill bonuses
+ if (sd && (skill2_lv = pc->skillheal_bonus(sd, skill_id)) != 0)
+ hp += hp*skill2_lv/100;
+
+ if (tsd && (skill2_lv = pc->skillheal2_bonus(tsd, skill_id)) != 0)
+ hp += hp*skill2_lv/100;
+
+ // Preprare the possible healing bonus
+ tmp = status->get_total_def(src)*2;
+ tmp1 = status->get_matk(src, 3);
+ // Use the highest from both
+ if (tmp > tmp1)
+ hp+=tmp;
+ else
+ hp+=tmp1;
+ ShowDebug("Redefined (idx=%d original %d)\n", hp, retVal);
+ ShowDebug("TMP %d TMP1 %d Won %d)\n", tmp, tmp1, hp);
+ }
+ }
+ if (hp)
+ return hp;
+ else
+ return retVal;
+}
+
+int eskill_consume_requirement_post(int retVal,
+ struct map_session_data *sd,
+ uint16 skill_id, uint16 skill_lv, short type)
+{
+ int i, n;
+ struct skill_condition req;
+
+ if (!sd)
+ return retVal;
+
+ //ShowInfo("crpost, Skill %d Level %d and type %d\n", skill_id, skill_lv, type);
+
+ req = skill->get_requirement(sd,skill_id,skill_lv);
+
+ // TODO We need more checks than only this
+ if (type == 1 && skill_id > EVOL_FIRST_SKILL) {
+ // Delete the items
+ for( i = 0; i < MAX_SKILL_ITEM_REQUIRE; ++i )
+ {
+ if( !req.itemid[i] )
+ continue;
+
+ if ((n = pc->search_inventory(sd,req.itemid[i])) != INDEX_NOT_FOUND)
+ pc->delitem(sd, n, req.amount[i], 0, DELITEM_SKILLUSE, LOG_TYPE_CONSUME);
+ }
+ }
+ return retVal;
+}
+
+
diff --git a/src/emap/skill.h b/src/emap/skill.h
index 51d7224..aa400d8 100644
--- a/src/emap/skill.h
+++ b/src/emap/skill.h
@@ -98,4 +98,15 @@ bool eskill_lookup_const(const struct config_setting_t *it,
const char *name,
int *value);
+int eskill_calc_heal_post(int retVal,
+ struct block_list *src,
+ struct block_list *target,
+ uint16 skill_id,
+ uint16 skill_lv __attribute__ ((unused)),
+ bool heal __attribute__ ((unused)));
+
+int eskill_consume_requirement_post(int retVal,
+ struct map_session_data *sd,
+ uint16 skill_id, uint16 skill_lv, short type);
+
#endif // EVOL_MAP_SKILL
diff --git a/src/emap/status.c b/src/emap/status.c
index 636a620..2d2a884 100644
--- a/src/emap/status.c
+++ b/src/emap/status.c
@@ -46,6 +46,20 @@ void eInitChangeTables(void)
SI_PHYSICAL_SHIELD,
SCB_DEF | SCB_DEF2 | SCB_ASPD);
+ // TMW2 Customs
+ //status->dbs->IconChangeTable[SC_INCSTR] = SI_TMW2_INCSTR;
+ status->dbs->IconChangeTable[SC_INCAGI] = SI_TMW2_INCAGI;
+ status->dbs->IconChangeTable[SC_INCVIT] = SI_TMW2_INCVIT;
+ status->dbs->IconChangeTable[SC_INCINT] = SI_TMW2_INCINT;
+ status->dbs->IconChangeTable[SC_INCDEX] = SI_TMW2_INCDEX;
+ status->dbs->IconChangeTable[SC_INCLUK] = SI_TMW2_INCLUK;
+
+ status->dbs->IconChangeTable[SC_INCHIT] = SI_TMW2_INCHIT;
+ status->dbs->IconChangeTable[SC_INCFLEE] = SI_TMW2_INCFLEE;
+ status->dbs->IconChangeTable[SC_WALKSPEED] = SI_TMW2_WALKSPEED;
+ status->dbs->IconChangeTable[SC_INCMHPRATE] = SI_TMW2_INCMHPRATE;
+ status->dbs->IconChangeTable[SC_INCMSPRATE] = SI_TMW2_INCMSPRATE;
+
// status->dbs->DisplayType[SC_PHYSICAL_SHIELD] = true;
}
diff --git a/src/emap/struct/mobdext.h b/src/emap/struct/mobdext.h
index 24c6f34..119ad3c 100644
--- a/src/emap/struct/mobdext.h
+++ b/src/emap/struct/mobdext.h
@@ -9,9 +9,11 @@ struct MobdExt
int walkMask;
int weaponAttacks[MAX_WEAPON_TYPE];
int skillAttacks[MAX_SKILL_DB];
+ /* Disabled in TMW2
int collisionDx;
int collisionDy;
int collisionMask;
+ */
};
#endif // EVOL_MAP_MOBDEXT