From 974222a8d3f189083205bf5d330de04a43226ad3 Mon Sep 17 00:00:00 2001 From: Smokexyz Date: Thu, 2 Mar 2017 19:24:48 +0800 Subject: Implementation of Item Options System. Allows the infusing of equipments with bonus item options. This feature is constrained to clients of packet versions greater than or equal to `20150226`. Item Options and their effects are defined server-side in `db/item_options.conf` and client side in `data/luafiles514/lua files/datainfo/addrandomoptionnametable.lub` The ID of the option must tally with the correct index of the description provided in the client side lua file to avoid bugs. IT_OPT_* keys and MAX_ITEM_OPTIONS macro are also exported from the source as constants. An additional flag `disable_options` has been added to sql, and as `DisableOptions: true/false (boolean, defaults to false !!for equipments only!!)` to item_db.conf files. Script commands documentation is also included. SQL file updates are included. Credits: [Smokexyz](https://github.com/Smokexyz) Style and Script Fixes by [Asheraf](https://github.com/Asheraf) Initial design Idea by [secretdataz](https://github.com/secretdataz) --- .gitignore | 2 +- db/item_options.conf | 1026 ++++++++++++++++++++ db/pre-re/item_db.conf | 1 + db/re/item_db.conf | 1 + doc/script_commands.txt | 44 + sql-files/logs.sql | 10 + sql-files/main.sql | 80 +- sql-files/upgrades/2017-03-02--11-40.sql | 93 ++ sql-files/upgrades/2017-03-05--08-09.sql | 15 + src/char/char.c | 51 +- src/char/int_auction.c | 42 +- src/char/int_mail.c | 43 +- src/char/int_storage.c | 71 +- src/common/HPMDataCheck.h | 3 +- src/common/mmo.h | 12 + src/map/clif.c | 92 +- src/map/clif.h | 2 +- src/map/itemdb.c | 156 ++- src/map/itemdb.h | 24 +- src/map/log.c | 13 +- src/map/npc.c | 15 + src/map/packets_struct.h | 6 +- src/map/script.c | 245 ++++- src/map/status.c | 37 +- src/map/status.h | 1 + src/map/storage.c | 9 +- src/plugins/HPMHooking/HPMHooking.Defs.inc | 12 +- .../HPMHooking/HPMHooking_map.HPMHooksCore.inc | 24 +- .../HPMHooking/HPMHooking_map.HookingPoints.inc | 6 +- src/plugins/HPMHooking/HPMHooking_map.Hooks.inc | 141 ++- src/plugins/db2sql.c | 4 + 31 files changed, 2131 insertions(+), 150 deletions(-) create mode 100644 db/item_options.conf create mode 100644 sql-files/upgrades/2017-03-02--11-40.sql create mode 100644 sql-files/upgrades/2017-03-05--08-09.sql diff --git a/.gitignore b/.gitignore index 1587868fe..c48554520 100644 --- a/.gitignore +++ b/.gitignore @@ -18,11 +18,11 @@ Thumbs.db /*.pid /*.sdf /*.stackdump -/*.suo /*.exp /*.lib /*.VC.db /*.VC.opendb +/.vs/ /autom4te.cache/ /start-log.txt /char-server diff --git a/db/item_options.conf b/db/item_options.conf new file mode 100644 index 000000000..fb0efa170 --- /dev/null +++ b/db/item_options.conf @@ -0,0 +1,1026 @@ +//================= Hercules Database ===================================== +//= _ _ _ +//= | | | | | | +//= | |_| | ___ _ __ ___ _ _| | ___ ___ +//= | _ |/ _ \ '__/ __| | | | |/ _ \/ __| +//= | | | | __/ | | (__| |_| | | __/\__ \ +//= \_| |_/\___|_| \___|\__,_|_|\___||___/ +//================= License =============================================== +//= This file is part of Hercules. +//= http://herc.ws - http://github.com/HerculesWS/Hercules +//= +//= Copyright (C) 2017 Hercules Dev Team +//= +//= Hercules is free software: you can redistribute it and/or modify +//= it under the terms of the GNU General Public License as published by +//= the Free Software Foundation, either version 3 of the License, or +//= (at your option) any later version. +//= +//= This program is distributed in the hope that it will be useful, +//= but WITHOUT ANY WARRANTY; without even the implied warranty of +//= MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//= GNU General Public License for more details. +//= +//= You should have received a copy of the GNU General Public License +//= along with this program. If not, see . +//========================================================================= +//= Items Options Database +//========================================================================= + +item_options_db: ( +/************************************************************************** + ************* Entry structure ******************************************** + ************************************************************************** +{ + Id: (int) This value must be unique, with an index + that is represented client-side in + data/luafiles514/lua files/datainfo/addrandomoptionnametable.lub + Name: (string) Must be a unique string since it is used + as a constant. + Script: <""> Script effect of the option. Utilizes getequippedoptioninfo + for a variable bonus effect. +}, +*/ +{ + Id: 1 + Name: "VAR_MAXHPAMOUNT" + Script: <" bonus(bMaxHP, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 2 + Name: "VAR_MAXSPAMOUNT" + Script: <" bonus(bMaxSP, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 3 + Name: "VAR_STRAMOUNT" + Script: <" bonus(bStr, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 4 + Name: "VAR_AGIAMOUNT" + Script: <" bonus(bAgi, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 5 + Name: "VAR_VITAMOUNT" + Script: <" bonus(bVit, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 6 + Name: "VAR_INTAMOUNT" + Script: <" bonus(bInt, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 7 + Name: "VAR_DEXAMOUNT" + Script: <" bonus(bDex, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 8 + Name: "VAR_LUKAMOUNT" + Script: <" bonus(bLuk, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 9 + Name: "VAR_MAXHPPERCENT" + Script: <" bonus(bMaxHPrate, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 10 + Name: "VAR_MAXSPPERCENT" + Script: <" bonus(bMaxSPrate, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 11 + Name: "VAR_HPACCELERATION" + Script: <" bonus(bHPrecovRate, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 12 + Name: "VAR_SPACCELERATION" + Script: <" bonus(bSPrecovRate, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 13 + Name: "VAR_ATKPERCENT" + Script: <" bonus(bAtkRate, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 14 + Name: "VAR_MAGICATKPERCENT" + Script: <" bonus(bMatkRate, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 15 + Name: "VAR_PLUSASPD" + Script: <" bonus(bAspd, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 16 + Name: "VAR_PLUSASPDPERCENT" + Script: <" bonus(bAspdRate, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 17 + Name: "VAR_ATTPOWER" + Script: <" bonus(bAtk, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 18 + Name: "VAR_HITSUCCESSVALUE" + Script: <" bonus(bHit, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 19 + Name: "VAR_ATTMPOWER" + Script: <" bonus(bMatk, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 20 + Name: "VAR_ITEMDEFPOWER" + Script: <" bonus(bDef, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 21 + Name: "VAR_MDEFPOWER" + Script: <" bonus(bMdef, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 22 + Name: "VAR_AVOIDSUCCESSVALUE" + Script: <" bonus(bFlee, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 23 + Name: "VAR_PLUSAVOIDSUCCESSVALUE" + Script: <" bonus(bFlee2, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 24 + Name: "VAR_CRITICALSUCCESSVALUE" + Script: <" bonus(bCritical, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 25 + Name: "ATTR_TOLERACE_NOTHING" + Script: <" bonus2(bSubEle, Ele_Neutral, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 26 + Name: "ATTR_TOLERACE_WATER" + Script: <" bonus2(bSubEle, Ele_Water, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 27 + Name: "ATTR_TOLERACE_GROUND" + Script: <" bonus2(bSubEle, Ele_Earth, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 28 + Name: "ATTR_TOLERACE_FIRE" + Script: <" bonus2(bSubEle, Ele_Fire, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 29 + Name: "ATTR_TOLERACE_WIND" + Script: <" bonus2(bSubEle, Ele_Wind, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 30 + Name: "ATTR_TOLERACE_POISON" + Script: <" bonus2(bSubEle, Ele_Poison, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 31 + Name: "ATTR_TOLERACE_SAINT" + Script: <" bonus2(bSubEle, Ele_Holy, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 32 + Name: "ATTR_TOLERACE_DARKNESS" + Script: <" bonus2(bSubEle, Ele_Dark, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 33 + Name: "ATTR_TOLERACE_TELEKINESIS" + Script: <" bonus2(bSubEle, Ele_Ghost, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 34 + Name: "ATTR_TOLERACE_UNDEAD" + Script: <" bonus2(bSubEle, Ele_Undead, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 35 + Name: "ATTR_TOLERACE_ALL" + Script: <" bonus2(bSubEle, Ele_All, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +// TODO: Confirm if damage reduction is implemented correctly. +// kRO desc : 몬스터로부터 받는 물리 데미지 %d%% 감소. +{ + Id: 36 + Name: "DAMAGE_PROPERTY_NOTHING_USER" + Script: <" bonus3(bSubEle, Ele_Neutral, getequippedoptioninfo(IT_OPT_VALUE), BF_NORMAL); "> +}, +{ + Id: 37 + Name: "DAMAGE_PROPERTY_NOTHING_TARGET" + Script: <" bonus2(bAddEle, Ele_Neutral, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 38 + Name: "DAMAGE_PROPERTY_WATER_USER" + Script: <" bonus3(bSubEle, Ele_Water, getequippedoptioninfo(IT_OPT_VALUE), BF_NORMAL); "> +}, +{ + Id: 39 + Name: "DAMAGE_PROPERTY_WATER_TARGET" + Script: <" bonus2(bAddEle, Ele_Water, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 40 + Name: "DAMAGE_PROPERTY_GROUND_USER" + Script: <" bonus3(bSubEle, Ele_Earth, getequippedoptioninfo(IT_OPT_VALUE), BF_NORMAL); "> +}, +{ + Id: 41 + Name: "DAMAGE_PROPERTY_GROUND_TARGET" + Script: <" bonus2(bAddEle, Ele_Earth, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 42 + Name: "DAMAGE_PROPERTY_FIRE_USER" + Script: <" bonus3(bSubEle, Ele_Fire, getequippedoptioninfo(IT_OPT_VALUE), BF_NORMAL); "> +}, +{ + Id: 43 + Name: "DAMAGE_PROPERTY_FIRE_TARGET" + Script: <" bonus2(bAddEle, Ele_Fire, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 44 + Name: "DAMAGE_PROPERTY_WIND_USER" + Script: <" bonus3(bSubEle, Ele_Wind, getequippedoptioninfo(IT_OPT_VALUE), BF_NORMAL); "> +}, +{ + Id: 45 + Name: "DAMAGE_PROPERTY_WIND_TARGET" + Script: <" bonus2(bAddEle, Ele_Wind, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 46 + Name: "DAMAGE_PROPERTY_POISON_USER" + Script: <" bonus3(bSubEle, Ele_Poison, getequippedoptioninfo(IT_OPT_VALUE), BF_NORMAL); "> +}, +{ + Id: 47 + Name: "DAMAGE_PROPERTY_POISON_TARGET" + Script: <" bonus2(bAddEle, Ele_Poison, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 48 + Name: "DAMAGE_PROPERTY_SAINT_USER" + Script: <" bonus3(bSubEle, Ele_Holy, getequippedoptioninfo(IT_OPT_VALUE), BF_NORMAL); "> +}, +{ + Id: 49 + Name: "DAMAGE_PROPERTY_SAINT_TARGET" + Script: <" bonus2(bAddEle, Ele_Holy, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 50 + Name: "DAMAGE_PROPERTY_DARKNESS_USER" + Script: <" bonus3(bSubEle, Ele_Dark, getequippedoptioninfo(IT_OPT_VALUE), BF_NORMAL); "> +}, +{ + Id: 51 + Name: "DAMAGE_PROPERTY_DARKNESS_TARGET" + Script: <" bonus2(bAddEle, Ele_Dark, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 52 + Name: "DAMAGE_PROPERTY_TELEKINESIS_USER" + Script: <" bonus3(bSubEle, Ele_Ghost, getequippedoptioninfo(IT_OPT_VALUE), BF_NORMAL); "> +}, +{ + Id: 53 + Name: "DAMAGE_PROPERTY_TELEKINESIS_TARGET" + Script: <" bonus2(bAddEle, Ele_Ghost, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 54 + Name: "DAMAGE_PROPERTY_UNDEAD_USER" + Script: <" bonus3(bSubEle, Ele_Undead, getequippedoptioninfo(IT_OPT_VALUE), BF_NORMAL); "> +}, +{ + Id: 55 + Name: "DAMAGE_PROPERTY_UNDEAD_TARGET" + Script: <" bonus2(bAddEle, Ele_Undead, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 56 + Name: "MDAMAGE_PROPERTY_NOTHING_USER" + Script: <" bonus3(bSubEle, Ele_Neutral, getequippedoptioninfo(IT_OPT_VALUE), BF_MAGIC); "> +}, +{ + Id: 57 + Name: "MDAMAGE_PROPERTY_NOTHING_TARGET" + Script: <" bonus2(bMagicAddEle, Ele_Neutral, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 58 + Name: "MDAMAGE_PROPERTY_WATER_USER" + Script: <" bonus3(bSubEle, Ele_Water, getequippedoptioninfo(IT_OPT_VALUE), BF_MAGIC); "> +}, +{ + Id: 59 + Name: "MDAMAGE_PROPERTY_WATER_TARGET" + Script: <" bonus2(bMagicAddEle, Ele_Water, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 60 + Name: "MDAMAGE_PROPERTY_GROUND_USER" + Script: <" bonus3(bSubEle, Ele_Earth, getequippedoptioninfo(IT_OPT_VALUE), BF_MAGIC); "> +}, +{ + Id: 61 + Name: "MDAMAGE_PROPERTY_GROUND_TARGET" + Script: <" bonus2(bMagicAddEle, Ele_Earth, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 62 + Name: "MDAMAGE_PROPERTY_FIRE_USER" + Script: <" bonus3(bSubEle, Ele_Fire, getequippedoptioninfo(IT_OPT_VALUE), BF_MAGIC); "> +}, +{ + Id: 63 + Name: "MDAMAGE_PROPERTY_FIRE_TARGET" + Script: <" bonus2(bMagicAddEle, Ele_Fire, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 64 + Name: "MDAMAGE_PROPERTY_WIND_USER" + Script: <" bonus3(bSubEle, Ele_Wind, getequippedoptioninfo(IT_OPT_VALUE), BF_MAGIC); "> +}, +{ + Id: 65 + Name: "MDAMAGE_PROPERTY_WIND_TARGET" + Script: <" bonus2(bMagicAddEle, Ele_Wind, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 66 + Name: "MDAMAGE_PROPERTY_POISON_USER" + Script: <" bonus3(bSubEle, Ele_Poison, getequippedoptioninfo(IT_OPT_VALUE), BF_MAGIC); "> +}, +{ + Id: 67 + Name: "MDAMAGE_PROPERTY_POISON_TARGET" + Script: <" bonus2(bMagicAddEle, Ele_Poison, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 68 + Name: "MDAMAGE_PROPERTY_SAINT_USER" + Script: <" bonus3(bSubEle, Ele_Holy, getequippedoptioninfo(IT_OPT_VALUE), BF_MAGIC); "> +}, +{ + Id: 69 + Name: "MDAMAGE_PROPERTY_SAINT_TARGET" + Script: <" bonus2(bMagicAddEle, Ele_Holy, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 70 + Name: "MDAMAGE_PROPERTY_DARKNESS_USER" + Script: <" bonus3(bSubEle, Ele_Dark, getequippedoptioninfo(IT_OPT_VALUE), BF_MAGIC); "> +}, +{ + Id: 71 + Name: "MDAMAGE_PROPERTY_DARKNESS_TARGET" + Script: <" bonus2(bMagicAddEle, Ele_Dark, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 72 + Name: "MDAMAGE_PROPERTY_TELEKINESIS_USER" + Script: <" bonus3(bSubEle, Ele_Ghost, getequippedoptioninfo(IT_OPT_VALUE), BF_MAGIC); "> +}, +{ + Id: 73 + Name: "MDAMAGE_PROPERTY_TELEKINESIS_TARGET" + Script: <" bonus2(bMagicAddEle, Ele_Ghost, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 74 + Name: "MDAMAGE_PROPERTY_UNDEAD_USER" + Script: <" bonus3(bSubEle, Ele_Undead, getequippedoptioninfo(IT_OPT_VALUE), BF_MAGIC); "> +}, +{ + Id: 75 + Name: "MDAMAGE_PROPERTY_UNDEAD_TARGET" + Script: <" bonus2(bMagicAddEle, Ele_Undead, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 76 + Name: "BODY_ATTR_NOTHING" + Script: <" bonus(bDefEle, Ele_Neutral); "> +}, +{ + Id: 77 + Name: "BODY_ATTR_WATER" + Script: <" bonus(bDefEle, Ele_Water); "> +}, +{ + Id: 78 + Name: "BODY_ATTR_GROUND" + Script: <" bonus(bDefEle, Ele_Earth); "> +}, +{ + Id: 79 + Name: "BODY_ATTR_FIRE" + Script: <" bonus(bDefEle, Ele_Fire); "> +}, +{ + Id: 80 + Name: "BODY_ATTR_WIND" + Script: <" bonus(bDefEle, Ele_Wind); "> +}, +{ + Id: 81 + Name: "BODY_ATTR_POISON" + Script: <" bonus(bDefEle, Ele_Poison); "> +}, +{ + Id: 82 + Name: "BODY_ATTR_SAINT" + Script: <" bonus(bDefEle, Ele_Holy); "> +}, +{ + Id: 83 + Name: "BODY_ATTR_DARKNESS" + Script: <" bonus(bDefEle, Ele_Dark); "> +}, +{ + Id: 84 + Name: "BODY_ATTR_TELEKINESIS" + Script: <" bonus(bDefEle, Ele_Ghost); "> +}, +{ + Id: 85 + Name: "BODY_ATTR_UNDEAD" + Script: <" bonus(bDefEle, Ele_Undead); "> +}, +{ + Id: 86 + Name: "BODY_ATTR_ALL" + Script: <" /* Needs more info */ "> +}, +{ + Id: 87 + Name: "RACE_TOLERACE_NOTHING" + Script: <" + if (RENEWAL) + bonus2(bAddRaceTolerance, RC_Formless, getequippedoptioninfo(IT_OPT_VALUE)); + else + bonus2(bSubRace, RC_Formless, getequippedoptioninfo(IT_OPT_VALUE)); + "> +}, +{ + Id: 88 + Name: "RACE_TOLERACE_UNDEAD" + Script: <" + if (RENEWAL) + bonus2(bAddRaceTolerance, RC_Undead, getequippedoptioninfo(IT_OPT_VALUE)); + else + bonus2(bSubRace, RC_Undead, getequippedoptioninfo(IT_OPT_VALUE)); + "> +}, +{ + Id: 89 + Name: "RACE_TOLERACE_ANIMAL" + Script: <" + if (RENEWAL) + bonus2(bAddRaceTolerance, RC_Brute, getequippedoptioninfo(IT_OPT_VALUE)); + else + bonus2(bSubRace, RC_Brute, getequippedoptioninfo(IT_OPT_VALUE)); + "> +}, +{ + Id: 90 + Name: "RACE_TOLERACE_PLANT" + Script: <" + if (RENEWAL) + bonus2(bAddRaceTolerance, RC_Plant, getequippedoptioninfo(IT_OPT_VALUE)); + else + bonus2(bSubRace, RC_Plant, getequippedoptioninfo(IT_OPT_VALUE)); + "> +}, +{ + Id: 91 + Name: "RACE_TOLERACE_INSECT" + Script: <" + if (RENEWAL) + bonus2(bAddRaceTolerance, RC_Insect, getequippedoptioninfo(IT_OPT_VALUE)); + else + bonus2(bSubRace, RC_Insect, getequippedoptioninfo(IT_OPT_VALUE)); + "> +}, +{ + Id: 92 + Name: "RACE_TOLERACE_FISHS" + Script: <" + if (RENEWAL) + bonus2(bAddRaceTolerance, RC_Fish, getequippedoptioninfo(IT_OPT_VALUE)); + else + bonus2(bSubRace, RC_Fish, getequippedoptioninfo(IT_OPT_VALUE)); + "> +}, +{ + Id: 93 + Name: "RACE_TOLERACE_DEVIL" + Script: <" + if (RENEWAL) + bonus2(bAddRaceTolerance, RC_Demon, getequippedoptioninfo(IT_OPT_VALUE)); + else + bonus2(bSubRace, RC_Demon, getequippedoptioninfo(IT_OPT_VALUE)); + "> +}, +{ + Id: 94 + Name: "RACE_TOLERACE_HUMAN" + Script: <" + if (RENEWAL) + bonus2(bAddRaceTolerance, RC_DemiPlayer, getequippedoptioninfo(IT_OPT_VALUE)); + else + bonus2(bSubRace, RC_DemiPlayer, getequippedoptioninfo(IT_OPT_VALUE)); + "> +}, +{ + Id: 95 + Name: "RACE_TOLERACE_ANGEL" + Script: <" + if (RENEWAL) + bonus2(bAddRaceTolerance, RC_Angel, getequippedoptioninfo(IT_OPT_VALUE)); + else + bonus2(bSubRace, RC_Angel, getequippedoptioninfo(IT_OPT_VALUE)); + "> +}, +{ + Id: 96 + Name: "RACE_TOLERACE_DRAGON" + Script: <" + if (RENEWAL) + bonus2(bAddRaceTolerance, RC_Dragon, getequippedoptioninfo(IT_OPT_VALUE)); + else + bonus2(bSubRace, RC_Dragon, getequippedoptioninfo(IT_OPT_VALUE)); + "> +}, +{ + Id: 97 + Name: "RACE_DAMAGE_NOTHING" + Script: <" bonus2(bAddRace, RC_Formless, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 98 + Name: "RACE_DAMAGE_UNDEAD" + Script: <" bonus2(bAddRace, RC_Undead, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 99 + Name: "RACE_DAMAGE_ANIMAL" + Script: <" bonus2(bAddRace, RC_Brute, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 100 + Name: "RACE_DAMAGE_PLANT" + Script: <" bonus2(bAddRace, RC_Plant, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 101 + Name: "RACE_DAMAGE_INSECT" + Script: <" bonus2(bAddRace, RC_Insect, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 102 + Name: "RACE_DAMAGE_FISHS" + Script: <" bonus2(bAddRace, RC_Fish, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 103 + Name: "RACE_DAMAGE_DEVIL" + Script: <" bonus2(bAddRace, RC_Demon, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 104 + Name: "RACE_DAMAGE_HUMAN" + Script: <" bonus2(bAddRace, RC_DemiPlayer, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 105 + Name: "RACE_DAMAGE_ANGEL" + Script: <" bonus2(bAddRace, RC_Angel, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 106 + Name: "RACE_DAMAGE_DRAGON" + Script: <" bonus2(bAddRace, RC_Dragon, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 107 + Name: "RACE_MDAMAGE_NOTHING" + Script: <" bonus2(bMagicAddRace, RC_Formless, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 108 + Name: "RACE_MDAMAGE_UNDEAD" + Script: <" bonus2(bMagicAddRace, RC_Undead, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 109 + Name: "RACE_MDAMAGE_ANIMAL" + Script: <" bonus2(bMagicAddRace, RC_Brute, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 110 + Name: "RACE_MDAMAGE_PLANT" + Script: <" bonus2(bMagicAddRace, RC_Plant, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 111 + Name: "RACE_MDAMAGE_INSECT" + Script: <" bonus2(bMagicAddRace, RC_Insect, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 112 + Name: "RACE_MDAMAGE_FISHS" + Script: <" bonus2(bMagicAddRace, RC_Fish, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 113 + Name: "RACE_MDAMAGE_DEVIL" + Script: <" bonus2(bMagicAddRace, RC_Demon, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 114 + Name: "RACE_MDAMAGE_HUMAN" + Script: <" bonus2(bMagicAddRace, RC_DemiPlayer, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 115 + Name: "RACE_MDAMAGE_ANGEL" + Script: <" bonus2(bMagicAddRace, RC_Angel, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 116 + Name: "RACE_MDAMAGE_DRAGON" + Script: <" bonus2(bMagicAddRace, RC_Dragon, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 117 + Name: "RACE_CRI_PERCENT_NOTHING" + Script: <" bonus2(bCriticalAddRace, RC_Formless, getequippedoptioninfo(IT_OPT_VALUE) / 10); "> +}, +{ + Id: 118 + Name: "RACE_CRI_PERCENT_UNDEAD" + Script: <" bonus2(bCriticalAddRace, RC_Undead, getequippedoptioninfo(IT_OPT_VALUE) / 10); "> +}, +{ + Id: 119 + Name: "RACE_CRI_PERCENT_ANIMAL" + Script: <" bonus2(bCriticalAddRace, RC_Brute, getequippedoptioninfo(IT_OPT_VALUE) / 10); "> +}, +{ + Id: 120 + Name: "RACE_CRI_PERCENT_PLANT" + Script: <" bonus2(bCriticalAddRace, RC_Plant, getequippedoptioninfo(IT_OPT_VALUE) / 10); "> +}, +{ + Id: 121 + Name: "RACE_CRI_PERCENT_INSECT" + Script: <" bonus2(bCriticalAddRace, RC_Insect, getequippedoptioninfo(IT_OPT_VALUE) / 10); "> +}, +{ + Id: 122 + Name: "RACE_CRI_PERCENT_FISHS" + Script: <" bonus2(bCriticalAddRace, RC_Fish, getequippedoptioninfo(IT_OPT_VALUE) / 10); "> +}, +{ + Id: 123 + Name: "RACE_CRI_PERCENT_DEVIL" + Script: <" bonus2(bCriticalAddRace, RC_Demon, getequippedoptioninfo(IT_OPT_VALUE) / 10); "> +}, +{ + Id: 124 + Name: "RACE_CRI_PERCENT_HUMAN" + Script: <" bonus2(bCriticalAddRace, RC_DemiPlayer, getequippedoptioninfo(IT_OPT_VALUE) / 10); "> +}, +{ + Id: 125 + Name: "RACE_CRI_PERCENT_ANGEL" + Script: <" bonus2(bCriticalAddRace, RC_Angel, getequippedoptioninfo(IT_OPT_VALUE) / 10); "> +}, +{ + Id: 126 + Name: "RACE_CRI_PERCENT_DRAGON" + Script: <" bonus2(bCriticalAddRace, RC_Dragon, getequippedoptioninfo(IT_OPT_VALUE) / 10); "> +}, +{ + Id: 127 + Name: "RACE_IGNORE_DEF_PERCENT_NOTHING" + Script: <" bonus2(bIgnoreDefRaceRate, RC_Formless, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 128 + Name: "RACE_IGNORE_DEF_PERCENT_UNDEAD" + Script: <" bonus2(bIgnoreDefRaceRate, RC_Undead, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 129 + Name: "RACE_IGNORE_DEF_PERCENT_ANIMAL" + Script: <" bonus2(bIgnoreDefRaceRate, RC_Brute, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 130 + Name: "RACE_IGNORE_DEF_PERCENT_PLANT" + Script: <" bonus2(bIgnoreDefRaceRate, RC_Plant, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 131 + Name: "RACE_IGNORE_DEF_PERCENT_INSECT" + Script: <" bonus2(bIgnoreDefRaceRate, RC_Insect, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 132 + Name: "RACE_IGNORE_DEF_PERCENT_FISHS" + Script: <" bonus2(bIgnoreDefRaceRate, RC_Fish, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 133 + Name: "RACE_IGNORE_DEF_PERCENT_DEVIL" + Script: <" bonus2(bIgnoreDefRaceRate, RC_Demon, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 134 + Name: "RACE_IGNORE_DEF_PERCENT_HUMAN" + Script: <" bonus2(bIgnoreDefRaceRate, RC_DemiPlayer, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 135 + Name: "RACE_IGNORE_DEF_PERCENT_ANGEL" + Script: <" bonus2(bIgnoreDefRaceRate, RC_Angel, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 136 + Name: "RACE_IGNORE_DEF_PERCENT_DRAGON" + Script: <" bonus2(bIgnoreDefRaceRate, RC_Dragon, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 137 + Name: "RACE_IGNORE_MDEF_PERCENT_NOTHING" + Script: <" bonus2(bIgnoreMdefRaceRate, RC_Formless, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 138 + Name: "RACE_IGNORE_MDEF_PERCENT_UNDEAD" + Script: <" bonus2(bIgnoreMdefRaceRate, RC_Undead, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 139 + Name: "RACE_IGNORE_MDEF_PERCENT_ANIMAL" + Script: <" bonus2(bIgnoreMdefRaceRate, RC_Brute, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 140 + Name: "RACE_IGNORE_MDEF_PERCENT_PLANT" + Script: <" bonus2(bIgnoreMdefRaceRate, RC_Plant, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 141 + Name: "RACE_IGNORE_MDEF_PERCENT_INSECT" + Script: <" bonus2(bIgnoreMdefRaceRate, RC_Insect, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 142 + Name: "RACE_IGNORE_MDEF_PERCENT_FISHS" + Script: <" bonus2(bIgnoreMdefRaceRate, RC_Fish, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 143 + Name: "RACE_IGNORE_MDEF_PERCENT_DEVIL" + Script: <" bonus2(bIgnoreMdefRaceRate, RC_Demon, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 144 + Name: "RACE_IGNORE_MDEF_PERCENT_HUMAN" + Script: <" bonus2(bIgnoreMdefRaceRate, RC_DemiPlayer, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 145 + Name: "RACE_IGNORE_MDEF_PERCENT_ANGEL" + Script: <" bonus2(bIgnoreMdefRaceRate, RC_Angel, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 146 + Name: "RACE_IGNORE_MDEF_PERCENT_DRAGON" + Script: <" bonus2(bIgnoreMdefRaceRate, RC_Dragon, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 147 + Name: "CLASS_DAMAGE_NORMAL_TARGET" + Script: <" bonus2(bAddClass, Class_Normal, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 148 + Name: "CLASS_DAMAGE_BOSS_TARGET" + Script: <" bonus2(bAddClass, Class_Boss, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 149 + Name: "CLASS_DAMAGE_NORMAL_USER" + Script: <" bonus2(bSubClass, Class_Normal, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 150 + Name: "CLASS_DAMAGE_BOSS_USER" + Script: <" bonus2(bSubClass, Class_Boss, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 151 + Name: "CLASS_MDAMAGE_NORMAL" + Script: <" bonus2(bMagicAddClass, Class_Normal, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 152 + Name: "CLASS_MDAMAGE_BOSS" + Script: <" bonus2(bMagicAddClass, Class_Boss, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 153 + Name: "CLASS_IGNORE_DEF_PERCENT_NORMAL" + Script: <" bonus2(bIgnoreDefClassRate, Class_Normal, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 154 + Name: "CLASS_IGNORE_DEF_PERCENT_BOSS" + Script: <" bonus2(bIgnoreDefClassRate, Class_Boss, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 155 + Name: "CLASS_IGNORE_MDEF_PERCENT_NORMAL" + Script: <" bonus2(bIgnoreMdefClassRate, Class_Normal, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 156 + Name: "CLASS_IGNORE_MDEF_PERCENT_BOSS" + Script: <" bonus2(bIgnoreMdefClassRate, Class_Boss, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 157 + Name: "DAMAGE_SIZE_SMALL_TARGET" + Script: <" bonus2(bAddSize, Size_Small, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 158 + Name: "DAMAGE_SIZE_MIDIUM_TARGET" + Script: <" bonus2(bAddSize, Size_Medium, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 159 + Name: "DAMAGE_SIZE_LARGE_TARGET" + Script: <" bonus2(bAddSize, Size_Large, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 160 + Name: "DAMAGE_SIZE_SMALL_USER" + Script: <" bonus2(bSubSize, Size_Small, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 161 + Name: "DAMAGE_SIZE_MIDIUM_USER" + Script: <" bonus2(bSubSize, Size_Medium, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 162 + Name: "DAMAGE_SIZE_LARGE_USER" + Script: <" bonus2(bSubSize, Size_Large, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 163 + Name: "DAMAGE_SIZE_PERFECT" + Script: <" bonus(bNoSizeFix, 1); "> +}, +{ + Id: 164 + Name: "DAMAGE_CRI_TARGET" + Script: <" bonus(bCritAtkRate, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 165 + Name: "DAMAGE_CRI_USER" + Script: <" bonus(bCriticalDef, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 166 + Name: "RANGE_ATTACK_DAMAGE_TARGET" + Script: <" bonus(bLongAtkRate, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 167 + Name: "RANGE_ATTACK_DAMAGE_USER" + Script: <" bonus(bLongAtkDef, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 168 + Name: "HEAL_VALUE" + Script: <" bonus(bHealPower, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 169 + Name: "HEAL_MODIFY_PERCENT" + Script: <" bonus(bHealPower2, getequippedoptioninfo(IT_OPT_VALUE)); "> +}, +{ + Id: 170 + Name: "DEC_SPELL_CAST_TIME" + Script: <" bonus(bVariableCastrate, -(getequippedoptioninfo(IT_OPT_VALUE))); "> +}, +{ + Id: 171 + Name: "DEC_SPELL_DELAY_TIME" + Script: <" bonus(bDelayrate, -(getequippedoptioninfo(IT_OPT_VALUE))); "> +}, +{ + Id: 172 + Name: "DEC_SP_CONSUMPTION" + Script: <" bonus(bUseSPrate, -(getequippedoptioninfo(IT_OPT_VALUE))); "> +}, +{ + Id: 173 + Name: "HP_DRAIN" + Script: <" /* Needs more info */ "> +}, +{ + Id: 174 + Name: "SP_DRAIN" + Script: <" /* Needs more info */ "> +}, +{ + Id: 175 + Name: "WEAPON_ATTR_NOTHING" + Script: <" bonus(bAtkEle, Ele_Neutral); "> +}, +{ + Id: 176 + Name: "WEAPON_ATTR_WATER" + Script: <" bonus(bAtkEle, Ele_Water); "> +}, +{ + Id: 177 + Name: "WEAPON_ATTR_GROUND" + Script: <" bonus(bAtkEle, Ele_Earth); "> +}, +{ + Id: 178 + Name: "WEAPON_ATTR_FIRE" + Script: <" bonus(bAtkEle, Ele_Fire); "> +}, +{ + Id: 179 + Name: "WEAPON_ATTR_WIND" + Script: <" bonus(bAtkEle, Ele_Wind); "> +}, +{ + Id: 180 + Name: "WEAPON_ATTR_POISON" + Script: <" bonus(bAtkEle, Ele_Poison); "> +}, +{ + Id: 181 + Name: "WEAPON_ATTR_SAINT" + Script: <" bonus(bAtkEle, Ele_Holy); "> +}, +{ + Id: 182 + Name: "WEAPON_ATTR_DARKNESS" + Script: <" bonus(bAtkEle, Ele_Dark); "> +}, +{ + Id: 183 + Name: "WEAPON_ATTR_TELEKINESIS" + Script: <" bonus(bAtkEle, Ele_Ghost); "> +}, +{ + Id: 184 + Name: "WEAPON_ATTR_UNDEAD" + Script: <" bonus(bAtkEle, Ele_Undead); "> +}, +{ + Id: 185 + Name: "WEAPON_INDESTRUCTIBLE" + Script: <" bonus(bUnbreakableWeapon, 1); "> +}, +{ + Id: 186 + Name: "BODY_INDESTRUCTIBLE" + Script: <" bonus(bUnbreakableArmor, 1); "> +} +) diff --git a/db/pre-re/item_db.conf b/db/pre-re/item_db.conf index ed400e270..a681d5753 100644 --- a/db/pre-re/item_db.conf +++ b/db/pre-re/item_db.conf @@ -86,6 +86,7 @@ item_db: ( EquipLv: Equip required level (int, defaults to 0) EquipLv: [min, max] (alternative syntax with min / max level) Refine: Refineable (boolean, defaults to true) + DisableOptions: true/false (boolean, defaults to false !!for equipments only!!) [Smokexyz] View: View ID (int, defaults to 0) BindOnEquip: true/false (boolean, defaults to false) ForceSerial: true/false (boolean, defaults to false) diff --git a/db/re/item_db.conf b/db/re/item_db.conf index 67617bec9..f813bdbfa 100644 --- a/db/re/item_db.conf +++ b/db/re/item_db.conf @@ -86,6 +86,7 @@ item_db: ( EquipLv: Equip required level (int, defaults to 0) EquipLv: [min, max] (alternative syntax with min / max level) Refine: Refineable (boolean, defaults to true) + DisableOptions: true/false (boolean, defaults to false !!for equipments only!!) [Smokexyz] View: View ID (int, defaults to 0) BindOnEquip: true/false (boolean, defaults to false) ForceSerial: true/false (boolean, defaults to false) diff --git a/doc/script_commands.txt b/doc/script_commands.txt index a0e3a783d..0efe238c4 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -3133,6 +3133,50 @@ Check sample in doc/sample/getiteminfo.txt --------------------------------------- +*getequipisenableopt() + +This function checks if the equipped item allows the use of bonus options. + +Returns 1 if allowed, 0 if not. + +--------------------------------------- + +*getequippedoptioninfo(); + +This function is to be used with the scripts of contents listed in +db/item_options.conf only. + +Returns the value of the current equipment being parsed. +If the equip was not found or the type is invalid, -1 is returned. + +--------------------------------------- + +*getequipoptioninfo(,,); + +Gets the option information of an equipment. + + For a list of equipment indexes see getequipid(). + can range from 1 to MAX_ITEM_OPTIONS + can be IT_OPT_INDEX (the ID of the option bonus, @see "Id" or "Name" in db/item_options.conf) + or IT_OPT_VALUE (the value of the bonus script of the equipment, @see "Script" in db_item_options.conf). + +returns the value of the slot if exists or -1 for invalid slot, type or slots. + +--------------------------------------- + +*setequipoption(,,,); + +Set an equipment's option index or value for the specified option slot. + + For a list of equipment indexes see getequipid(). + can range from 1 to MAX_ITEM_OPTIONS + can be IT_OPT_INDEX (the ID of the option bonus, @see "Id" or "Name" in db/item_options.conf) + The value of the type to be set. + +returns 0 if value couldn't be set, 1 on success. + +--------------------------------------- + *getequipcardid(, ) Returns value for equipped item slot in the indicated slot (0, 1, 2, or 3). diff --git a/sql-files/logs.sql b/sql-files/logs.sql index 82c1c944c..c75fc37d2 100644 --- a/sql-files/logs.sql +++ b/sql-files/logs.sql @@ -152,6 +152,16 @@ CREATE TABLE IF NOT EXISTS `picklog` ( `card1` INT(11) NOT NULL DEFAULT '0', `card2` INT(11) NOT NULL DEFAULT '0', `card3` INT(11) NOT NULL DEFAULT '0', + `opt_idx0` smallint(5) unsigned NOT NULL default '0', + `opt_val0` smallint(5) unsigned NOT NULL default '0', + `opt_idx1` smallint(5) unsigned NOT NULL default '0', + `opt_val1` smallint(5) unsigned NOT NULL default '0', + `opt_idx2` smallint(5) unsigned NOT NULL default '0', + `opt_val2` smallint(5) unsigned NOT NULL default '0', + `opt_idx3` smallint(5) unsigned NOT NULL default '0', + `opt_val3` smallint(5) unsigned NOT NULL default '0', + `opt_idx4` smallint(5) unsigned NOT NULL default '0', + `opt_val4` smallint(5) unsigned NOT NULL default '0', `unique_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0', `map` VARCHAR(11) NOT NULL DEFAULT '', PRIMARY KEY (`id`), diff --git a/sql-files/main.sql b/sql-files/main.sql index aa9386179..3edbdbc3b 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -28,7 +28,7 @@ CREATE TABLE IF NOT EXISTS `account_data` ( `base_drop` SMALLINT(6) UNSIGNED NOT NULL DEFAULT '100', `base_death` SMALLINT(6) UNSIGNED NOT NULL DEFAULT '100', PRIMARY KEY (`account_id`) -) ENGINE=MyISAM; +) ENGINE=MyISAM; -- -- Table structure for table `acc_reg_num_db` @@ -79,6 +79,16 @@ CREATE TABLE IF NOT EXISTS `auction` ( `card1` SMALLINT(11) NOT NULL DEFAULT '0', `card2` SMALLINT(11) NOT NULL DEFAULT '0', `card3` SMALLINT(11) NOT NULL DEFAULT '0', + `opt_idx0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val0` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val1` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val2` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val3` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val4` SMALLINT(5) NOT NULL DEFAULT '0', `unique_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0', PRIMARY KEY (`auction_id`) ) ENGINE=MyISAM; @@ -93,7 +103,7 @@ CREATE TABLE IF NOT EXISTS `autotrade_data` ( `amount` INT(11) NOT NULL DEFAULT '0', `price` INT(11) NOT NULL DEFAULT '0', PRIMARY KEY (`char_id`,`itemkey`) -) ENGINE=MyISAM; +) ENGINE=MyISAM; -- -- Table structure for table `autotrade_merchants` @@ -105,7 +115,7 @@ CREATE TABLE IF NOT EXISTS `autotrade_merchants` ( `sex` TINYINT(2) NOT NULL DEFAULT '0', `title` VARCHAR(80) NOT NULL DEFAULT 'Buy From Me!', PRIMARY KEY (`account_id`,`char_id`) -) ENGINE=MyISAM; +) ENGINE=MyISAM; -- -- Table structure for table `cart_inventory` @@ -124,6 +134,16 @@ CREATE TABLE IF NOT EXISTS `cart_inventory` ( `card1` SMALLINT(11) NOT NULL DEFAULT '0', `card2` SMALLINT(11) NOT NULL DEFAULT '0', `card3` SMALLINT(11) NOT NULL DEFAULT '0', + `opt_idx0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val0` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val1` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val2` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val3` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val4` SMALLINT(5) NOT NULL DEFAULT '0', `expire_time` INT(11) UNSIGNED NOT NULL DEFAULT '0', `bound` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', `unique_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0', @@ -169,7 +189,7 @@ CREATE TABLE IF NOT EXISTS `char` ( `hair` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0', `hair_color` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', `clothes_color` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', - `body` SMALLINT(5) unsigned NOT NULL default '0', + `body` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', `weapon` SMALLINT(6) UNSIGNED NOT NULL DEFAULT '0', `shield` SMALLINT(6) UNSIGNED NOT NULL DEFAULT '0', `head_top` SMALLINT(6) UNSIGNED NOT NULL DEFAULT '0', @@ -203,7 +223,7 @@ CREATE TABLE IF NOT EXISTS `char` ( KEY `party_id` (`party_id`), KEY `guild_id` (`guild_id`), KEY `online` (`online`) -) ENGINE=MyISAM AUTO_INCREMENT=150000; +) ENGINE=MyISAM AUTO_INCREMENT=150000; -- -- Table structure for table `char_reg_num_db` @@ -469,6 +489,16 @@ CREATE TABLE IF NOT EXISTS `guild_storage` ( `card1` SMALLINT(11) NOT NULL DEFAULT '0', `card2` SMALLINT(11) NOT NULL DEFAULT '0', `card3` SMALLINT(11) NOT NULL DEFAULT '0', + `opt_idx0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val0` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val1` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val2` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val3` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val4` SMALLINT(5) NOT NULL DEFAULT '0', `expire_time` INT(11) UNSIGNED NOT NULL DEFAULT '0', `bound` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', `unique_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0', @@ -507,14 +537,14 @@ CREATE TABLE IF NOT EXISTS `homunculus` ( PRIMARY KEY (`homun_id`) ) ENGINE=MyISAM; --- +-- -- Table structure for table `interlog` -- CREATE TABLE IF NOT EXISTS `interlog` ( `time` DATETIME NULL, `log` VARCHAR(255) NOT NULL DEFAULT '' -) ENGINE=MyISAM; +) ENGINE=MyISAM; -- -- Table structure for table `inventory` @@ -533,6 +563,16 @@ CREATE TABLE IF NOT EXISTS `inventory` ( `card1` SMALLINT(11) NOT NULL DEFAULT '0', `card2` SMALLINT(11) NOT NULL DEFAULT '0', `card3` SMALLINT(11) NOT NULL DEFAULT '0', + `opt_idx0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val0` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val1` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val2` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val3` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val4` SMALLINT(5) NOT NULL DEFAULT '0', `expire_time` INT(11) UNSIGNED NOT NULL DEFAULT '0', `favorite` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', `bound` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', @@ -568,7 +608,7 @@ CREATE TABLE IF NOT EXISTS `login` ( `unban_time` INT(11) UNSIGNED NOT NULL DEFAULT '0', `expiration_time` INT(11) UNSIGNED NOT NULL DEFAULT '0', `logincount` MEDIUMINT(9) UNSIGNED NOT NULL DEFAULT '0', - `lastlogin` DATETIME NULL, + `lastlogin` DATETIME NULL, `last_ip` VARCHAR(100) NOT NULL DEFAULT '', `birthdate` DATE NULL, `character_slots` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0', @@ -576,7 +616,7 @@ CREATE TABLE IF NOT EXISTS `login` ( `pincode_change` INT(11) UNSIGNED NOT NULL DEFAULT '0', PRIMARY KEY (`account_id`), KEY `name` (`userid`) -) ENGINE=MyISAM AUTO_INCREMENT=2000000; +) ENGINE=MyISAM AUTO_INCREMENT=2000000; -- added standard accounts for servers, VERY INSECURE!!! -- inserted into the table called login which is above @@ -647,6 +687,16 @@ CREATE TABLE IF NOT EXISTS `mail` ( `card1` SMALLINT(11) NOT NULL DEFAULT '0', `card2` SMALLINT(11) NOT NULL DEFAULT '0', `card3` SMALLINT(11) NOT NULL DEFAULT '0', + `opt_idx0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val0` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val1` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val2` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val3` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val4` SMALLINT(5) NOT NULL DEFAULT '0', `unique_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=MyISAM; @@ -830,6 +880,8 @@ INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1467934919); -- 2016-07-0 INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1467935469); -- 2016-07-08--02-51.sql INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1475526420); -- 2016-10-03--20-27.sql INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1477434595); -- 2016-10-26--10-29.sql +INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1488454834); -- 2017-03-02--11-40.sql +INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1488744559); -- 2017-03-05--08-09.sql -- -- Table structure for table `storage` @@ -848,6 +900,16 @@ CREATE TABLE IF NOT EXISTS `storage` ( `card1` SMALLINT(11) NOT NULL DEFAULT '0', `card2` SMALLINT(11) NOT NULL DEFAULT '0', `card3` SMALLINT(11) NOT NULL DEFAULT '0', + `opt_idx0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val0` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val1` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val2` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val3` SMALLINT(5) NOT NULL DEFAULT '0', + `opt_idx4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `opt_val4` SMALLINT(5) NOT NULL DEFAULT '0', `expire_time` INT(11) UNSIGNED NOT NULL DEFAULT '0', `bound` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', `unique_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0', diff --git a/sql-files/upgrades/2017-03-02--11-40.sql b/sql-files/upgrades/2017-03-02--11-40.sql new file mode 100644 index 000000000..30798b5df --- /dev/null +++ b/sql-files/upgrades/2017-03-02--11-40.sql @@ -0,0 +1,93 @@ +#1488454834 + +-- This file is part of Hercules. +-- http://herc.ws - http://github.com/HerculesWS/Hercules +-- +-- Copyright (C) 2015-2016 Hercules Dev Team +-- +-- Hercules is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . + +ALTER TABLE `auction` + ADD COLUMN `opt_idx0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `card3`, + ADD COLUMN `opt_val0` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx0`, + ADD COLUMN `opt_idx1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val0`, + ADD COLUMN `opt_val1` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx1`, + ADD COLUMN `opt_idx2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val1`, + ADD COLUMN `opt_val2` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx2`, + ADD COLUMN `opt_idx3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val2`, + ADD COLUMN `opt_val3` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx3`, + ADD COLUMN `opt_idx4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val3`, + ADD COLUMN `opt_val4` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx4`; + +ALTER TABLE `cart_inventory` + ADD COLUMN `opt_idx0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `card3`, + ADD COLUMN `opt_val0` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx0`, + ADD COLUMN `opt_idx1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val0`, + ADD COLUMN `opt_val1` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx1`, + ADD COLUMN `opt_idx2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val1`, + ADD COLUMN `opt_val2` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx2`, + ADD COLUMN `opt_idx3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val2`, + ADD COLUMN `opt_val3` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx3`, + ADD COLUMN `opt_idx4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val3`, + ADD COLUMN `opt_val4` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx4`; + +ALTER TABLE `guild_storage` + ADD COLUMN `opt_idx0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `card3`, + ADD COLUMN `opt_val0` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx0`, + ADD COLUMN `opt_idx1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val0`, + ADD COLUMN `opt_val1` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx1`, + ADD COLUMN `opt_idx2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val1`, + ADD COLUMN `opt_val2` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx2`, + ADD COLUMN `opt_idx3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val2`, + ADD COLUMN `opt_val3` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx3`, + ADD COLUMN `opt_idx4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val3`, + ADD COLUMN `opt_val4` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx4`; + +ALTER TABLE `inventory` + ADD COLUMN `opt_idx0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `card3`, + ADD COLUMN `opt_val0` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx0`, + ADD COLUMN `opt_idx1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val0`, + ADD COLUMN `opt_val1` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx1`, + ADD COLUMN `opt_idx2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val1`, + ADD COLUMN `opt_val2` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx2`, + ADD COLUMN `opt_idx3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val2`, + ADD COLUMN `opt_val3` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx3`, + ADD COLUMN `opt_idx4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val3`, + ADD COLUMN `opt_val4` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx4`; + +ALTER TABLE `mail` + ADD COLUMN `opt_idx0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `card3`, + ADD COLUMN `opt_val0` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx0`, + ADD COLUMN `opt_idx1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val0`, + ADD COLUMN `opt_val1` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx1`, + ADD COLUMN `opt_idx2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val1`, + ADD COLUMN `opt_val2` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx2`, + ADD COLUMN `opt_idx3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val2`, + ADD COLUMN `opt_val3` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx3`, + ADD COLUMN `opt_idx4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val3`, + ADD COLUMN `opt_val4` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx4`; + +ALTER TABLE `storage` + ADD COLUMN `opt_idx0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `card3`, + ADD COLUMN `opt_val0` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx0`, + ADD COLUMN `opt_idx1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val0`, + ADD COLUMN `opt_val1` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx1`, + ADD COLUMN `opt_idx2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val1`, + ADD COLUMN `opt_val2` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx2`, + ADD COLUMN `opt_idx3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val2`, + ADD COLUMN `opt_val3` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx3`, + ADD COLUMN `opt_idx4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val3`, + ADD COLUMN `opt_val4` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx4`; + +INSERT INTO `sql_updates` (`timestamp`, `ignored`) VALUES (1488454834 , 'No'); diff --git a/sql-files/upgrades/2017-03-05--08-09.sql b/sql-files/upgrades/2017-03-05--08-09.sql new file mode 100644 index 000000000..3b5ee1a23 --- /dev/null +++ b/sql-files/upgrades/2017-03-05--08-09.sql @@ -0,0 +1,15 @@ +#1488744559 + +ALTER TABLE `picklog` + ADD COLUMN `opt_idx0` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `card3`, + ADD COLUMN `opt_val0` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx0`, + ADD COLUMN `opt_idx1` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val0`, + ADD COLUMN `opt_val1` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx1`, + ADD COLUMN `opt_idx2` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val1`, + ADD COLUMN `opt_val2` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx2`, + ADD COLUMN `opt_idx3` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val2`, + ADD COLUMN `opt_val3` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx3`, + ADD COLUMN `opt_idx4` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' AFTER `opt_val3`, + ADD COLUMN `opt_val4` SMALLINT(5) NOT NULL DEFAULT '0' AFTER `opt_idx4`; + +INSERT INTO `sql_updates` (`timestamp`, `ignored`) VALUES (1488744559 , 'No'); diff --git a/src/char/char.c b/src/char/char.c index 9314e8c81..4395ee9c2 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -745,6 +745,9 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`"); for (j = 0; j < MAX_SLOTS; ++j) StrBuf->Printf(&buf, ", `card%d`", j); + for (j = 0; j < MAX_ITEM_OPTIONS; ++j) + StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", j, j); + if (has_favorite) StrBuf->AppendStr(&buf, ", `favorite`"); StrBuf->Printf(&buf, " FROM `%s` WHERE `%s`='%d'", tablename, selectoption, id); @@ -769,9 +772,13 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl SQL->StmtBindColumn(stmt, 8, SQLDT_UCHAR, &item.bound, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 9, SQLDT_UINT64, &item.unique_id, 0, NULL, NULL); for (j = 0; j < MAX_SLOTS; ++j) - SQL->StmtBindColumn(stmt, 10+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 10 + j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); + for (j = 0; j < MAX_ITEM_OPTIONS; ++j) { + SQL->StmtBindColumn(stmt, 10 + MAX_SLOTS + j * 2, SQLDT_INT16, &item.option[j].index, 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 11 + MAX_SLOTS + j * 2, SQLDT_INT16, &item.option[j].value, 0, NULL, NULL); + } if (has_favorite) - SQL->StmtBindColumn(stmt, 10+MAX_SLOTS, SQLDT_UCHAR, &item.favorite, 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 10 + MAX_SLOTS + MAX_ITEM_OPTIONS * 2, SQLDT_UCHAR, &item.favorite, 0, NULL, NULL); // bit array indicating which inventory items have already been matched flag = aCalloc(max, sizeof(bool)); @@ -790,9 +797,12 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl && items[i].card[2] == item.card[2] && items[i].card[3] == item.card[3] ) { + int k = 0; // They are the same item. ARR_FIND(0, MAX_SLOTS, j, items[i].card[j] != item.card[j]); - if (j == MAX_SLOTS + ARR_FIND(0, MAX_ITEM_OPTIONS, k, items[i].option[k].index != item.option[k].index || items[i].option[k].value != item.option[k].value); + + if (j == MAX_SLOTS && k == MAX_ITEM_OPTIONS && items[i].amount == item.amount && items[i].equip == item.equip && items[i].identify == item.identify @@ -810,6 +820,8 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].bound); for (j = 0; j < MAX_SLOTS; ++j) StrBuf->Printf(&buf, ", `card%d`='%d'", j, items[i].card[j]); + for (j = 0; j < MAX_ITEM_OPTIONS; ++j) + StrBuf->Printf(&buf, ", `opt_idx%d`='%d', `opt_val%d`='%d'", j, items[i].option[j].index, j, items[i].option[j].value); if (has_favorite) StrBuf->Printf(&buf, ", `favorite`='%d'", items[i].favorite); StrBuf->Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id); @@ -838,6 +850,8 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl StrBuf->Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`", tablename, selectoption); for (j = 0; j < MAX_SLOTS; ++j) StrBuf->Printf(&buf, ", `card%d`", j); + for (j = 0; j < MAX_ITEM_OPTIONS; ++j) + StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", j, j); if (has_favorite) StrBuf->AppendStr(&buf, ", `favorite`"); StrBuf->AppendStr(&buf, ") VALUES "); @@ -858,6 +872,8 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].bound, items[i].unique_id); for (j = 0; j < MAX_SLOTS; ++j) StrBuf->Printf(&buf, ", '%d'", items[i].card[j]); + for (j = 0; j < MAX_ITEM_OPTIONS; ++j) + StrBuf->Printf(&buf, ", '%d', '%d'", items[i].option[j].index, items[i].option[j].value); if (has_favorite) StrBuf->Printf(&buf, ", '%d'", items[i].favorite); StrBuf->AppendStr(&buf, ")"); @@ -1188,8 +1204,10 @@ int char_mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_every //`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `expire_time`, `favorite`, `bound`, `unique_id`) StrBuf->Init(&buf); StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`, `unique_id`"); - for( i = 0; i < MAX_SLOTS; ++i ) + for (i = 0; i < MAX_SLOTS; ++i) StrBuf->Printf(&buf, ", `card%d`", i); + for (i = 0; i < MAX_ITEM_OPTIONS; ++i) + StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", i, i); StrBuf->Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", inventory_db, MAX_INVENTORY); memset(&tmp_item, 0, sizeof(tmp_item)); @@ -1209,8 +1227,14 @@ int char_mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_every || SQL_ERROR == SQL->StmtBindColumn(stmt, 10, SQLDT_UINT64, &tmp_item.unique_id, 0, NULL, NULL) ) SqlStmt_ShowDebug(stmt); - for( i = 0; i < MAX_SLOTS; ++i ) - if( SQL_ERROR == SQL->StmtBindColumn(stmt, 11+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) ) + /* Card Slots */ + for (i = 0; i < MAX_SLOTS; ++i) + if (SQL_ERROR == SQL->StmtBindColumn(stmt, 11 + i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL)) + SqlStmt_ShowDebug(stmt); + /* Item Options */ + for (i = 0; i < MAX_ITEM_OPTIONS; i++) + if (SQL_ERROR == SQL->StmtBindColumn(stmt, 11 + MAX_SLOTS + i * 2, SQLDT_INT16, &tmp_item.option[i].index, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 12 + MAX_SLOTS + i * 2, SQLDT_INT16, &tmp_item.option[i].value, 0, NULL, NULL)) SqlStmt_ShowDebug(stmt); for( i = 0; i < MAX_INVENTORY && SQL_SUCCESS == SQL->StmtNextRow(stmt); ++i ) @@ -1222,8 +1246,10 @@ int char_mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_every //`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, expire_time`, `bound`, `unique_id`) StrBuf->Clear(&buf); StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`"); - for( j = 0; j < MAX_SLOTS; ++j ) + for (j = 0; j < MAX_SLOTS; ++j) StrBuf->Printf(&buf, ", `card%d`", j); + for (j = 0; j < MAX_ITEM_OPTIONS; ++j) + StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", j, j); StrBuf->Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", cart_db, MAX_CART); memset(&tmp_item, 0, sizeof(tmp_item)); @@ -1243,12 +1269,19 @@ int char_mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_every ) { SqlStmt_ShowDebug(stmt); } - for( i = 0; i < MAX_SLOTS; ++i ) - if( SQL_ERROR == SQL->StmtBindColumn(stmt, 10+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) ) + /* Card Slots */ + for (i = 0; i < MAX_SLOTS; ++i) + if( SQL_ERROR == SQL->StmtBindColumn(stmt, 10 + i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) ) + SqlStmt_ShowDebug(stmt); + /* Item Options */ + for (i = 0; i < MAX_ITEM_OPTIONS; ++i) + if (SQL_ERROR == SQL->StmtBindColumn(stmt, 10 + MAX_SLOTS + i * 2, SQLDT_INT16, &tmp_item.option[i].index, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 11 + MAX_SLOTS + i * 2, SQLDT_INT16, &tmp_item.option[i].value, 0, NULL, NULL)) SqlStmt_ShowDebug(stmt); for( i = 0; i < MAX_CART && SQL_SUCCESS == SQL->StmtNextRow(stmt); ++i ) memcpy(&p->cart[i], &tmp_item, sizeof(tmp_item)); + strcat(t_msg, " cart"); //read storage diff --git a/src/char/int_auction.c b/src/char/int_auction.c index bf690327c..2dd65f213 100644 --- a/src/char/int_auction.c +++ b/src/char/int_auction.c @@ -71,8 +71,10 @@ void inter_auction_save(struct auction_data *auction) StrBuf->Init(&buf); StrBuf->Printf(&buf, "UPDATE `%s` SET `seller_id` = '%d', `seller_name` = ?, `buyer_id` = '%d', `buyer_name` = ?, `price` = '%d', `buynow` = '%d', `hours` = '%d', `timestamp` = '%lu', `nameid` = '%d', `item_name` = ?, `type` = '%d', `refine` = '%d', `attribute` = '%d'", auction_db, auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute); - for( j = 0; j < MAX_SLOTS; j++ ) + for (j = 0; j < MAX_SLOTS; j++) StrBuf->Printf(&buf, ", `card%d` = '%d'", j, auction->item.card[j]); + for (j = 0; j < MAX_ITEM_OPTIONS; j++) + StrBuf->Printf(&buf, ", `opt_idx%d` = '%d', `opt_val%d` = '%d'", j, auction->item.option[j].index, j, auction->item.option[j].value); StrBuf->Printf(&buf, " WHERE `auction_id` = '%u'", auction->auction_id); stmt = SQL->StmtMalloc(inter->sql_handle); @@ -95,33 +97,35 @@ unsigned int inter_auction_create(struct auction_data *auction) StringBuf buf; struct SqlStmt *stmt; - if( !auction ) - return false; + nullpo_ret(auction); auction->timestamp = time(NULL) + (auction->hours * 3600); StrBuf->Init(&buf); StrBuf->Printf(&buf, "INSERT INTO `%s` (`seller_id`,`seller_name`,`buyer_id`,`buyer_name`,`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`,`unique_id`", auction_db); - for( j = 0; j < MAX_SLOTS; j++ ) + for (j = 0; j < MAX_SLOTS; j++) StrBuf->Printf(&buf, ",`card%d`", j); + for (j = 0; j < MAX_ITEM_OPTIONS; j++) + StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", j, j); StrBuf->Printf(&buf, ") VALUES ('%d',?,'%d',?,'%d','%d','%d','%lu','%d',?,'%d','%d','%d','%"PRIu64"'", auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute, auction->item.unique_id); - for( j = 0; j < MAX_SLOTS; j++ ) + for (j = 0; j < MAX_SLOTS; j++) StrBuf->Printf(&buf, ",'%d'", auction->item.card[j]); + for (j = 0; j < MAX_ITEM_OPTIONS; j++) + StrBuf->Printf(&buf, ",'%d','%d'", auction->item.option[j].index, auction->item.option[j].value); + StrBuf->AppendStr(&buf, ")"); stmt = SQL->StmtMalloc(inter->sql_handle); - if( SQL_SUCCESS != SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf)) + if (SQL_SUCCESS != SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf)) || SQL_SUCCESS != SQL->StmtBindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH)) || SQL_SUCCESS != SQL->StmtBindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH)) || SQL_SUCCESS != SQL->StmtBindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH)) - || SQL_SUCCESS != SQL->StmtExecute(stmt) ) + || SQL_SUCCESS != SQL->StmtExecute(stmt)) { SqlStmt_ShowDebug(stmt); auction->auction_id = 0; - } - else - { + } else { struct auction_data *auction_; int64 tick = (int64)auction->hours * 3600000; @@ -204,8 +208,10 @@ void inter_auctions_fromsql(void) StrBuf->Init(&buf); StrBuf->AppendStr(&buf, "SELECT `auction_id`,`seller_id`,`seller_name`,`buyer_id`,`buyer_name`," "`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`,`unique_id`"); - for( i = 0; i < MAX_SLOTS; i++ ) + for (i = 0; i < MAX_SLOTS; i++) StrBuf->Printf(&buf, ",`card%d`", i); + for (i = 0; i < MAX_ITEM_OPTIONS; i++) + StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", i, i); StrBuf->Printf(&buf, " FROM `%s` ORDER BY `auction_id` DESC", auction_db); if (SQL_ERROR == SQL->QueryStr(inter->sql_handle, StrBuf->Value(&buf))) @@ -238,14 +244,20 @@ void inter_auctions_fromsql(void) item->identify = 1; item->amount = 1; item->expire_time = 0; - - for( i = 0; i < MAX_SLOTS; i++ ) - { + /* Card Slots */ + for (i = 0; i < MAX_SLOTS; i++) { SQL->GetData(inter->sql_handle, 15 + i, &data, NULL); item->card[i] = atoi(data); } + /* Item Options */ + for (i = 0; i < MAX_ITEM_OPTIONS; i++) { + SQL->GetData(inter->sql_handle, 15 + MAX_SLOTS + i * 2, &data, NULL); + item->option[i].index = atoi(data); + SQL->GetData(inter->sql_handle, 16 + MAX_SLOTS + i * 2, &data, NULL); + item->option[i].value = atoi(data); + } - if( auction->timestamp > now ) + if (auction->timestamp > now) endtick = ((int64)(auction->timestamp - now) * 1000) + tick; else endtick = tick + 10000; // 10 seconds to process ended auctions diff --git a/src/char/int_mail.c b/src/char/int_mail.c index 10f905a0d..1d00b0fdf 100644 --- a/src/char/int_mail.c +++ b/src/char/int_mail.c @@ -57,6 +57,8 @@ static int inter_mail_fromsql(int char_id, struct mail_data* md) "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`,`unique_id`"); for (i = 0; i < MAX_SLOTS; i++) StrBuf->Printf(&buf, ",`card%d`", i); + for (i = 0; i < MAX_ITEM_OPTIONS; i++) + StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", i, i); // I keep the `status` < 3 just in case someone forget to apply the sqlfix StrBuf->Printf(&buf, " FROM `%s` WHERE `dest_id`='%d' AND `status` < 3 ORDER BY `id` LIMIT %d", @@ -90,12 +92,18 @@ static int inter_mail_fromsql(int char_id, struct mail_data* md) SQL->GetData(inter->sql_handle,15, &data, NULL); item->unique_id = strtoull(data, NULL, 10); item->expire_time = 0; item->bound = 0; - - for (j = 0; j < MAX_SLOTS; j++) - { + /* Card Slots */ + for (j = 0; j < MAX_SLOTS; j++) { SQL->GetData(inter->sql_handle, 16 + j, &data, NULL); item->card[j] = atoi(data); } + /* Item Options */ + for (j = 0; j < MAX_ITEM_OPTIONS; j++) { + SQL->GetData(inter->sql_handle, 16 + MAX_SLOTS + j * 2, &data, NULL); + item->option[j].index = atoi(data); + SQL->GetData(inter->sql_handle, 17 + MAX_SLOTS + j * 2, &data, NULL); + item->option[j].value = atoi(data); + } } md->full = ( SQL->NumRows(inter->sql_handle) > MAIL_MAX_INBOX ); @@ -138,25 +146,30 @@ int inter_mail_savemessage(struct mail_message* msg) StrBuf->Printf(&buf, "INSERT INTO `%s` (`send_name`, `send_id`, `dest_name`, `dest_id`, `title`, `message`, `time`, `status`, `zeny`, `amount`, `nameid`, `refine`, `attribute`, `identify`, `unique_id`", mail_db); for (j = 0; j < MAX_SLOTS; j++) StrBuf->Printf(&buf, ", `card%d`", j); + for (j = 0; j < MAX_ITEM_OPTIONS; j++) + StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", j, j); StrBuf->Printf(&buf, ") VALUES (?, '%d', ?, '%d', ?, ?, '%lu', '%u', '%d', '%d', '%d', '%d', '%d', '%d', '%"PRIu64"'", msg->send_id, msg->dest_id, (unsigned long)msg->timestamp, msg->status, msg->zeny, msg->item.amount, msg->item.nameid, msg->item.refine, msg->item.attribute, msg->item.identify, msg->item.unique_id); for (j = 0; j < MAX_SLOTS; j++) StrBuf->Printf(&buf, ", '%d'", msg->item.card[j]); + for (j = 0; j < MAX_ITEM_OPTIONS; j++) + StrBuf->Printf(&buf, ", '%d', '%d'", msg->item.option[j].index, msg->item.option[j].value); StrBuf->AppendStr(&buf, ")"); // prepare and execute query stmt = SQL->StmtMalloc(inter->sql_handle); - if( SQL_SUCCESS != SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf)) + if (SQL_SUCCESS != SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf)) || SQL_SUCCESS != SQL->StmtBindParam(stmt, 0, SQLDT_STRING, msg->send_name, strnlen(msg->send_name, NAME_LENGTH)) || SQL_SUCCESS != SQL->StmtBindParam(stmt, 1, SQLDT_STRING, msg->dest_name, strnlen(msg->dest_name, NAME_LENGTH)) || SQL_SUCCESS != SQL->StmtBindParam(stmt, 2, SQLDT_STRING, msg->title, strnlen(msg->title, MAIL_TITLE_LENGTH)) || SQL_SUCCESS != SQL->StmtBindParam(stmt, 3, SQLDT_STRING, msg->body, strnlen(msg->body, MAIL_BODY_LENGTH)) - || SQL_SUCCESS != SQL->StmtExecute(stmt) ) + || SQL_SUCCESS != SQL->StmtExecute(stmt)) { SqlStmt_ShowDebug(stmt); msg->id = 0; - } else + } else { msg->id = (int)SQL->StmtLastInsertId(stmt); + } SQL->StmtFree(stmt); StrBuf->Destroy(&buf); @@ -176,8 +189,10 @@ static bool inter_mail_loadmessage(int mail_id, struct mail_message* msg) StrBuf->Init(&buf); StrBuf->AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`," "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`,`unique_id`"); - for( j = 0; j < MAX_SLOTS; j++ ) + for (j = 0; j < MAX_SLOTS; j++) StrBuf->Printf(&buf, ",`card%d`", j); + for (j = 0; j < MAX_ITEM_OPTIONS; j++) + StrBuf->Printf(&buf, ",`opt_idx%d`,`opt_val%d`", j, j); StrBuf->Printf(&buf, " FROM `%s` WHERE `id` = '%d'", mail_db, mail_id); if (SQL_ERROR == SQL->QueryStr(inter->sql_handle, StrBuf->Value(&buf)) @@ -207,12 +222,18 @@ static bool inter_mail_loadmessage(int mail_id, struct mail_message* msg) SQL->GetData(inter->sql_handle,15, &data, NULL); msg->item.unique_id = strtoull(data, NULL, 10); msg->item.expire_time = 0; msg->item.bound = 0; - - for( j = 0; j < MAX_SLOTS; j++ ) - { + /* Card Slots */ + for (j = 0; j < MAX_SLOTS; j++) { SQL->GetData(inter->sql_handle,16 + j, &data, NULL); msg->item.card[j] = atoi(data); } + /* Item Options */ + for (j = 0 ; j < MAX_ITEM_OPTIONS; j++) { + SQL->GetData(inter->sql_handle, 16 + MAX_SLOTS + j * 2, &data, NULL); + msg->item.option[j].index = atoi(data); + SQL->GetData(inter->sql_handle, 17 + MAX_SLOTS + j * 2, &data, NULL); + msg->item.option[j].value = atoi(data); + } } StrBuf->Destroy(&buf); @@ -269,6 +290,8 @@ static bool inter_mail_DeleteAttach(int mail_id) StrBuf->Printf(&buf, "UPDATE `%s` SET `zeny` = '0', `nameid` = '0', `amount` = '0', `refine` = '0', `attribute` = '0', `identify` = '0'", mail_db); for (i = 0; i < MAX_SLOTS; i++) StrBuf->Printf(&buf, ", `card%d` = '0'", i); + for (i = 0; i < MAX_ITEM_OPTIONS; i++) + StrBuf->Printf(&buf, ", `opt_idx%d` = '0', `opt_val%d` = '0'", i, i); StrBuf->Printf(&buf, " WHERE `id` = '%d'", mail_id); if (SQL_ERROR == SQL->QueryStr(inter->sql_handle, StrBuf->Value(&buf))) { diff --git a/src/char/int_storage.c b/src/char/int_storage.c index 8e3ebdff3..b78ad9f0e 100644 --- a/src/char/int_storage.c +++ b/src/char/int_storage.c @@ -63,8 +63,10 @@ int inter_storage_fromsql(int account_id, struct storage_data* p) // storage {`account_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`} StrBuf->Init(&buf); StrBuf->AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`expire_time`,`bound`,`unique_id`"); - for( j = 0; j < MAX_SLOTS; ++j ) + for (j = 0; j < MAX_SLOTS; ++j) StrBuf->Printf(&buf, ",`card%d`", j); + for (j = 0; j < MAX_ITEM_OPTIONS; ++j) + StrBuf->Printf(&buf, ",`opt_idx%d`,`opt_val%d`", j, j); StrBuf->Printf(&buf, " FROM `%s` WHERE `account_id`='%d' ORDER BY `nameid`", storage_db, account_id); if (SQL_ERROR == SQL->QueryStr(inter->sql_handle, StrBuf->Value(&buf))) @@ -84,9 +86,17 @@ int inter_storage_fromsql(int account_id, struct storage_data* p) SQL->GetData(inter->sql_handle, 7, &data, NULL); item->expire_time = (unsigned int)atoi(data); SQL->GetData(inter->sql_handle, 8, &data, NULL); item->bound = atoi(data); SQL->GetData(inter->sql_handle, 9, &data, NULL); item->unique_id = strtoull(data, NULL, 10); - for( j = 0; j < MAX_SLOTS; ++j ) - { - SQL->GetData(inter->sql_handle, 10+j, &data, NULL); item->card[j] = atoi(data); + /* Card Slots */ + for (j = 0; j < MAX_SLOTS; ++j) { + SQL->GetData(inter->sql_handle, 10 + j, &data, NULL); + item->card[j] = atoi(data); + } + /* Item Options */ + for (j = 0; j < MAX_ITEM_OPTIONS; ++j) { + SQL->GetData(inter->sql_handle, 10 + MAX_SLOTS + j * 2, &data, NULL); + item->option[j].index = atoi(data); + SQL->GetData(inter->sql_handle, 11 + MAX_SLOTS + j * 2, &data, NULL); + item->option[j].value = atoi(data); } } p->storage_amount = i; @@ -121,8 +131,10 @@ int inter_storage_guild_storage_fromsql(int guild_id, struct guild_storage* p) // storage {`guild_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`} StrBuf->Init(&buf); StrBuf->AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`bound`,`unique_id`"); - for( j = 0; j < MAX_SLOTS; ++j ) + for (j = 0; j < MAX_SLOTS; ++j) StrBuf->Printf(&buf, ",`card%d`", j); + for (j = 0; j < MAX_ITEM_OPTIONS; ++j) + StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", j, j); StrBuf->Printf(&buf, " FROM `%s` WHERE `guild_id`='%d' ORDER BY `nameid`", guild_storage_db, guild_id); if( SQL_ERROR == SQL->QueryStr(inter->sql_handle, StrBuf->Value(&buf))) @@ -142,9 +154,17 @@ int inter_storage_guild_storage_fromsql(int guild_id, struct guild_storage* p) SQL->GetData(inter->sql_handle, 7, &data, NULL); item->bound = atoi(data); SQL->GetData(inter->sql_handle, 8, &data, NULL); item->unique_id = strtoull(data, NULL, 10); item->expire_time = 0; - - for( j = 0; j < MAX_SLOTS; ++j ) { - SQL->GetData(inter->sql_handle, 9+j, &data, NULL); item->card[j] = atoi(data); + /* Card Slots */ + for (j = 0; j < MAX_SLOTS; ++j) { + SQL->GetData(inter->sql_handle, 9 + j, &data, NULL); + item->card[j] = atoi(data); + } + /* Item Options */ + for (j = 0; j < MAX_ITEM_OPTIONS; ++j) { + SQL->GetData(inter->sql_handle, 9 + MAX_SLOTS + j * 2, &data, NULL); + item->option[j].index = atoi(data); + SQL->GetData(inter->sql_handle, 10 + MAX_SLOTS + j * 2, &data, NULL); + item->option[j].value = atoi(data); } } p->storage_amount = i; @@ -288,8 +308,10 @@ int mapif_parse_ItemBoundRetrieve_sub(int fd) StrBuf->Init(&buf); StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`"); - for( j = 0; j < MAX_SLOTS; ++j ) + for (j = 0; j < MAX_SLOTS; ++j) StrBuf->Printf(&buf, ", `card%d`", j); + for (j = 0; j < MAX_ITEM_OPTIONS; ++j) + StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", j, j); StrBuf->Printf(&buf, " FROM `%s` WHERE `char_id`='%d' AND `bound` = '%d'",inventory_db,char_id,IBT_GUILD); stmt = SQL->StmtMalloc(inter->sql_handle); @@ -313,17 +335,22 @@ int mapif_parse_ItemBoundRetrieve_sub(int fd) SQL->StmtBindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 8, SQLDT_UCHAR, &item.bound, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 9, SQLDT_UINT64, &item.unique_id, 0, NULL, NULL); - for( j = 0; j < MAX_SLOTS; ++j ) - SQL->StmtBindColumn(stmt, 10+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); - - while( SQL_SUCCESS == SQL->StmtNextRow(stmt)) { + /* Card Slots */ + for (j = 0; j < MAX_SLOTS; ++j) + SQL->StmtBindColumn(stmt, 10 + j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); + /* Item Options */ + for (j = 0; j < MAX_ITEM_OPTIONS; ++j) { + SQL->StmtBindColumn(stmt, 10 + MAX_SLOTS + j * 2, SQLDT_INT16, &item.option[j].index, 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 11 + MAX_SLOTS + j * 2, SQLDT_INT16, &item.option[j].value, 0, NULL, NULL); + } + while (SQL_SUCCESS == SQL->StmtNextRow(stmt)) { Assert_retb(i < MAX_INVENTORY); memcpy(&items[i],&item,sizeof(struct item)); i++; } SQL->FreeResult(inter->sql_handle); - if(!i) { //No items found - No need to continue + if (i == 0) { //No items found - No need to continue StrBuf->Destroy(&buf); SQL->StmtFree(stmt); return 0; @@ -408,24 +435,28 @@ int mapif_parse_ItemBoundRetrieve_sub(int fd) StrBuf->Printf(&buf,"INSERT INTO `%s` (`guild_id`,`nameid`,`amount`,`equip`,`identify`,`refine`," "`attribute`,`expire_time`,`bound`,`unique_id`", guild_storage_db); - for( s = 0; s < MAX_SLOTS; ++s ) + for (s = 0; s < MAX_SLOTS; ++s) StrBuf->Printf(&buf, ", `card%d`", s); + for (s = 0; s < MAX_ITEM_OPTIONS; ++s) + StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", s, s); StrBuf->AppendStr(&buf," ) VALUES "); - for( j = 0; j < i; ++j ) { - if( j ) + for (j = 0; j < i; ++j) { + if (j != 0) StrBuf->AppendStr(&buf, ","); StrBuf->Printf(&buf, "('%d', '%d', '%d', '%u', '%d', '%d', '%d', '%u', '%d', '%"PRIu64"'", guild_id, items[j].nameid, items[j].amount, items[j].equip, items[j].identify, items[j].refine, items[j].attribute, items[j].expire_time, items[j].bound, items[j].unique_id); - for( s = 0; s < MAX_SLOTS; ++s ) + for (s = 0; s < MAX_SLOTS; ++s) StrBuf->Printf(&buf, ", '%d'", items[j].card[s]); + for (s = 0; s < MAX_ITEM_OPTIONS; ++s) + StrBuf->Printf(&buf, ", '%d', '%d'", items[j].option[s].index, items[j].option[s].value); StrBuf->AppendStr(&buf, ")"); } - if( SQL_ERROR == SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf)) - || SQL_ERROR == SQL->StmtExecute(stmt) ) + if (SQL_ERROR == SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf)) + || SQL_ERROR == SQL->StmtExecute(stmt)) { Sql_ShowDebug(inter->sql_handle); SQL->StmtFree(stmt); diff --git a/src/common/HPMDataCheck.h b/src/common/HPMDataCheck.h index 0a4af75dd..2a1c092b7 100644 --- a/src/common/HPMDataCheck.h +++ b/src/common/HPMDataCheck.h @@ -452,6 +452,7 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = { { "item_combo", sizeof(struct item_combo), SERVER_TYPE_MAP }, { "item_data", sizeof(struct item_data), SERVER_TYPE_MAP }, { "item_group", sizeof(struct item_group), SERVER_TYPE_MAP }, + { "item_option", sizeof(struct item_option), SERVER_TYPE_MAP }, { "item_package", sizeof(struct item_package), SERVER_TYPE_MAP }, { "item_package_must_entry", sizeof(struct item_package_must_entry), SERVER_TYPE_MAP }, { "item_package_rand_entry", sizeof(struct item_package_rand_entry), SERVER_TYPE_MAP }, @@ -542,8 +543,8 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = { #ifdef MAP_PACKETS_STRUCT_H { "EQUIPITEM_INFO", sizeof(struct EQUIPITEM_INFO), SERVER_TYPE_MAP }, { "EQUIPSLOTINFO", sizeof(struct EQUIPSLOTINFO), SERVER_TYPE_MAP }, + { "ItemOptions", sizeof(struct ItemOptions), SERVER_TYPE_MAP }, { "NORMALITEM_INFO", sizeof(struct NORMALITEM_INFO), SERVER_TYPE_MAP }, - { "RndOptions", sizeof(struct RndOptions), SERVER_TYPE_MAP }, { "packet_additem", sizeof(struct packet_additem), SERVER_TYPE_MAP }, { "packet_authok", sizeof(struct packet_authok), SERVER_TYPE_MAP }, { "packet_banking_check", sizeof(struct packet_banking_check), SERVER_TYPE_MAP }, diff --git a/src/common/mmo.h b/src/common/mmo.h index 9c29b8a0e..35e66964c 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -256,6 +256,12 @@ #define MAX_ELESKILLTREE 3 #endif +// Maximum item options [Smokexyz] +#ifndef MAX_ITEM_OPTIONS +#define MAX_ITEM_OPTIONS 5 +#endif +STATIC_ASSERT(MAX_ITEM_OPTIONS <= 5, "This value is limited by the client and database layout and should only be increased if you know the consequences."); + // The following system marks a different job ID system used by the map server, // which makes a lot more sense than the normal one. [Skotlex] // These marks the "level" of the job. @@ -326,6 +332,12 @@ struct item { char favorite; unsigned char bound; uint64 unique_id; + + struct { + int16 index; + int16 value; + uint8 param; + } option[MAX_ITEM_OPTIONS]; }; //Equip position constants diff --git a/src/map/clif.c b/src/map/clif.c index c48241898..8de18da30 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -2378,23 +2378,37 @@ void clif_addcards2(unsigned short *cards, struct item* item) { } /** - * Fills in RandomOptions(Bonuses) of items into the buffer + * Fills in ItemOptions(Bonuses) of items into the buffer * - * Dummy datais used since this feature isn't supported yet (ITEM_RDM_OPT). - * A maximum of 5 random options can be supported. + * A maximum of 5 item options can be supported. * * @param buf[in,out] The buffer to write to. The pointer must be valid and initialized. * @param item[in] The source item. */ -void clif_add_random_options(unsigned char* buf, struct item* item) -{ - int i; - nullpo_retv(buf); - for (i = 0; i < 5; i++){ - WBUFW(buf,i*5+0) = 0; // OptIndex - WBUFW(buf,i*5+2) = 0; // Value - WBUFB(buf,i*5+4) = 0; // Param1 + int clif_add_item_options(struct ItemOptions *buf, const struct item *it) +{ + int i = 0, j = 0, total_options = 0; + + nullpo_ret(buf); + + // Append the buffer with existing options first. + for (i = 0; i < MAX_ITEM_OPTIONS; i++) { + if (it->option[i].index) { + WBUFW(buf, j * 5 + 0) = it->option[i].index; // OptIndex + WBUFW(buf, j * 5 + 2) = it->option[i].value; // Value + WBUFB(buf, j * 5 + 4) = it->option[i].param; // Param1 + total_options++; + j++; + } + } + // Append the remaining buffer with no values; + for (; j < MAX_ITEM_OPTIONS || j < 5; j++) { + WBUFW(buf, j * 5 + 0) = 0; + WBUFW(buf, j * 5 + 2) = 0; + WBUFB(buf, j * 5 + 4) = 0; } + + return total_options; } /// Notifies the client, about a received inventory item or the result of a pick-up request. @@ -2418,9 +2432,6 @@ void clif_additem(struct map_session_data *sd, int n, int amount, int fail) { p.count = amount; if( !fail ) { -#if PACKETVER >= 20150226 - int i; -#endif if( n < 0 || n >= MAX_INVENTORY || sd->status.inventory[n].nameid <=0 || sd->inventory_data[n] == NULL ) return; @@ -2445,11 +2456,7 @@ void clif_additem(struct map_session_data *sd, int n, int amount, int fail) { p.bindOnEquipType = sd->status.inventory[n].bound && !itemdb->isstackable2(sd->inventory_data[n]) ? 2 : sd->inventory_data[n]->flag.bindonequip ? 1 : 0; #endif #if PACKETVER >= 20150226 - for (i=0; i<5; i++){ - p.option_data[i].index = 0; - p.option_data[i].value = 0; - p.option_data[i].param = 0; - } + clif->add_item_options(&p.option_data[0], &sd->status.inventory[n]); #endif } p.result = (unsigned char)fail; @@ -2522,19 +2529,17 @@ void clif_item_sub(unsigned char *buf, int n, struct item *i, struct item_data * } -void clif_item_equip(short idx, struct EQUIPITEM_INFO *p, struct item *i, struct item_data *id, int eqp_pos) { -#if PACKETVER >= 20150226 - int j; -#endif +void clif_item_equip(short idx, struct EQUIPITEM_INFO *p, struct item *it, struct item_data *id, int eqp_pos) +{ nullpo_retv(p); - nullpo_retv(i); + nullpo_retv(it); nullpo_retv(id); p->index = idx; if (id->view_id > 0) p->ITID = id->view_id; else - p->ITID = i->nameid; + p->ITID = it->nameid; p->type = itemtype(id->type); @@ -2543,20 +2548,20 @@ void clif_item_equip(short idx, struct EQUIPITEM_INFO *p, struct item *i, struct #endif p->location = eqp_pos; - p->WearState = i->equip; + p->WearState = it->equip; #if PACKETVER < 20120925 p->IsDamaged = (i->attribute & ATTR_BROKEN) != 0 ? 1 : 0; #endif - p->RefiningLevel = i->refine; + p->RefiningLevel = it->refine; - clif->addcards2(&p->slot.card[0], i); + clif->addcards2(&p->slot.card[0], it); #if PACKETVER >= 20071002 - p->HireExpireDate = i->expire_time; + p->HireExpireDate = it->expire_time; #endif #if PACKETVER >= 20080102 - p->bindOnEquipType = i->bound ? 2 : id->flag.bindonequip ? 1 : 0; + p->bindOnEquipType = it->bound ? 2 : id->flag.bindonequip ? 1 : 0; #endif #if PACKETVER >= 20100629 @@ -2564,19 +2569,14 @@ void clif_item_equip(short idx, struct EQUIPITEM_INFO *p, struct item *i, struct #endif #if PACKETVER >= 20120925 - p->Flag.IsIdentified = i->identify ? 1 : 0; - p->Flag.IsDamaged = (i->attribute & ATTR_BROKEN) != 0 ? 1 : 0; - p->Flag.PlaceETCTab = i->favorite ? 1 : 0; + p->Flag.IsIdentified = it->identify ? 1 : 0; + p->Flag.IsDamaged = (it->attribute & ATTR_BROKEN) != 0 ? 1 : 0; + p->Flag.PlaceETCTab = it->favorite ? 1 : 0; p->Flag.SpareBits = 0; #endif #if PACKETVER >= 20150226 - p->option_count = 0; - for (j=0; j<5; j++){ - p->option_data[j].index = 0; - p->option_data[j].value = 0; - p->option_data[j].param = 0; - } + p->option_count = clif->add_item_options(p->option_data, it); #endif } @@ -3992,7 +3992,7 @@ void clif_tradeadditem(struct map_session_data* sd, struct map_session_data* tsd WBUFW(buf,15)= 0; //card (4w) WBUFW(buf,17)= 0; //card (4w) #if PACKETVER >= 20150226 - clif->add_random_options(WBUFP(buf, 19), &sd->status.inventory[index]); + clif->add_item_options(WBUFP(buf, 19), &sd->status.inventory[index]); #endif } else @@ -4018,7 +4018,7 @@ void clif_tradeadditem(struct map_session_data* sd, struct map_session_data* tsd WBUFB(buf,10)= sd->status.inventory[index].refine; //refine clif->addcards(WBUFP(buf, 11), &sd->status.inventory[index]); #if PACKETVER >= 20150226 - clif->add_random_options(WBUFP(buf, 19), &sd->status.inventory[index]); + clif->add_item_options(WBUFP(buf, 19), &sd->status.inventory[index]); #endif } WFIFOSET(fd,packet_len(tradeaddType)); @@ -4149,7 +4149,7 @@ void clif_storageitemadded(struct map_session_data* sd, struct item* i, int inde WFIFOB(fd,12+offset) = i->refine; //refine clif->addcards(WFIFOP(fd,13+offset), i); #if PACKETVER >= 20150226 - clif->add_random_options(WFIFOP(fd,21+offset), i); + clif->add_item_options(WFIFOP(fd,21+offset), i); #endif WFIFOSET(fd,packet_len(storageaddType)); } @@ -6223,7 +6223,7 @@ void clif_cart_additem(struct map_session_data *sd,int n,int amount,int fail) WBUFB(buf,12+offset)=sd->status.cart[n].refine; clif->addcards(WBUFP(buf,13+offset), &sd->status.cart[n]); #if PACKETVER >= 20150226 - clif->add_random_options(WBUFP(buf,21+offset), &sd->status.cart[n]); + clif->add_item_options(WBUFP(buf,21+offset), &sd->status.cart[n]); #endif WFIFOSET(fd,packet_len(cartaddType)); } @@ -6351,7 +6351,7 @@ void clif_vendinglist(struct map_session_data* sd, unsigned int id, struct s_ven WFIFOB(fd,offset+13+i*item_length) = vsd->status.cart[index].refine; clif->addcards(WFIFOP(fd,offset+14+i*item_length), &vsd->status.cart[index]); #if PACKETVER >= 20150226 - clif->add_random_options(WFIFOP(fd,offset+22+i*item_length), &vsd->status.cart[index]); + clif->add_item_options(WFIFOP(fd,offset+22+i*item_length), &vsd->status.cart[index]); #endif } WFIFOSET(fd,WFIFOW(fd,2)); @@ -6417,7 +6417,7 @@ void clif_openvending(struct map_session_data* sd, int id, struct s_vending* ven WFIFOB(fd,21+i*item_length) = sd->status.cart[index].refine; clif->addcards(WFIFOP(fd,22+i*item_length), &sd->status.cart[index]); #if PACKETVER >= 20150226 - clif->add_random_options(WFIFOP(fd,30+22+i*item_length), &sd->status.cart[index]); + clif->add_item_options(WFIFOP(fd,30+22+i*item_length), &sd->status.cart[index]); #endif } WFIFOSET(fd,WFIFOW(fd,2)); @@ -20092,7 +20092,7 @@ void clif_defaults(void) { clif->pNPCMarketClosed = clif_parse_NPCMarketClosed; clif->pNPCMarketPurchase = clif_parse_NPCMarketPurchase; /* */ - clif->add_random_options = clif_add_random_options; + clif->add_item_options = clif_add_item_options; clif->pHotkeyRowShift = clif_parse_HotkeyRowShift; clif->dressroom_open = clif_dressroom_open; clif->pOneClick_ItemIdentify = clif_parse_OneClick_ItemIdentify; diff --git a/src/map/clif.h b/src/map/clif.h index b27adb5be..c4cf045c3 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -1351,7 +1351,7 @@ struct clif_interface { void (*pNPCMarketClosed) (int fd, struct map_session_data *sd); void (*pNPCMarketPurchase) (int fd, struct map_session_data *sd); /* */ - void (*add_random_options) (unsigned char* buf, struct item* item); + int (*add_item_options) (struct ItemOptions *buf, const struct item *it); void (*pHotkeyRowShift) (int fd, struct map_session_data *sd); void (*dressroom_open) (struct map_session_data *sd, int view); void (*pOneClick_ItemIdentify) (int fd,struct map_session_data *sd); diff --git a/src/map/itemdb.c b/src/map/itemdb.c index 445307aeb..a35aa67f1 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -321,6 +321,16 @@ struct item_data* itemdb_exists(int nameid) return item; } +/** + * Searches for the item_option data. + * @param option_index as the index of the item option (client side). + * @return pointer to struct item_option data or NULL. + */ +struct item_option *itemdb_option_exists(int idx) +{ + return (struct item_option *)idb_get(itemdb->options, idx); +} + /// Returns human readable name for given item type. /// @param type Type id to retrieve name for ( IT_* ). const char* itemdb_typename(int type) @@ -1299,6 +1309,125 @@ void itemdb_read_packages(void) { ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, config_filename); } +/** + * Processes any (plugin-defined) additional fields for a itemdb_options entry. + * + * @param[in,out] entry The destination ito entry, already initialized + * (item_opt.index, status.mode are expected to be already set). + * @param[in] t The libconfig entry. + * @param[in] source Source of the entry (file name), to be displayed in + * case of validation errors. + */ +void itemdb_readdb_options_additional_fields(struct item_option *ito, struct config_setting_t *t, const char *source) +{ + // do nothing. plugins can do their own work +} + +/** + * Reads the Item Options configuration file. + */ +void itemdb_read_options(void) +{ + struct config_t item_options_db; + struct config_setting_t *ito = NULL, *conf = NULL; + int index = 0, count = 0; + const char *filepath = "db/item_options.conf"; + VECTOR_DECL(int) duplicate_id; + + if (!libconfig->load_file(&item_options_db, filepath)) + return; + +#ifdef ENABLE_CASE_CHECK + script->parser_current_file = filepath; +#endif // ENABLE_CASE_CHECK + + if ((ito=libconfig->setting_get_member(item_options_db.root, "item_options_db")) == NULL) { + ShowError("itemdb_read_options: '%s' could not be loaded.\n", filepath); + libconfig->destroy(&item_options_db); + return; + } + + VECTOR_INIT(duplicate_id); + + VECTOR_ENSURE(duplicate_id, libconfig->setting_length(ito), 1); + + while ((conf = libconfig->setting_get_elem(ito, index++))) { + struct item_option t_opt = { 0 }, *s_opt = NULL; + const char *str = NULL; + int i = 0; + + /* Id Lookup */ + if (!libconfig->setting_lookup_int16(conf, "Id", &t_opt.index) || t_opt.index <= 0) { + ShowError("itemdb_read_options: Invalid Option Id provided for entry %d in '%s', skipping...\n", t_opt.index, filepath); + continue; + } + + /* Checking for duplicate entries. */ + ARR_FIND(0, VECTOR_LENGTH(duplicate_id), i, VECTOR_INDEX(duplicate_id, i) == t_opt.index); + + if (i != VECTOR_LENGTH(duplicate_id)) { + ShowError("itemdb_read_options: Duplicate entry for Option Id %d in '%s', skipping...\n", t_opt.index, filepath); + continue; + } + + VECTOR_PUSH(duplicate_id, t_opt.index); + + /* Name Lookup */ + if (!libconfig->setting_lookup_string(conf, "Name", &str)) { + ShowError("itemdb_read_options: Invalid Option Name '%s' provided for Id %d in '%s', skipping...\n", str, t_opt.index, filepath); + continue; + } + + /* check for illegal characters in the constant. */ + { + const char *c = str; + + while (ISALNUM(*c) || *c == '_') + ++c; + + if (*c != '\0') { + ShowError("itemdb_read_options: Invalid characters in Option Name '%s' for Id %d in '%s', skipping...\n", str, t_opt.index, filepath); + continue; + } + } + + /* Set name as a script constant with index as value. */ + script->set_constant2(str, t_opt.index, false, false); + + /* Script Code Lookup */ + if (!libconfig->setting_lookup_string(conf, "Script", &str)) { + ShowError("itemdb_read_options: Script code not found for entry %s (Id: %d) in '%s', skipping...\n", str, t_opt.index, filepath); + continue; + } + + /* Set Script */ + t_opt.script = *str ? script->parse(str, filepath, t_opt.index, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL; + + /* Additional fields through plugins */ + itemdb->readdb_options_additional_fields(&t_opt, ito, filepath); + + /* Allocate memory and copy contents */ + CREATE(s_opt, struct item_option, 1); + + *s_opt = t_opt; + + /* Store ptr in the database */ + idb_put(itemdb->options, t_opt.index, s_opt); + + count++; + } + +#ifdef ENABLE_CASE_CHECK + script->parser_current_file = NULL; +#endif // ENABLE_CASE_CHECK + + libconfig->destroy(&item_options_db); + + VECTOR_CLEAR(duplicate_id); + + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filepath); +} + void itemdb_read_chains(void) { struct config_t item_chain_conf; struct config_setting_t *itc = NULL; @@ -1674,7 +1803,10 @@ int itemdb_validate_entry(struct item_data *entry, int n, const char *source) { if( entry->type != IT_ARMOR && entry->type != IT_WEAPON && !entry->flag.no_refine ) entry->flag.no_refine = 1; - + + if (entry->type != IT_ARMOR && entry->type != IT_WEAPON && !entry->flag.no_options) + entry->flag.no_options = 1; + if (entry->flag.available != 1) { entry->flag.available = 1; entry->view_id = 0; @@ -1922,6 +2054,9 @@ int itemdb_readdb_libconfig_sub(struct config_setting_t *it, int n, const char * if( (t = libconfig->setting_get_member(it, "Refine")) ) id.flag.no_refine = libconfig->setting_get_bool(t) ? 0 : 1; + + if ((t = libconfig->setting_get_member(it, "DisableOptions"))) + id.flag.no_options = libconfig->setting_get_bool(t) ? 1 : 0; if( itemdb->lookup_const(it, "View", &i32) && i32 >= 0 ) id.look = i32; @@ -2165,6 +2300,7 @@ void itemdb_read(bool minimal) { itemdb->read_groups(); itemdb->read_chains(); itemdb->read_packages(); + itemdb->read_options(); } @@ -2226,6 +2362,17 @@ int itemdb_final_sub(union DBKey key, struct DBData *data, va_list ap) return 0; } + +int itemdb_options_final_sub(union DBKey key, struct DBData *data, va_list ap) +{ + struct item_option *ito = DB->data2ptr(data); + + if (ito->script != NULL) + script->free_code(ito->script); + + return 0; +} + void itemdb_clear(bool total) { int i; // clear the previous itemdb data @@ -2289,6 +2436,7 @@ void itemdb_clear(bool total) { return; itemdb->other->clear(itemdb->other, itemdb->final_sub); + itemdb->options->clear(itemdb->options, itemdb->options_final_sub); memset(itemdb->array, 0, sizeof(itemdb->array)); @@ -2373,6 +2521,7 @@ void do_final_itemdb(void) { itemdb->clear(true); itemdb->other->destroy(itemdb->other, itemdb->final_sub); + itemdb->options->destroy(itemdb->options, itemdb->options_final_sub); itemdb->destroy_item_data(&itemdb->dummy, 0); db_destroy(itemdb->names); } @@ -2380,6 +2529,7 @@ void do_final_itemdb(void) { void do_init_itemdb(bool minimal) { memset(itemdb->array, 0, sizeof(itemdb->array)); itemdb->other = idb_alloc(DB_OPT_BASE); + itemdb->options = idb_alloc(DB_OPT_RELEASE_DATA); itemdb->names = strdb_alloc(DB_OPT_BASE,ITEM_NAME_LENGTH); itemdb->create_dummy_data(); //Dummy data item. itemdb->read(minimal); @@ -2422,6 +2572,7 @@ void itemdb_defaults(void) { itemdb->read_groups = itemdb_read_groups; itemdb->read_chains = itemdb_read_chains; itemdb->read_packages = itemdb_read_packages; + itemdb->read_options = itemdb_read_options; /* */ itemdb->write_cached_packages = itemdb_write_cached_packages; itemdb->read_cached_packages = itemdb_read_cached_packages; @@ -2432,6 +2583,7 @@ void itemdb_defaults(void) { itemdb->load = itemdb_load; itemdb->search = itemdb_search; itemdb->exists = itemdb_exists; + itemdb->option_exists = itemdb_option_exists; itemdb->in_group = itemdb_in_group; itemdb->group_item = itemdb_searchrandomid; itemdb->chain_item = itemdb_chain_item; @@ -2464,6 +2616,7 @@ void itemdb_defaults(void) { itemdb->read_combos = itemdb_read_combos; itemdb->gendercheck = itemdb_gendercheck; itemdb->validate_entry = itemdb_validate_entry; + itemdb->readdb_options_additional_fields = itemdb_readdb_options_additional_fields; itemdb->readdb_additional_fields = itemdb_readdb_additional_fields; itemdb->readdb_job_sub = itemdb_readdb_job_sub; itemdb->readdb_libconfig_sub = itemdb_readdb_libconfig_sub; @@ -2472,6 +2625,7 @@ void itemdb_defaults(void) { itemdb->read = itemdb_read; itemdb->destroy_item_data = destroy_item_data; itemdb->final_sub = itemdb_final_sub; + itemdb->options_final_sub = itemdb_options_final_sub; itemdb->clear = itemdb_clear; itemdb->id2combo = itemdb_id2combo; itemdb->is_item_usable = itemdb_is_item_usable; diff --git a/src/map/itemdb.h b/src/map/itemdb.h index 571512e49..618111d2a 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -388,7 +388,7 @@ enum ItemTradeRestrictions { }; /** - * Iten No-use restrictions + * Item No-use restrictions */ enum ItemNouseRestrictions { INR_NONE = 0x0, ///< No restrictions @@ -397,6 +397,16 @@ enum ItemNouseRestrictions { INR_ALL = 0x1 ///< Sum of all the above values }; +/** + * Item Option Types + */ +enum ItemOptionTypes { + IT_OPT_INDEX = 0, + IT_OPT_VALUE, + IT_OPT_PARAM, + IT_OPT_MAX +}; + /** Convenience item list (entry) used in various functions */ struct itemlist_entry { int id; ///< Item ID or (inventory) index @@ -462,6 +472,11 @@ struct item_package { unsigned short must_qty; }; +struct item_option { + int16 index; + struct script_code *script; +}; + struct item_data { uint16 nameid; char name[ITEM_NAME_LENGTH],jname[ITEM_NAME_LENGTH]; @@ -507,6 +522,7 @@ struct item_data { unsigned bindonequip : 1; unsigned keepafteruse : 1; unsigned force_serial : 1; + unsigned no_options: 1; // < disallows use of item options on the item. (non-equippable items are automatically flagged) [Smokexyz] } flag; struct {// item stacking limitation unsigned short amount; @@ -548,6 +564,7 @@ struct item_data { #define itemdb_value_buy(n) (itemdb->search(n)->value_buy) #define itemdb_value_sell(n) (itemdb->search(n)->value_sell) #define itemdb_canrefine(n) (!itemdb->search(n)->flag.no_refine) +#define itemdb_allowoption(n) (!itemdb->search(n)->flag.no_options) #define itemdb_is_rune(n) (((n) >= ITEMID_NAUTHIZ && (n) <= ITEMID_HAGALAZ) || (n) == ITEMID_LUX_ANIMA) #define itemdb_is_element(n) ((n) >= ITEMID_SCARLET_PTS && (n) <= ITEMID_LIME_GREEN_PTS) @@ -595,11 +612,13 @@ struct itemdb_interface { /* */ struct item_data *array[MAX_ITEMDB]; struct DBMap *other;// int nameid -> struct item_data* + struct DBMap *options; // int opt_id -> struct item_option* struct item_data dummy; //This is the default dummy item used for non-existant items. [Skotlex] /* */ void (*read_groups) (void); void (*read_chains) (void); void (*read_packages) (void); + void (*read_options) (void); /* */ void (*write_cached_packages) (const char *config_filename); bool (*read_cached_packages) (const char *config_filename); @@ -610,6 +629,7 @@ struct itemdb_interface { struct item_data* (*load)(int nameid); struct item_data* (*search)(int nameid); struct item_data* (*exists) (int nameid); + struct item_option* (*option_exists) (int idx); bool (*in_group) (struct item_group *group, int nameid); int (*group_item) (struct item_group *group); int (*chain_item) (unsigned short chain_id, int *rate); @@ -642,6 +662,7 @@ struct itemdb_interface { void (*read_combos) (void); int (*gendercheck) (struct item_data *id); int (*validate_entry) (struct item_data *entry, int n, const char *source); + void (*readdb_options_additional_fields) (struct item_option *ito, struct config_setting_t *t, const char *source); void (*readdb_additional_fields) (int itemid, struct config_setting_t *it, int n, const char *source); void (*readdb_job_sub) (struct item_data *id, struct config_setting_t *t); int (*readdb_libconfig_sub) (struct config_setting_t *it, int n, const char *source); @@ -650,6 +671,7 @@ struct itemdb_interface { void (*read) (bool minimal); void (*destroy_item_data) (struct item_data *self, int free_self); int (*final_sub) (union DBKey key, struct DBData *data, va_list ap); + int (*options_final_sub) (union DBKey key, struct DBData *data, va_list ap); void (*clear) (bool total); struct item_combo * (*id2combo) (unsigned short id); bool (*is_item_usable) (struct item_data *item); diff --git a/src/map/log.c b/src/map/log.c index 902d428a7..6419c4766 100644 --- a/src/map/log.c +++ b/src/map/log.c @@ -161,12 +161,15 @@ void log_branch(struct map_session_data* sd) { } void log_pick_sub_sql(int id, int16 m, e_log_pick_type type, int amount, struct item* itm, struct item_data *data) { nullpo_retv(itm); - if( SQL_ERROR == SQL->Query(logs->mysql_handle, - LOG_QUERY " INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`, `unique_id`) " - "VALUES (NOW(), '%d', '%c', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s', '%"PRIu64"')", + if (SQL_ERROR == SQL->Query(logs->mysql_handle, + LOG_QUERY " INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, " + "`opt_idx0`, `opt_val0`, `opt_idx1`, `opt_val1`, `opt_idx2`, `opt_val2`, `opt_idx3`, `opt_val3`, `opt_idx4`, `opt_val4`, `map`, `unique_id`) " + "VALUES (NOW(), '%d', '%c', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s', '%"PRIu64"')", logs->config.log_pick, id, logs->picktype2char(type), itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], - map->list[m].name, itm->unique_id) - ) { + itm->option[0].index, itm->option[0].value, itm->option[1].index, itm->option[1].value, itm->option[2].index, itm->option[2].value, + itm->option[3].index, itm->option[3].value, itm->option[4].index, itm->option[4].value, + map->list[m].name, itm->unique_id)) + { Sql_ShowDebug(logs->mysql_handle); return; } diff --git a/src/map/npc.c b/src/map/npc.c index a824d4216..2876ea595 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -2089,6 +2089,8 @@ int npc_selllist_sub(struct map_session_data *sd, struct itemlist *item_list, st { char npc_ev[EVENT_NAME_LENGTH]; char card_slot[NAME_LENGTH]; + char opt_index_str[NAME_LENGTH]; + char opt_value_str[NAME_LENGTH]; int i, j; int key_nameid = 0; int key_amount = 0; @@ -2096,6 +2098,8 @@ int npc_selllist_sub(struct map_session_data *sd, struct itemlist *item_list, st int key_attribute = 0; int key_identify = 0; int key_card[MAX_SLOTS]; + int key_opt_idx[MAX_ITEM_OPTIONS]; + int key_opt_value[MAX_ITEM_OPTIONS]; nullpo_ret(sd); nullpo_ret(item_list); @@ -2140,6 +2144,17 @@ int npc_selllist_sub(struct map_session_data *sd, struct itemlist *item_list, st script->setarray_pc(sd, card_slot, i, (void*)card, &key_card[j]); } + for (j = 0; j < MAX_ITEM_OPTIONS; j++) { + intptr_t opt_idx = item->option[j].index; + intptr_t opt_value = item->option[j].value; + + snprintf(opt_index_str, sizeof(opt_index_str), "@slot_opt_idx%d", j + 1); + script->setarray_pc(sd, opt_index_str, i, (void*)opt_idx, &key_opt_idx[j]); + + snprintf(opt_value_str, sizeof(opt_value_str), "@slot_opt_val%d", j + 1); + script->setarray_pc(sd, opt_value_str, i, (void*)opt_value, &key_opt_value[j]); + } + } // invoke event diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h index e461eebe9..420cf0c4b 100644 --- a/src/map/packets_struct.h +++ b/src/map/packets_struct.h @@ -343,7 +343,7 @@ struct NORMALITEM_INFO { #endif } __attribute__((packed)); -struct RndOptions { +struct ItemOptions { int16 index; int16 value; uint8 param; @@ -379,7 +379,7 @@ struct EQUIPITEM_INFO { #endif #if PACKETVER >= 20150226 uint8 option_count; - struct RndOptions option_data[5]; + struct ItemOptions option_data[MAX_ITEM_OPTIONS]; #endif #if PACKETVER >= 20120925 struct { @@ -442,7 +442,7 @@ struct packet_additem { uint16 bindOnEquipType; #endif #if PACKETVER >= 20150226 - struct RndOptions option_data[5]; + struct ItemOptions option_data[MAX_ITEM_OPTIONS]; #endif } __attribute__((packed)); diff --git a/src/map/script.c b/src/map/script.c index 38931bd11..e14cd5504 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -9019,6 +9019,35 @@ BUILDIN(getequipisenableref) return true; } +/** + * Checks if the equipped item allows options. + * *getequipisenableopt(); + * + * @param equipment_index as the inventory index of the equipment. + * @return 1 on enabled 0 on disabled. + */ +BUILDIN(getequipisenableopt) +{ + int i = -1, index = script_getnum(st, 2); + struct map_session_data *sd = script->rid2sd(st); + + if (sd == NULL) { + script_pushint(st, -1); + ShowError("buildin_getequipisenableopt: player is not attached!"); + return false; + } + + if (index > 0 && index <= ARRAYLENGTH(script->equip)) + i = pc->checkequip(sd, script->equip[index - 1]); + + if (i >=0 && sd->inventory_data[i] && !sd->inventory_data[i]->flag.no_options && !sd->status.inventory[i].expire_time) + script_pushint(st, 1); + else + script_pushint(st, 0); + + return true; +} + /*========================================== * Chk if the item equiped at pos is identify (huh ?) * return (npc) @@ -13546,6 +13575,190 @@ BUILDIN(getiteminfo) return true; } +/** + * Returns the value of the current equipment being parsed using static variables - + * current_equip_item_index and current_equip_option_index. + * !!Designed to be used with item_options.conf only!! + * *getequippedoptioninfo(); + * + * @param (int) Types - + * IT_OPT_INDEX ID of the item option. + * IT_OPT_VALUE Amount of the bonus to be added. + * @return value of the type or -1. + */ +BUILDIN(getequippedoptioninfo) +{ + int val = 0, type = script_getnum(st, 2); + struct map_session_data *sd = NULL; + + if ((sd = script->rid2sd(st)) == NULL || status->current_equip_item_index == -1 || status->current_equip_option_index == -1 + || !sd->status.inventory[status->current_equip_item_index].option[status->current_equip_option_index].index) { + script_pushint(st, -1); + return false; + } + + switch (type) { + case IT_OPT_INDEX: + val = sd->status.inventory[status->current_equip_item_index].option[status->current_equip_option_index].index; + break; + case IT_OPT_VALUE: + val = sd->status.inventory[status->current_equip_item_index].option[status->current_equip_option_index].value; + break; + default: + ShowError("buildin_getequippedoptioninfo: Invalid option data type %d (Max %d).\n", type, IT_OPT_MAX-1); + script_pushint(st, -1); + return false; + } + + script_pushint(st, val); + + return true; +} + +/** + * Gets the option information of an equipment. + * *getequipoptioninfo(,,); + * + * @param equip_index as the Index of the Equipment. + * @param slot as the slot# of the Item Option (1 to MAX_ITEM_OPTIONS) + * @param type IT_OPT_INDEX or IT_OPT_VALUE. + * @return (int) value or -1 on failure. + */ +BUILDIN(getequipoption) +{ + int val = 0, equip_index = script_getnum(st, 2); + int slot = script_getnum(st, 3); + int opt_type = script_getnum(st, 4); + int i = -1; + struct map_session_data *sd = script->rid2sd(st); + + if (sd == NULL) { + script_pushint(st, -1); + ShowError("buildin_getequipoptioninfo: Player not attached!\n"); + return false; + } + + if (slot <= 0 || slot > MAX_ITEM_OPTIONS) { + script_pushint(st, -1); + ShowError("buildin_getequipoptioninfo: Invalid option slot %d (Min: 1, Max: %d) provided.\n", slot, MAX_ITEM_OPTIONS); + return false; + } + + if (equip_index > 0 && equip_index <= ARRAYLENGTH(script->equip)) { + if ((i = pc->checkequip(sd, script->equip[equip_index - 1])) == -1) { + ShowError("buildin_getequipoptioninfo: No equipment is equipped in the given index %d.\n", equip_index); + script_pushint(st, -1); + return false; + } + } else { + ShowError("buildin_getequipoptioninfo: Invalid equipment index %d provided.\n", equip_index); + script_pushint(st, 0); + return false; + } + + if (sd->status.inventory[i].nameid != 0) { + switch (opt_type) { + case IT_OPT_INDEX: + val = sd->status.inventory[i].option[slot-1].index; + break; + case IT_OPT_VALUE: + val = sd->status.inventory[i].option[slot-1].value; + break; + default: + ShowError("buildin_geteqiupoptioninfo: Invalid option data type %d provided.\n", opt_type); + script_pushint(st, -1); + break; + } + } + + script_pushint(st, val); + + return true; +} + +/** + * Set an equipment's option value. + * *setequipoption(,,,); + * + * @param equip_index as the inventory index of the equipment. + * @param slot as the slot of the item option (1 to MAX_ITEM_OPTIONS) + * @param opt_index as the index of the option available as "Id" in db/item_options.conf. + * @param value as the value of the option type. + * For IT_OPT_INDEX see "Name" in item_options.conf + * For IT_OPT_VALUE, the value of the script bonus. + * @return 0 on failure, 1 on success. + */ +BUILDIN(setequipoption) +{ + int equip_index = script_getnum(st, 2); + int slot = script_getnum(st, 4); + int opt_index = script_getnum(st, 3); + int value = script_getnum(st, 5); + int i = -1; + + struct map_session_data *sd = script->rid2sd(st); + struct item_option *ito = NULL; + + if (sd == NULL) { + script_pushint(st, 0); + ShowError("buildin_setequipoption: Player not attached!\n"); + return false; + } + + if (slot <= 0 || slot > MAX_ITEM_OPTIONS) { + script_pushint(st, 0); + ShowError("buildin_setequipoption: Invalid option index %d (Min: 1, Max: %d) provided.\n", slot, MAX_ITEM_OPTIONS); + return false; + } + + if (equip_index > 0 && equip_index <= ARRAYLENGTH(script->equip)) { + if ((i = pc->checkequip(sd, script->equip[equip_index - 1])) == -1) { + ShowError("buildin_setequipoptioninfo: No equipment is equipped in the given index %d.\n", equip_index); + script_pushint(st, 0); + return false; + } + } else { + ShowError("buildin_setequipoptioninfo: Invalid equipment index %d provided.\n", equip_index); + script_pushint(st, 0); + return false; + } + + if (sd->status.inventory[i].nameid != 0) { + + if ((ito = itemdb->option_exists(opt_index)) == NULL) { + script_pushint(st, 0); + ShowError("buildin_setequipotion: Option index %d does not exist!\n", opt_index); + return false; + } else if (value < -INT16_MAX || value > INT16_MAX) { + script_pushint(st, 0); + ShowError("buildin_setequipotion: Option value %d exceeds maximum limit (%d to %d) for type!\n", value, -INT16_MAX, INT16_MAX); + return false; + } + /* Add Option Index */ + sd->status.inventory[i].option[slot-1].index = ito->index; + /* Add Option Value */ + sd->status.inventory[i].option[slot-1].value = value; + + /* Unequip and simulate deletion of the item. */ + pc->unequipitem(sd, i, PCUNEQUIPITEM_FORCE); // status calc will happen in pc->equipitem() below + clif->refine(sd->fd, 0, i, sd->status.inventory[i].refine); // notify client of a refine. + clif->delitem(sd, i, 1, DELITEM_MATERIALCHANGE); // notify client to simulate item deletion. + /* Log deletion of the item. */ + logs->pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->status.inventory[i],sd->inventory_data[i]); + /* Equip and simulate addition of the item. */ + clif->additem(sd, i, 1, 0); // notify client to simulate item addition. + /* Log addition of the item. */ + logs->pick_pc(sd, LOG_TYPE_SCRIPT, 1, &sd->status.inventory[i], sd->inventory_data[i]); + pc->equipitem(sd, i, sd->status.inventory[i].equip); // force equip the item at the original position. + clif->misceffect(&sd->bl, 2); // show effect + } + + script_pushint(st, 1); + + return true; + +} + /*========================================== * Set some values of an item [Lupus] * Price, Weight, etc... @@ -13706,7 +13919,7 @@ BUILDIN(petloot) BUILDIN(getinventorylist) { struct map_session_data *sd = script->rid2sd(st); - char card_var[NAME_LENGTH]; + char card_var[SCRIPT_VARNAME_LENGTH]; int i,j=0,k; if(!sd) return true; @@ -13727,6 +13940,14 @@ BUILDIN(getinventorylist) sprintf(card_var, "@inventorylist_card%d",k+1); pc->setreg(sd,reference_uid(script->add_str(card_var), j),sd->status.inventory[i].card[k]); } + for (k = 0; k < MAX_ITEM_OPTIONS; k++) { + sprintf(card_var, "@inventorylist_opt_id%d", k + 1); + pc->setreg(sd, reference_uid(script->add_str(card_var), j), sd->status.inventory[i].option[k].index); + sprintf(card_var, "@inventorylist_opt_val%d", k + 1); + pc->setreg(sd, reference_uid(script->add_str(card_var), j), sd->status.inventory[i].option[k].value); + sprintf(card_var, "@inventorylist_opt_param%d", k + 1); + pc->setreg(sd, reference_uid(script->add_str(card_var), j), sd->status.inventory[i].option[k].param); + } pc->setreg(sd,reference_uid(script->add_str("@inventorylist_expire"), j),sd->status.inventory[i].expire_time); pc->setreg(sd,reference_uid(script->add_str("@inventorylist_bound"), j),sd->status.inventory[i].bound); j++; @@ -13739,7 +13960,7 @@ BUILDIN(getinventorylist) BUILDIN(getcartinventorylist) { struct map_session_data *sd = script->rid2sd(st); - char card_var[26]; + char card_var[SCRIPT_VARNAME_LENGTH]; int i,j=0,k; if(!sd) return true; @@ -13756,6 +13977,14 @@ BUILDIN(getcartinventorylist) sprintf(card_var, "@cartinventorylist_card%d",k+1); pc->setreg(sd,reference_uid(script->add_str(card_var), j),sd->status.cart[i].card[k]); } + for (k = 0; k < MAX_ITEM_OPTIONS; k++) { + sprintf(card_var, "@cartinventorylist_opt_id%d", k + 1); + pc->setreg(sd, reference_uid(script->add_str(card_var), j), sd->status.cart[i].option[k].index); + sprintf(card_var, "@cartinventorylist_opt_val%d", k + 1); + pc->setreg(sd, reference_uid(script->add_str(card_var), j), sd->status.cart[i].option[k].value); + sprintf(card_var, "@cartinventorylist_opt_param%d", k + 1); + pc->setreg(sd, reference_uid(script->add_str(card_var), j), sd->status.cart[i].option[k].param); + } pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_expire"), j),sd->status.cart[i].expire_time); pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_bound"), j),sd->status.cart[i].bound); j++; @@ -21096,6 +21325,10 @@ void script_parse_builtin(void) { BUILDIN_DEF(getiteminfo,"ii"), //[Lupus] returns Items Buy / sell Price, etc info BUILDIN_DEF(setiteminfo,"iii"), //[Lupus] set Items Buy / sell Price, etc info BUILDIN_DEF(getequipcardid,"ii"), //[Lupus] returns CARD ID or other info from CARD slot N of equipped item + BUILDIN_DEF(getequippedoptioninfo, "i"), + BUILDIN_DEF(getequipoption, "iii"), + BUILDIN_DEF(setequipoption, "iiii"), + BUILDIN_DEF(getequipisenableopt, "i"), // List of mathematics commands ---> BUILDIN_DEF(log10,"i"), BUILDIN_DEF(sqrt,"i"), //[zBuffer] @@ -21463,6 +21696,14 @@ void script_hardcoded_constants(void) script->set_constant("EQP_SHADOW_ACC_R", EQP_SHADOW_ACC_R, false, false); script->set_constant("EQP_SHADOW_ACC_L", EQP_SHADOW_ACC_L, false, false); + script->constdb_comment("Item Option Types"); + script->set_constant("IT_OPT_INDEX", IT_OPT_INDEX, false, false); + script->set_constant("IT_OPT_VALUE", IT_OPT_VALUE, false, false); + script->set_constant("IT_OPT_PARAM", IT_OPT_PARAM, false, false); + + script->constdb_comment("Maximum Item Options"); + script->set_constant("MAX_ITEM_OPTIONS", MAX_ITEM_OPTIONS, false, false); + script->constdb_comment("Navigation constants, use with *navigateto*"); script->set_constant("NAV_NONE", NAV_NONE, false, false); script->set_constant("NAV_AIRSHIP_ONLY", NAV_AIRSHIP_ONLY, false, false); diff --git a/src/map/status.c b/src/map/status.c index 78c11899b..d8fb9a350 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -2400,8 +2400,8 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt) bstatus->speed = pSpeed; } - //FIXME: Most of these stuff should be calculated once, but how do I fix the memset above to do that? [Skotlex] - //Give them all modes except these (useful for clones) + // FIXME: Most of these stuff should be calculated once, but how do I fix the memset above to do that? [Skotlex] + // Give them all modes except these (useful for clones) bstatus->mode = MD_MASK&~(MD_BOSS|MD_PLANT|MD_DETECTOR|MD_ANGRY|MD_TARGETWEAK); bstatus->size = ((sd->job & JOBL_BABY) != 0 || (sd->job & MAPID_BASEMASK) == MAPID_SUMMONER)?SZ_SMALL:SZ_MEDIUM; @@ -2646,6 +2646,39 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt) } } } + + /* parse item options [Smokexyz] */ + for (i = 0; i < EQI_MAX; i++) { + status->current_equip_item_index = index = sd->equip_index[i]; + status->current_equip_option_index = -1; + + if (i == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index) + continue; + else if (i == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index) + continue; + else if (i == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == index || sd->equip_index[EQI_HEAD_LOW] == index)) + continue; + + if (index >= 0 && sd->inventory_data[index]) { + int j = 0; + for (j = 0; j < MAX_ITEM_OPTIONS; j++) { + int16 option_index = sd->status.inventory[index].option[j].index; + struct item_option *ito = NULL; + + if (option_index == 0 || (ito = itemdb->option_exists(option_index)) == NULL || ito->script == NULL) + continue; + + status->current_equip_option_index = j; + script->run(ito->script, 0, sd->bl.id, 0); + + if (calculating == 0) //Abort, script->run his function. [Skotlex] + return 1; + } + } + } + + status->current_equip_option_index = -1; + status->current_equip_item_index = -1; status->calc_pc_additional(sd, opt); diff --git a/src/map/status.h b/src/map/status.h index e6c205b1d..6f68c36c3 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -2205,6 +2205,7 @@ struct status_interface { /* vars */ int current_equip_item_index; int current_equip_card_id; + int current_equip_option_index; struct s_status_dbs *dbs; diff --git a/src/map/storage.c b/src/map/storage.c index acb72be81..aacc7c053 100644 --- a/src/map/storage.c +++ b/src/map/storage.c @@ -133,9 +133,12 @@ int compare_item(struct item *a, struct item *b) a->bound == b->bound && a->unique_id == b->unique_id) { - int i; - for (i = 0; i < MAX_SLOTS && (a->card[i] == b->card[i]); i++); - return (i == MAX_SLOTS); + int i = 0, k = 0; + ARR_FIND(0, MAX_SLOTS, i, a->card[i] != b->card[i]); + ARR_FIND(0, MAX_ITEM_OPTIONS, k, a->option[k].index != b->option[k].index || a->option[k].value != b->option[k].value); + + if (i == MAX_SLOTS && k == MAX_ITEM_OPTIONS) + return 1; } return 0; } diff --git a/src/plugins/HPMHooking/HPMHooking.Defs.inc b/src/plugins/HPMHooking/HPMHooking.Defs.inc index 57abf25e0..74af2f26d 100644 --- a/src/plugins/HPMHooking/HPMHooking.Defs.inc +++ b/src/plugins/HPMHooking/HPMHooking.Defs.inc @@ -2222,8 +2222,8 @@ typedef void (*HPMHOOK_pre_clif_pNPCMarketClosed) (int *fd, struct map_session_d typedef void (*HPMHOOK_post_clif_pNPCMarketClosed) (int fd, struct map_session_data *sd); typedef void (*HPMHOOK_pre_clif_pNPCMarketPurchase) (int *fd, struct map_session_data **sd); typedef void (*HPMHOOK_post_clif_pNPCMarketPurchase) (int fd, struct map_session_data *sd); -typedef void (*HPMHOOK_pre_clif_add_random_options) (unsigned char **buf, struct item **item); -typedef void (*HPMHOOK_post_clif_add_random_options) (unsigned char *buf, struct item *item); +typedef int (*HPMHOOK_pre_clif_add_random_options) (struct ItemOptions **buf, const struct item **it); +typedef int (*HPMHOOK_post_clif_add_random_options) (int retVal___, struct ItemOptions *buf, const struct item *it); typedef void (*HPMHOOK_pre_clif_pHotkeyRowShift) (int *fd, struct map_session_data **sd); typedef void (*HPMHOOK_post_clif_pHotkeyRowShift) (int fd, struct map_session_data *sd); typedef void (*HPMHOOK_pre_clif_dressroom_open) (struct map_session_data **sd, int *view); @@ -3300,6 +3300,8 @@ typedef void (*HPMHOOK_pre_itemdb_read_chains) (void); typedef void (*HPMHOOK_post_itemdb_read_chains) (void); typedef void (*HPMHOOK_pre_itemdb_read_packages) (void); typedef void (*HPMHOOK_post_itemdb_read_packages) (void); +typedef void (*HPMHOOK_pre_itemdb_read_options) (void); +typedef void (*HPMHOOK_post_itemdb_read_options) (void); typedef void (*HPMHOOK_pre_itemdb_write_cached_packages) (const char **config_filename); typedef void (*HPMHOOK_post_itemdb_write_cached_packages) (const char *config_filename); typedef bool (*HPMHOOK_pre_itemdb_read_cached_packages) (const char **config_filename); @@ -3316,6 +3318,8 @@ typedef struct item_data* (*HPMHOOK_pre_itemdb_search) (int *nameid); typedef struct item_data* (*HPMHOOK_post_itemdb_search) (struct item_data* retVal___, int nameid); typedef struct item_data* (*HPMHOOK_pre_itemdb_exists) (int *nameid); typedef struct item_data* (*HPMHOOK_post_itemdb_exists) (struct item_data* retVal___, int nameid); +typedef struct item_option* (*HPMHOOK_pre_itemdb_option_exists) (int *idx); +typedef struct item_option* (*HPMHOOK_post_itemdb_option_exists) (struct item_option* retVal___, int idx); typedef bool (*HPMHOOK_pre_itemdb_in_group) (struct item_group **group, int *nameid); typedef bool (*HPMHOOK_post_itemdb_in_group) (bool retVal___, struct item_group *group, int nameid); typedef int (*HPMHOOK_pre_itemdb_group_item) (struct item_group **group); @@ -3380,6 +3384,8 @@ typedef int (*HPMHOOK_pre_itemdb_gendercheck) (struct item_data **id); typedef int (*HPMHOOK_post_itemdb_gendercheck) (int retVal___, struct item_data *id); typedef int (*HPMHOOK_pre_itemdb_validate_entry) (struct item_data **entry, int *n, const char **source); typedef int (*HPMHOOK_post_itemdb_validate_entry) (int retVal___, struct item_data *entry, int n, const char *source); +typedef void (*HPMHOOK_pre_itemdb_readdb_options_additional_fields) (struct item_option **ito, struct config_setting_t **t, int *n, const char **source); +typedef void (*HPMHOOK_post_itemdb_readdb_options_additional_fields) (struct item_option *ito, struct config_setting_t *t, int n, const char *source); typedef void (*HPMHOOK_pre_itemdb_readdb_additional_fields) (int *itemid, struct config_setting_t **it, int *n, const char **source); typedef void (*HPMHOOK_post_itemdb_readdb_additional_fields) (int itemid, struct config_setting_t *it, int n, const char *source); typedef void (*HPMHOOK_pre_itemdb_readdb_job_sub) (struct item_data **id, struct config_setting_t **t); @@ -3396,6 +3402,8 @@ typedef void (*HPMHOOK_pre_itemdb_destroy_item_data) (struct item_data **self, i typedef void (*HPMHOOK_post_itemdb_destroy_item_data) (struct item_data *self, int free_self); typedef int (*HPMHOOK_pre_itemdb_final_sub) (union DBKey *key, struct DBData **data, va_list ap); typedef int (*HPMHOOK_post_itemdb_final_sub) (int retVal___, union DBKey key, struct DBData *data, va_list ap); +typedef int (*HPMHOOK_pre_itemdb_options_final_sub) (union DBKey *key, struct DBData **data, va_list ap); +typedef int (*HPMHOOK_post_itemdb_options_final_sub) (int retVal___, union DBKey key, struct DBData *data, va_list ap); typedef void (*HPMHOOK_pre_itemdb_clear) (bool *total); typedef void (*HPMHOOK_post_itemdb_clear) (bool total); typedef struct item_combo* (*HPMHOOK_pre_itemdb_id2combo) (unsigned short *id); diff --git a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc index bd055cac2..cdd2386a6 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc @@ -1860,8 +1860,8 @@ struct { struct HPMHookPoint *HP_clif_pNPCMarketClosed_post; struct HPMHookPoint *HP_clif_pNPCMarketPurchase_pre; struct HPMHookPoint *HP_clif_pNPCMarketPurchase_post; - struct HPMHookPoint *HP_clif_add_random_options_pre; - struct HPMHookPoint *HP_clif_add_random_options_post; + struct HPMHookPoint *HP_clif_add_item_options_pre; + struct HPMHookPoint *HP_clif_add_item_options_post; struct HPMHookPoint *HP_clif_pHotkeyRowShift_pre; struct HPMHookPoint *HP_clif_pHotkeyRowShift_post; struct HPMHookPoint *HP_clif_dressroom_open_pre; @@ -2682,6 +2682,8 @@ struct { struct HPMHookPoint *HP_itemdb_read_chains_post; struct HPMHookPoint *HP_itemdb_read_packages_pre; struct HPMHookPoint *HP_itemdb_read_packages_post; + struct HPMHookPoint *HP_itemdb_read_options_pre; + struct HPMHookPoint *HP_itemdb_read_options_post; struct HPMHookPoint *HP_itemdb_write_cached_packages_pre; struct HPMHookPoint *HP_itemdb_write_cached_packages_post; struct HPMHookPoint *HP_itemdb_read_cached_packages_pre; @@ -2698,6 +2700,8 @@ struct { struct HPMHookPoint *HP_itemdb_search_post; struct HPMHookPoint *HP_itemdb_exists_pre; struct HPMHookPoint *HP_itemdb_exists_post; + struct HPMHookPoint *HP_itemdb_option_exists_pre; + struct HPMHookPoint *HP_itemdb_option_exists_post; struct HPMHookPoint *HP_itemdb_in_group_pre; struct HPMHookPoint *HP_itemdb_in_group_post; struct HPMHookPoint *HP_itemdb_group_item_pre; @@ -2762,6 +2766,8 @@ struct { struct HPMHookPoint *HP_itemdb_gendercheck_post; struct HPMHookPoint *HP_itemdb_validate_entry_pre; struct HPMHookPoint *HP_itemdb_validate_entry_post; + struct HPMHookPoint *HP_itemdb_readdb_options_additional_fields_pre; + struct HPMHookPoint *HP_itemdb_readdb_options_additional_fields_post; struct HPMHookPoint *HP_itemdb_readdb_additional_fields_pre; struct HPMHookPoint *HP_itemdb_readdb_additional_fields_post; struct HPMHookPoint *HP_itemdb_readdb_job_sub_pre; @@ -2778,6 +2784,8 @@ struct { struct HPMHookPoint *HP_itemdb_destroy_item_data_post; struct HPMHookPoint *HP_itemdb_final_sub_pre; struct HPMHookPoint *HP_itemdb_final_sub_post; + struct HPMHookPoint *HP_itemdb_options_final_sub_pre; + struct HPMHookPoint *HP_itemdb_options_final_sub_post; struct HPMHookPoint *HP_itemdb_clear_pre; struct HPMHookPoint *HP_itemdb_clear_post; struct HPMHookPoint *HP_itemdb_id2combo_pre; @@ -7899,8 +7907,8 @@ struct { int HP_clif_pNPCMarketClosed_post; int HP_clif_pNPCMarketPurchase_pre; int HP_clif_pNPCMarketPurchase_post; - int HP_clif_add_random_options_pre; - int HP_clif_add_random_options_post; + int HP_clif_add_item_options_pre; + int HP_clif_add_item_options_post; int HP_clif_pHotkeyRowShift_pre; int HP_clif_pHotkeyRowShift_post; int HP_clif_dressroom_open_pre; @@ -8721,6 +8729,8 @@ struct { int HP_itemdb_read_chains_post; int HP_itemdb_read_packages_pre; int HP_itemdb_read_packages_post; + int HP_itemdb_read_options_pre; + int HP_itemdb_read_options_post; int HP_itemdb_write_cached_packages_pre; int HP_itemdb_write_cached_packages_post; int HP_itemdb_read_cached_packages_pre; @@ -8737,6 +8747,8 @@ struct { int HP_itemdb_search_post; int HP_itemdb_exists_pre; int HP_itemdb_exists_post; + int HP_itemdb_option_exists_pre; + int HP_itemdb_option_exists_post; int HP_itemdb_in_group_pre; int HP_itemdb_in_group_post; int HP_itemdb_group_item_pre; @@ -8801,6 +8813,8 @@ struct { int HP_itemdb_gendercheck_post; int HP_itemdb_validate_entry_pre; int HP_itemdb_validate_entry_post; + int HP_itemdb_readdb_options_additional_fields_pre; + int HP_itemdb_readdb_options_additional_fields_post; int HP_itemdb_readdb_additional_fields_pre; int HP_itemdb_readdb_additional_fields_post; int HP_itemdb_readdb_job_sub_pre; @@ -8817,6 +8831,8 @@ struct { int HP_itemdb_destroy_item_data_post; int HP_itemdb_final_sub_pre; int HP_itemdb_final_sub_post; + int HP_itemdb_options_final_sub_pre; + int HP_itemdb_options_final_sub_post; int HP_itemdb_clear_pre; int HP_itemdb_clear_post; int HP_itemdb_id2combo_pre; diff --git a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc index 53f65bcd3..9075901c4 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc @@ -952,7 +952,7 @@ struct HookingPointData HookingPoints[] = { { HP_POP(clif->pNPCShopClosed, HP_clif_pNPCShopClosed) }, { HP_POP(clif->pNPCMarketClosed, HP_clif_pNPCMarketClosed) }, { HP_POP(clif->pNPCMarketPurchase, HP_clif_pNPCMarketPurchase) }, - { HP_POP(clif->add_random_options, HP_clif_add_random_options) }, + { HP_POP(clif->add_item_options, HP_clif_add_item_options) }, { HP_POP(clif->pHotkeyRowShift, HP_clif_pHotkeyRowShift) }, { HP_POP(clif->dressroom_open, HP_clif_dressroom_open) }, { HP_POP(clif->pOneClick_ItemIdentify, HP_clif_pOneClick_ItemIdentify) }, @@ -1378,6 +1378,7 @@ struct HookingPointData HookingPoints[] = { { HP_POP(itemdb->read_groups, HP_itemdb_read_groups) }, { HP_POP(itemdb->read_chains, HP_itemdb_read_chains) }, { HP_POP(itemdb->read_packages, HP_itemdb_read_packages) }, + { HP_POP(itemdb->read_options, HP_itemdb_read_options) }, { HP_POP(itemdb->write_cached_packages, HP_itemdb_write_cached_packages) }, { HP_POP(itemdb->read_cached_packages, HP_itemdb_read_cached_packages) }, { HP_POP(itemdb->name2id, HP_itemdb_name2id) }, @@ -1386,6 +1387,7 @@ struct HookingPointData HookingPoints[] = { { HP_POP(itemdb->load, HP_itemdb_load) }, { HP_POP(itemdb->search, HP_itemdb_search) }, { HP_POP(itemdb->exists, HP_itemdb_exists) }, + { HP_POP(itemdb->option_exists, HP_itemdb_option_exists) }, { HP_POP(itemdb->in_group, HP_itemdb_in_group) }, { HP_POP(itemdb->group_item, HP_itemdb_group_item) }, { HP_POP(itemdb->chain_item, HP_itemdb_chain_item) }, @@ -1418,6 +1420,7 @@ struct HookingPointData HookingPoints[] = { { HP_POP(itemdb->read_combos, HP_itemdb_read_combos) }, { HP_POP(itemdb->gendercheck, HP_itemdb_gendercheck) }, { HP_POP(itemdb->validate_entry, HP_itemdb_validate_entry) }, + { HP_POP(itemdb->readdb_options_additional_fields, HP_itemdb_readdb_options_additional_fields) }, { HP_POP(itemdb->readdb_additional_fields, HP_itemdb_readdb_additional_fields) }, { HP_POP(itemdb->readdb_job_sub, HP_itemdb_readdb_job_sub) }, { HP_POP(itemdb->readdb_libconfig_sub, HP_itemdb_readdb_libconfig_sub) }, @@ -1426,6 +1429,7 @@ struct HookingPointData HookingPoints[] = { { HP_POP(itemdb->read, HP_itemdb_read) }, { HP_POP(itemdb->destroy_item_data, HP_itemdb_destroy_item_data) }, { HP_POP(itemdb->final_sub, HP_itemdb_final_sub) }, + { HP_POP(itemdb->options_final_sub, HP_itemdb_options_final_sub) }, { HP_POP(itemdb->clear, HP_itemdb_clear) }, { HP_POP(itemdb->id2combo, HP_itemdb_id2combo) }, { HP_POP(itemdb->is_item_usable, HP_itemdb_is_item_usable) }, diff --git a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc index 654c902d8..b24c7d315 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc @@ -24201,31 +24201,32 @@ void HP_clif_pNPCMarketPurchase(int fd, struct map_session_data *sd) { } return; } -void HP_clif_add_random_options(unsigned char *buf, struct item *item) { +int HP_clif_add_item_options(struct ItemOptions *buf, const struct item *it) { int hIndex = 0; - if( HPMHooks.count.HP_clif_add_random_options_pre ) { - void (*preHookFunc) (unsigned char **buf, struct item **item); + int retVal___ = 0; + if( HPMHooks.count.HP_clif_add_item_options_pre ) { + int (*preHookFunc) (struct ItemOptions **buf, const struct item **it); *HPMforce_return = false; - for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_add_random_options_pre; hIndex++ ) { - preHookFunc = HPMHooks.list.HP_clif_add_random_options_pre[hIndex].func; - preHookFunc(&buf, &item); + for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_add_item_options_pre; hIndex++ ) { + preHookFunc = HPMHooks.list.HP_clif_add_item_options_pre[hIndex].func; + retVal___ = preHookFunc(&buf, &it); } if( *HPMforce_return ) { *HPMforce_return = false; - return; + return retVal___; } } { - HPMHooks.source.clif.add_random_options(buf, item); + retVal___ = HPMHooks.source.clif.add_item_options(buf, it); } - if( HPMHooks.count.HP_clif_add_random_options_post ) { - void (*postHookFunc) (unsigned char *buf, struct item *item); - for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_add_random_options_post; hIndex++ ) { - postHookFunc = HPMHooks.list.HP_clif_add_random_options_post[hIndex].func; - postHookFunc(buf, item); + if( HPMHooks.count.HP_clif_add_item_options_post ) { + int (*postHookFunc) (int retVal___, struct ItemOptions *buf, const struct item *it); + for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_add_item_options_post; hIndex++ ) { + postHookFunc = HPMHooks.list.HP_clif_add_item_options_post[hIndex].func; + retVal___ = postHookFunc(retVal___, buf, it); } } - return; + return retVal___; } void HP_clif_pHotkeyRowShift(int fd, struct map_session_data *sd) { int hIndex = 0; @@ -35242,6 +35243,32 @@ void HP_itemdb_read_packages(void) { } return; } +void HP_itemdb_read_options(void) { + int hIndex = 0; + if( HPMHooks.count.HP_itemdb_read_options_pre ) { + void (*preHookFunc) (void); + *HPMforce_return = false; + for(hIndex = 0; hIndex < HPMHooks.count.HP_itemdb_read_options_pre; hIndex++ ) { + preHookFunc = HPMHooks.list.HP_itemdb_read_options_pre[hIndex].func; + preHookFunc(); + } + if( *HPMforce_return ) { + *HPMforce_return = false; + return; + } + } + { + HPMHooks.source.itemdb.read_options(); + } + if( HPMHooks.count.HP_itemdb_read_options_post ) { + void (*postHookFunc) (void); + for(hIndex = 0; hIndex < HPMHooks.count.HP_itemdb_read_options_post; hIndex++ ) { + postHookFunc = HPMHooks.list.HP_itemdb_read_options_post[hIndex].func; + postHookFunc(); + } + } + return; +} void HP_itemdb_write_cached_packages(const char *config_filename) { int hIndex = 0; if( HPMHooks.count.HP_itemdb_write_cached_packages_pre ) { @@ -35457,6 +35484,33 @@ struct item_data* HP_itemdb_exists(int nameid) { } return retVal___; } +struct item_option* HP_itemdb_option_exists(int idx) { + int hIndex = 0; + struct item_option* retVal___ = NULL; + if( HPMHooks.count.HP_itemdb_option_exists_pre ) { + struct item_option* (*preHookFunc) (int *idx); + *HPMforce_return = false; + for(hIndex = 0; hIndex < HPMHooks.count.HP_itemdb_option_exists_pre; hIndex++ ) { + preHookFunc = HPMHooks.list.HP_itemdb_option_exists_pre[hIndex].func; + retVal___ = preHookFunc(&idx); + } + if( *HPMforce_return ) { + *HPMforce_return = false; + return retVal___; + } + } + { + retVal___ = HPMHooks.source.itemdb.option_exists(idx); + } + if( HPMHooks.count.HP_itemdb_option_exists_post ) { + struct item_option* (*postHookFunc) (struct item_option* retVal___, int idx); + for(hIndex = 0; hIndex < HPMHooks.count.HP_itemdb_option_exists_post; hIndex++ ) { + postHookFunc = HPMHooks.list.HP_itemdb_option_exists_post[hIndex].func; + retVal___ = postHookFunc(retVal___, idx); + } + } + return retVal___; +} bool HP_itemdb_in_group(struct item_group *group, int nameid) { int hIndex = 0; bool retVal___ = false; @@ -36328,6 +36382,32 @@ int HP_itemdb_validate_entry(struct item_data *entry, int n, const char *source) } return retVal___; } +void HP_itemdb_readdb_options_additional_fields(struct item_option *ito, struct config_setting_t *t, const char *source) { + int hIndex = 0; + if( HPMHooks.count.HP_itemdb_readdb_options_additional_fields_pre ) { + void (*preHookFunc) (struct item_option **ito, struct config_setting_t **t, const char **source); + *HPMforce_return = false; + for(hIndex = 0; hIndex < HPMHooks.count.HP_itemdb_readdb_options_additional_fields_pre; hIndex++ ) { + preHookFunc = HPMHooks.list.HP_itemdb_readdb_options_additional_fields_pre[hIndex].func; + preHookFunc(&ito, &t, &source); + } + if( *HPMforce_return ) { + *HPMforce_return = false; + return; + } + } + { + HPMHooks.source.itemdb.readdb_options_additional_fields(ito, t, source); + } + if( HPMHooks.count.HP_itemdb_readdb_options_additional_fields_post ) { + void (*postHookFunc) (struct item_option *ito, struct config_setting_t *t, const char *source); + for(hIndex = 0; hIndex < HPMHooks.count.HP_itemdb_readdb_options_additional_fields_post; hIndex++ ) { + postHookFunc = HPMHooks.list.HP_itemdb_readdb_options_additional_fields_post[hIndex].func; + postHookFunc(ito, t, source); + } + } + return; +} void HP_itemdb_readdb_additional_fields(int itemid, struct config_setting_t *it, int n, const char *source) { int hIndex = 0; if( HPMHooks.count.HP_itemdb_readdb_additional_fields_pre ) { @@ -36546,6 +36626,39 @@ int HP_itemdb_final_sub(union DBKey key, struct DBData *data, va_list ap) { } return retVal___; } +int HP_itemdb_options_final_sub(union DBKey key, struct DBData *data, va_list ap) { + int hIndex = 0; + int retVal___ = 0; + if( HPMHooks.count.HP_itemdb_options_final_sub_pre ) { + int (*preHookFunc) (union DBKey *key, struct DBData **data, va_list ap); + *HPMforce_return = false; + for(hIndex = 0; hIndex < HPMHooks.count.HP_itemdb_options_final_sub_pre; hIndex++ ) { + va_list ap___copy; va_copy(ap___copy, ap); + preHookFunc = HPMHooks.list.HP_itemdb_options_final_sub_pre[hIndex].func; + retVal___ = preHookFunc(&key, &data, ap___copy); + va_end(ap___copy); + } + if( *HPMforce_return ) { + *HPMforce_return = false; + return retVal___; + } + } + { + va_list ap___copy; va_copy(ap___copy, ap); + retVal___ = HPMHooks.source.itemdb.options_final_sub(key, data, ap___copy); + va_end(ap___copy); + } + if( HPMHooks.count.HP_itemdb_options_final_sub_post ) { + int (*postHookFunc) (int retVal___, union DBKey key, struct DBData *data, va_list ap); + for(hIndex = 0; hIndex < HPMHooks.count.HP_itemdb_options_final_sub_post; hIndex++ ) { + va_list ap___copy; va_copy(ap___copy, ap); + postHookFunc = HPMHooks.list.HP_itemdb_options_final_sub_post[hIndex].func; + retVal___ = postHookFunc(retVal___, key, data, ap___copy); + va_end(ap___copy); + } + } + return retVal___; +} void HP_itemdb_clear(bool total) { int hIndex = 0; if( HPMHooks.count.HP_itemdb_clear_pre ) { diff --git a/src/plugins/db2sql.c b/src/plugins/db2sql.c index f801e4147..33a62757a 100644 --- a/src/plugins/db2sql.c +++ b/src/plugins/db2sql.c @@ -320,6 +320,9 @@ int itemdb2sql_sub(struct config_setting_t *entry, int n, const char *source) // refineable StrBuf->Printf(&buf, "'%d',", it->flag.no_refine?0:1); + + // disable_options + StrBuf->Printf(&buf, "'%d',", it->flag.no_options?1:0); // view StrBuf->Printf(&buf, "'%d',", it->look); @@ -462,6 +465,7 @@ void itemdb2sql_tableheader(void) " `equip_level_min` smallint(5) UNSIGNED DEFAULT NULL,\n" " `equip_level_max` smallint(5) UNSIGNED DEFAULT NULL,\n" " `refineable` tinyint(1) UNSIGNED DEFAULT NULL,\n" + " `disable_options` tinyint(1) UNSIGNED DEFAULT NULL,\n" " `view` smallint(3) UNSIGNED DEFAULT NULL,\n" " `bindonequip` tinyint(1) UNSIGNED DEFAULT NULL,\n" " `forceserial` tinyint(1) UNSIGNED DEFAULT NULL,\n" -- cgit v1.2.3-60-g2f50