OpenGothic
Open source reimplementation of Gothic I and II
Loading...
Searching...
No Matches
item.cpp
Go to the documentation of this file.
1#include "item.h"
2
3#include <Tempest/Log>
4
5#include "game/serialize.h"
6#include "game/gamescript.h"
7#include "utils/versioninfo.h"
8#include "world/objects/npc.h"
9#include "world/world.h"
10#include "utils/fileext.h"
11
12using namespace Tempest;
13
14Item::Item(World &owner, size_t itemInstance, Type type)
15 :Vob(owner) {
16 assert(itemInstance!=size_t(-1));
17 hitem = std::make_shared<zenkit::IItem>();
18 hitem->user_ptr=this;
19 owner.script().initializeInstanceItem(hitem, itemInstance);
20 setCount(1);
21
22 if(type!=T_Inventory) {
23 view = world.addView(*hitem);
24 if(type==T_WorldDyn)
25 setPhysicsEnable(view);
26 }
27 }
28
29Item::Item(World &owner, Serialize &fin, Type type)
30 :Vob(owner) {
31 auto& h = hitem;
32 h = std::make_shared<zenkit::IItem>();
33 h->user_ptr = this;
34
35 Tempest::Matrix4x4 mat;
36
37 uint32_t instanceSymbol=0;
38 fin.read(instanceSymbol);
39
40 auto& vm = owner.script().getVm();
41 auto* sym = vm.find_symbol_by_index(instanceSymbol);
42
43 if (sym != nullptr) {
44 vm.allocate_instance(h, sym);
45 } else {
46 Tempest::Log::e("Loading unknown item from save: " , instanceSymbol);
47 }
48
49 fin.read(h->id,h->name,h->name_id,h->hp,h->hp_max,h->main_flag);
50 fin.read(reinterpret_cast<int&>(h->flags),h->weight,h->value,h->damage_type,h->damage_total,h->damage);
51 fin.read(h->wear,h->protection,h->nutrition,h->cond_atr,h->cond_value,h->change_atr,h->change_value,h->magic);
52 fin.read(h->on_equip,h->on_unequip,h->on_state);
53 fin.read(h->owner,h->owner_guild,h->disguise_guild,h->visual,h->visual_change);
54 fin.read(h->effect,h->visual_skin,h->scheme_name,h->material);
55 fin.read(h->munition,h->spell,h->range,h->mag_circle);
56 fin.read(h->description,h->text,h->count);
57 fin.read(h->inv_zbias,h->inv_rot_x,h->inv_rot_y,h->inv_rot_z,h->inv_animate);
58 fin.read(amount);
59 fin.read(pos,equipped,itSlot);
60 fin.read(mat);
61
62 if(type!=T_Inventory) {
63 if(!FileExt::hasExt(hitem->visual,"ZEN"))
64 view = world.addView(*hitem);
65 if(type==T_WorldDyn)
66 setPhysicsEnable(view);
67 }
68
70 view .setObjMatrix(mat);
71 physic.setObjMatrix(mat);
72 }
73
75 : Vob(it.world), hitem(it.hitem),
76 pos(it.pos),equipped(it.equipped),itSlot(it.itSlot),view(std::move(it.view)) {
77 setLocalTransform(it.localTransform());
78 physic = std::move(it.physic);
79 }
80
82 }
83
84void Item::save(Serialize &fout) const {
85 auto& h = *hitem;
86 fout.write(uint32_t(h.symbol_index()));
87 fout.write(h.id,h.name,h.name_id,h.hp,h.hp_max,h.main_flag);
88 fout.write(reinterpret_cast<int&>(h.flags),h.weight,h.value,h.damage_type,h.damage_total,h.damage);
89 fout.write(h.wear,h.protection,h.nutrition,h.cond_atr,h.cond_value,h.change_atr,h.change_value,h.magic);
90 fout.write(h.on_equip,h.on_unequip,h.on_state);
91 fout.write(h.owner,h.owner_guild,h.disguise_guild,h.visual,h.visual_change);
92 fout.write(h.effect,h.visual_skin,h.scheme_name,h.material);
93 fout.write(h.munition,h.spell,h.range,h.mag_circle);
94 fout.write(h.description,h.text,h.count);
95 fout.write(h.inv_zbias,h.inv_rot_x,h.inv_rot_y,h.inv_rot_z,h.inv_animate);
96 fout.write(amount);
97 fout.write(pos,equipped,itSlot);
98 fout.write(localTransform());
99 }
100
102 view = MeshObjects::Mesh();
103 }
104
105bool Item::isTorchBurn() const {
106 return false;
107 }
108
109void Item::setPosition(float x, float y, float z) {
110 pos={x,y,z};
111 updateMatrix();
112 }
113
114void Item::setDirection(float, float, float) {
115 }
116
117void Item::setObjMatrix(const Tempest::Matrix4x4 &m) {
118 pos.x = m.at(3,0);
119 pos.y = m.at(3,1);
120 pos.z = m.at(3,2);
122 view.setObjMatrix(m);
123 }
124
125bool Item::isMission() const {
126 return (uint32_t(hitem->flags)&ITM_MISSION);
127 }
128
130 if(e)
131 ++equipped; else
132 --equipped;
133 if(equipped>amount) {
134 Log::e("[",displayName(),"] inconsistent inventory state");
135 }
136 if(equipped==0)
137 itSlot=NSLOT;
138 }
139
144
149
151 if(view.nodesCount()==0)
152 return;
153 auto& p = *world.physic();
154 physic = p.dynamicObj(transform(),view.bounds(),zenkit::MaterialGroup(hitem->material));
155 physic.setItem(this);
156 }
157
159 if(mesh==nullptr)
160 return;
161 auto& p = *world.physic();
162 Bounds b;
163 b.assign(mesh->bbox);
164 physic = p.dynamicObj(transform(),b,zenkit::MaterialGroup(hitem->material));
165 physic.setItem(this);
166 }
167
168bool Item::isDynamic() const {
169 return !physic.isEmpty();
170 }
171
172std::string_view Item::displayName() const {
173 return hitem->name;
174 }
175
176std::string_view Item::description() const {
177 return hitem->description;
178 }
179
180Tempest::Vec3 Item::position() const {
181 return pos;
182 }
183
184Vec3 Item::midPosition() const {
185 auto b = view.bounds();
186 auto v = (b.bbox[1]-b.bbox[0])*0.5;
187 // transform().project(v); // doesn't work for Karibik mod
188 return pos + v;
189 }
190
191bool Item::isGold() const {
192 return hitem->symbol_index()==world.script().goldId()->index();
193 }
194
196 return ItmFlags(hitem->main_flag);
197 }
198
199int32_t Item::itemFlag() const {
200 return static_cast<int>(hitem->flags);
201 }
202
203bool Item::isMulti() const {
204 return uint32_t(hitem->flags)&ITM_MULTI;
205 }
206
207bool Item::isSpellShoot() const {
208 // Whether a spell is a projectile is hardcoded in vanilla, see
209 // https://forum.worldofplayers.de/forum/threads/1460092-Stuck-in-a-charge-spell/page2?p=24786462&viewfull=1#post24786462
210 // Only hardcode Stormfist for now since other spells work with the heuristic based on target_collect_algo
211 if(!isSpellOrRune())
212 return false;
213 bool g1 = world.version().game==1;
214 const int32_t SPL_STORMFIST = 47;
215 if(g1 && spellId()==SPL_STORMFIST)
216 return true;
217 auto& spl = world.script().spellDesc(spellId());
218 return spl.target_collect_algo!=TargetCollect::TARGET_COLLECT_NONE &&
219 spl.target_collect_algo!=TargetCollect::TARGET_COLLECT_CASTER &&
220 spl.target_collect_algo!=TargetCollect::TARGET_COLLECT_FOCUS &&
222 }
223
225 return (uint32_t(mainFlag()) & ITM_CAT_RUNE);
226 }
227
228bool Item::isSpell() const {
229 if(isSpellOrRune())
230 return isMulti();
231 return false;
232 }
233
234bool Item::isRune() const {
235 return isSpellOrRune() && !isSpell();
236 }
237
238bool Item::is2H() const {
239 auto flg = uint32_t(itemFlag());
240 return flg & (ITM_2HD_SWD | ITM_2HD_AXE);
241 }
242
243bool Item::isCrossbow() const {
244 auto flg = uint32_t(itemFlag());
245 return flg & ITM_CROSSBOW;
246 }
247
248bool Item::isRing() const {
249 auto flg = uint32_t(itemFlag());
250 return flg & ITM_RING;
251 }
252
253bool Item::isArmor() const {
254 auto flg = ItmFlags(mainFlag());
255 return flg & ITM_CAT_ARMOR;
256 }
257
258int32_t Item::spellId() const {
259 return hitem->spell;
260 }
261
262int32_t Item::swordLength() const {
263 return hitem->range;
264 }
265
266void Item::setCount(size_t cnt) {
267 amount = uint32_t(cnt);
268 }
269
270size_t Item::count() const {
271 return amount;
272 }
273
274std::string_view Item::uiText(size_t id) const {
275 return hitem->text[id];
276 }
277
278int32_t Item::uiValue(size_t id) const {
279 return hitem->count[id];
280 }
281
282int32_t Item::cost() const {
283 return hitem->value;
284 }
285
286int32_t Item::sellCost() const {
287 return int32_t(std::ceil(world.script().tradeValueMultiplier()*float(cost())));
288 }
289
290bool Item::checkCond(const Npc &other) const {
291 int32_t a=0,v=0;
292 return checkCondUse(other,a,v) && checkCondRune(other,a,v);
293 }
294
295bool Item::checkCondUse(const Npc &other, int32_t &a, int32_t &nv) const {
296 for(size_t i=0;i<zenkit::IItem::condition_count;++i){
297 auto atr = Attribute(hitem->cond_atr[i]);
298 if(other.attribute(atr)<hitem->cond_value[i] && hitem->cond_value[i]!=0) {
299 a = atr;
300 nv = hitem->cond_value[i];
301 return false;
302 }
303 }
304 return true;
305 }
306
307bool Item::checkCondRune(const Npc &other, int32_t &cPl, int32_t &cIt) const {
308 cIt = hitem->mag_circle;
309 cPl = other.mageCycle();
310 return (cPl>=cIt);
311 }
312
313size_t Item::clsId() const {
314 return hitem->symbol_index();
315 }
316
317void Item::updateMatrix() {
318 Tempest::Matrix4x4 mat;
319 mat.identity();
320 mat.translate(pos.x,pos.y,pos.z);
322 }
323
325 view .setObjMatrix(transform());
326 physic.setObjMatrix(transform());
327 if(!isDynamic())
329 }
void assign(const Tempest::Vec3 &cen, float sizeSz)
void initializeInstanceItem(const std::shared_ptr< zenkit::IItem > &item, size_t instance)
const zenkit::ISpell & spellDesc(int32_t splId)
float tradeValueMultiplier() const
Definition gamescript.h:163
auto * goldId() const
Definition gamescript.h:95
auto & getVm()
Definition gamescript.h:78
Definition item.h:14
void setPhysicsDisable()
Definition item.cpp:145
~Item()
Definition item.cpp:81
bool isRune() const
Definition item.cpp:234
bool isRing() const
Definition item.cpp:248
std::string_view displayName() const
Definition item.cpp:172
Type
Definition item.h:18
@ T_Inventory
Definition item.h:21
@ T_WorldDyn
Definition item.h:20
Tempest::Vec3 midPosition() const
Definition item.cpp:184
bool isGold() const
Definition item.cpp:191
int32_t spellId() const
Definition item.cpp:258
bool isSpellOrRune() const
Definition item.cpp:224
int32_t cost() const
Definition item.cpp:282
bool checkCondRune(const Npc &other, int32_t &cPl, int32_t &cIt) const
Definition item.cpp:307
size_t count() const
Definition item.cpp:270
virtual bool isTorchBurn() const
Definition item.cpp:105
void setPosition(float x, float y, float z)
Definition item.cpp:109
Item(World &owner, size_t inst, Type type)
Definition item.cpp:14
ItmFlags mainFlag() const
Definition item.cpp:195
std::string_view uiText(size_t id) const
Definition item.cpp:274
int32_t uiValue(size_t id) const
Definition item.cpp:278
void setCount(size_t cnt)
Definition item.cpp:266
bool isSpellShoot() const
Definition item.cpp:207
bool checkCond(const Npc &other) const
Definition item.cpp:290
size_t clsId() const
Definition item.cpp:313
int32_t itemFlag() const
Definition item.cpp:199
bool isArmor() const
Definition item.cpp:253
void moveEvent() override
Definition item.cpp:324
bool isSpell() const
Definition item.cpp:228
void setObjMatrix(const Tempest::Matrix4x4 &m)
Definition item.cpp:117
bool isMission() const
Definition item.cpp:125
void setPhysicsEnable(World &w)
Definition item.cpp:140
bool isCrossbow() const
Definition item.cpp:243
std::string_view description() const
Definition item.cpp:176
bool isMulti() const
Definition item.cpp:203
void setAsEquipped(bool e)
Definition item.cpp:129
bool is2H() const
Definition item.cpp:238
virtual void clearView()
Definition item.cpp:101
bool isDynamic() const override
Definition item.cpp:168
int32_t sellCost() const
Definition item.cpp:286
@ NSLOT
Definition item.h:16
bool checkCondUse(const Npc &other, int32_t &atr, int32_t &nv) const
Definition item.cpp:295
void setDirection(float x, float y, float z)
Definition item.cpp:114
void save(Serialize &fout) const override
Definition item.cpp:84
int32_t swordLength() const
Definition item.cpp:262
Tempest::Vec3 position() const
Definition item.cpp:180
void setObjMatrix(const Tempest::Matrix4x4 &mt)
Bounds bounds() const
size_t nodesCount() const
Definition meshobjects.h:63
Definition npc.h:25
int32_t attribute(Attribute a) const
Definition npc.cpp:1171
int32_t mageCycle() const
Definition npc.cpp:1159
Tempest::Vec3 bbox[2]
Definition protomesh.h:87
void write(const Arg &... a)
Definition serialize.h:76
void read(Arg &... a)
Definition serialize.h:81
Definition vob.h:11
World & world
Definition vob.h:45
void setLocalTransform(const Tempest::Matrix4x4 &p)
Definition vob.cpp:73
auto localTransform() const -> const Tempest::Matrix4x4 &
Definition vob.h:37
auto transform() const -> const Tempest::Matrix4x4 &
Definition vob.h:34
Definition world.h:31
auto version() const -> const VersionInfo &
Definition world.cpp:1023
DynamicWorld * physic() const
Definition world.h:81
void invalidateVobIndex()
Definition world.cpp:832
MeshObjects::Mesh addView(std::string_view visual) const
Definition world.cpp:251
GameScript & script() const
Definition world.cpp:1019
@ TARGET_COLLECT_FOCUS
Definition constants.h:280
@ TARGET_COLLECT_CASTER
Definition constants.h:279
@ TARGET_COLLECT_ALL_FALLBACK_NONE
Definition constants.h:284
@ TARGET_COLLECT_NONE
Definition constants.h:278
ItmFlags
Definition constants.h:312
@ ITM_MULTI
Definition constants.h:335
@ ITM_2HD_SWD
Definition constants.h:330
@ ITM_2HD_AXE
Definition constants.h:331
@ ITM_CAT_RUNE
Definition constants.h:322
@ ITM_RING
Definition constants.h:325
@ ITM_MISSION
Definition constants.h:326
@ ITM_CROSSBOW
Definition constants.h:334
@ ITM_CAT_ARMOR
Definition constants.h:317
Attribute
Definition constants.h:462
bool hasExt(std::string_view s, const char *extIn)
Definition fileext.h:8
bool isEmpty() const
void setItem(::Item *it)
void setObjMatrix(const Tempest::Matrix4x4 &m)