1 /*
2 * Copyright 2011-2013 Arx Libertatis Team (see the AUTHORS file)
3 *
4 * This file is part of Arx Libertatis.
5 *
6 * Arx Libertatis is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Arx Libertatis is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Arx Libertatis. If not, see <http://www.gnu.org/licenses/>.
18 */
19 /* Based on:
20 ===========================================================================
21 ARX FATALIS GPL Source Code
22 Copyright (C) 1999-2010 Arkane Studios SA, a ZeniMax Media company.
23
24 This file is part of the Arx Fatalis GPL Source Code ('Arx Fatalis Source Code').
25
26 Arx Fatalis Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
27 License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
28
29 Arx Fatalis Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
30 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
31
32 You should have received a copy of the GNU General Public License along with Arx Fatalis Source Code. If not, see
33 <http://www.gnu.org/licenses/>.
34
35 In addition, the Arx Fatalis Source Code is also subject to certain additional terms. You should have received a copy of these
36 additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Arx
37 Fatalis Source Code. If not, please request a copy in writing from Arkane Studios at the address below.
38
39 If you have questions concerning this license or the applicable additional terms, you may contact in writing Arkane Studios, c/o
40 ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
41 ===========================================================================
42 */
43 // Code: Cyril Meynier
44 //
45 // Copyright (c) 1999-2001 ARKANE Studios SA. All rights reserved
46
47 #include "game/Inventory.h"
48
49 #include <algorithm>
50 #include <set>
51 #include <vector>
52
53 #include <boost/foreach.hpp>
54
55 #include "ai/Paths.h"
56
57 #include "core/Application.h"
58 #include "core/Config.h"
59
60 #include "game/EntityManager.h"
61 #include "game/Item.h"
62 #include "game/Player.h"
63
64 #include "gui/Interface.h"
65
66 #include "graphics/GraphicsTypes.h"
67 #include "graphics/Math.h"
68 #include "graphics/data/Mesh.h"
69 #include "graphics/data/TextureContainer.h"
70
71 #include "input/Input.h"
72
73 #include "io/log/Logger.h"
74
75 #include "math/Angle.h"
76 #include "math/Vector2.h"
77 #include "math/Vector3.h"
78
79 #include "physics/Box.h"
80
81 #include "platform/Platform.h"
82
83 #include "scene/Light.h"
84 #include "scene/Interactive.h"
85 #include "scene/GameSound.h"
86
87 #include "script/Script.h"
88
89 using std::vector;
90 using std::string;
91
92 //------------------------------------------------------------------------------------
93 extern E_ARX_STATE_MOUSE eMouseState;
94 extern float InventoryX;
95 extern float InventoryDir;
96 extern long PLAYER_INTERFACE_HIDE_COUNT;
97 extern long DRAGGING;
98
99 extern bool TRUE_PLAYER_MOUSELOOK_ON;
100
101 void ARX_INTERFACE_Combat_Mode(long i);
102 void ARX_INVENTORY_ReOrder();
103 void ARX_INVENTORY_IdentifyIO(Entity * _pIO);
104
105 //------------------------------------------------------------------------------------
106 //CInventory Inventory;
107 INVENTORY_SLOT inventory[3][INVENTORY_X][INVENTORY_Y];
108 INVENTORY_DATA * SecondaryInventory = NULL;
109 Entity * DRAGINTER = NULL;
110 Entity * ioSteal = NULL;
111 long InventoryY = 100;
112 static long HERO_OR_SECONDARY = 0;
113 short sActiveInventory = 0;
114
115 // 1 player 2 secondary
116 short sInventory = -1;
117 short sInventoryX = -1;
118 short sInventoryY = -1;
119
120 /*!
121 * Declares an IO as entering into player Inventory
122 * Sends appropriate INVENTORYIN Event to player AND concerned io.
123 */
ARX_INVENTORY_Declare_InventoryIn(Entity * io)124 static void ARX_INVENTORY_Declare_InventoryIn(Entity * io) {
125
126 if(!io) {
127 return;
128 }
129
130 io->show = SHOW_FLAG_IN_INVENTORY;
131
132 if(io->ignition > 0) {
133
134 if(ValidDynLight(io->ignit_light)) {
135 DynLight[io->ignit_light].exist = 0;
136 }
137 io->ignit_light = -1;
138
139 if (io->ignit_sound != audio::INVALID_ID) {
140 ARX_SOUND_Stop(io->ignit_sound);
141 io->ignit_sound = audio::INVALID_ID;
142 }
143
144 io->ignition = 0;
145 }
146
147 EVENT_SENDER = io;
148 SendIOScriptEvent(entities.player(), SM_INVENTORYIN);
149 EVENT_SENDER = entities.player();
150 SendIOScriptEvent(io, SM_INVENTORYIN);
151 EVENT_SENDER = NULL;
152 }
153
154 //*************************************************************************************
155 // void CleanInventory()
156 //-------------------------------------------------------------------------------------
157 // FUNCTION/RESULT:
158 // Cleans Player inventory
159 //*************************************************************************************
CleanInventory()160 void CleanInventory() {
161
162 for(long iNbBag = 0; iNbBag < 3; iNbBag++) {
163 for(size_t j = 0; j < INVENTORY_Y; j++) {
164 for(size_t i = 0; i < INVENTORY_X; i++) {
165 inventory[iNbBag][i][j].io = NULL;
166 inventory[iNbBag][i][j].show = 1;
167 }
168 }
169 }
170
171 sActiveInventory = 0;
172 }
173
174 extern Vec2s DANAEMouse;
175 extern long DANAESIZX;
176 extern long DANAESIZY;
177 extern long DANAECENTERX;
178 extern long DANAECENTERY;
179
GetInventoryObj(Vec2s * pos)180 static Entity * GetInventoryObj(Vec2s * pos) {
181
182 long tx, ty;
183
184
185 float fCenterX = DANAECENTERX - INTERFACE_RATIO(320) + INTERFACE_RATIO(35);
186 float fSizY = DANAESIZY - INTERFACE_RATIO(101) + INTERFACE_RATIO_LONG(InventoryY);
187
188 int iPosX = checked_range_cast<int>(fCenterX);
189 int iPosY = checked_range_cast<int>(fSizY);
190
191
192 if (player.Interface & INTER_INVENTORY)
193 {
194 tx = pos->x - iPosX; //-4
195 ty = pos->y - iPosY; //-2
196
197 if ((tx >= 0) && (ty >= 0))
198 {
199
200 tx = checked_range_cast<long>(tx / INTERFACE_RATIO(32));
201 ty = checked_range_cast<long>(ty / INTERFACE_RATIO(32));
202
203
204 if ((tx >= 0) && ((size_t)tx < INVENTORY_X) && (ty >= 0) && ((size_t)ty < INVENTORY_Y))
205 {
206 if ((inventory[sActiveInventory][tx][ty].io)
207 && (inventory[sActiveInventory][tx][ty].io->gameFlags & GFLAG_INTERACTIVITY))
208 {
209 HERO_OR_SECONDARY = 1;
210 return (inventory[sActiveInventory][tx][ty].io);
211 }
212 }
213
214 return NULL;
215 }
216 }
217 else if (player.Interface & INTER_INVENTORYALL)
218 {
219
220 float fBag = (player.bag - 1) * INTERFACE_RATIO(-121);
221
222 int iY = checked_range_cast<int>(fBag);
223
224
225 for (int i = 0; i < player.bag; i++)
226 {
227 tx = pos->x - iPosX;
228 ty = pos->y - iPosY - iY;
229
230 tx = checked_range_cast<long>(tx / INTERFACE_RATIO(32));
231 ty = checked_range_cast<long>(ty / INTERFACE_RATIO(32));
232
233 if ((tx >= 0) && ((size_t)tx < INVENTORY_X) && (ty >= 0) && ((size_t)ty < INVENTORY_Y))
234 {
235 if ((inventory[i][tx][ty].io)
236 && (inventory[i][tx][ty].io->gameFlags & GFLAG_INTERACTIVITY))
237 {
238 HERO_OR_SECONDARY = 1;
239 return (inventory[i][tx][ty].io);
240 }
241
242 return NULL;
243 }
244
245 iY += checked_range_cast<int>(INTERFACE_RATIO(121));
246 }
247 }
248
249 return NULL;
250 }
251
252
253 //*************************************************************************************
254 // Entity * GetInventoryObj_INVENTORYUSE(EERIE_S2D * pos)
255 //-------------------------------------------------------------------------------------
256 // FUNCTION/RESULT:
257 //
258 //*************************************************************************************
GetInventoryObj_INVENTORYUSE(Vec2s * pos)259 Entity * GetInventoryObj_INVENTORYUSE(Vec2s * pos)
260 {
261 Entity * io = GetFromInventory(pos);
262
263 if (io != NULL)
264 {
265 if (HERO_OR_SECONDARY == 2)
266 {
267 if (SecondaryInventory != NULL)
268 {
269 Entity * temp = (Entity *)SecondaryInventory->io;
270
271 if (temp->ioflags & IO_SHOP) return NULL;
272 }
273 }
274
275 return io;
276 }
277
278 if (InInventoryPos(pos)) return NULL;
279
280 if ((io = InterClick(pos)) != NULL)
281 {
282 return io;
283 }
284
285 return NULL;
286
287 }
288
289 //*************************************************************************************
290 // void PutInFrontOfPlayer(Entity * io,long flag)
291 //-------------------------------------------------------------------------------------
292 // FUNCTION/RESULT:
293 // Puts an IO in front of the player
294 //*************************************************************************************
PutInFrontOfPlayer(Entity * io)295 void PutInFrontOfPlayer(Entity * io)
296 {
297 if (io == NULL) return;
298
299 float t = radians(player.angle.b);
300 io->pos.x = player.pos.x - (float)EEsin(t) * 80.f;
301 io->pos.y = player.pos.y + 20.f;
302 io->pos.z = player.pos.z + (float)EEcos(t) * 80.f;
303 io->velocity.y = 0.3f;
304 io->velocity.x = 0;
305 io->velocity.z = 0;
306 io->angle.a = 0.f;
307 io->angle.b = 0;
308 io->angle.g = 0.f;
309 io->stopped = 0;
310 io->show = SHOW_FLAG_IN_SCENE;
311
312 if (io->obj && io->obj->pbox)
313 {
314 Vec3f vector = Vec3f(0.f, 100.f, 0.f);
315 Vec3f pos = io->pos;
316 io->soundtime = 0;
317 io->soundcount = 0;
318 EERIE_PHYSICS_BOX_Launch(io->obj, &pos, &vector);
319 }
320 }
321
322 //*************************************************************************************
323 // void IO_Drop_Item(Entity * io_src,Entity * io)
324 //-------------------------------------------------------------------------------------
325 // FUNCTION/RESULT:
326 // forces "io_scr" IO to drop "io" item with physics
327 //*************************************************************************************
IO_Drop_Item(Entity * io_src,Entity * io)328 void IO_Drop_Item(Entity * io_src, Entity * io)
329 {
330 // Validity Check
331 if ((!io) || (!io_src)) return;
332
333 float t = radians(io_src->angle.b);
334 io->velocity.x = -(float)EEsin(t) * 50.f;
335 io->velocity.y = 0.3f;
336 io->velocity.z = (float)EEcos(t) * 50.f;
337 io->angle.a = 0.f;
338 io->angle.b = 0;
339 io->angle.g = 0.f;
340 io->stopped = 0;
341 io->show = SHOW_FLAG_IN_SCENE;
342
343 if(io->obj && io->obj->pbox) {
344 Vec3f vector(0.f, 100.f, 0.f);
345 Vec3f pos = io->pos;
346 io->soundtime = 0;
347 io->soundcount = 0;
348 EERIE_PHYSICS_BOX_Launch_NOCOL(io, io->obj, &pos, &vector);
349 }
350 }
351
operator <<(std::ostream & strm,const InventoryPos & p)352 std::ostream & operator<<(std::ostream & strm, const InventoryPos & p) {
353 return strm << '(' << p.io << ", " << p.bag << ", " << p.x << ", " << p.y << ')';
354 }
355
356 namespace {
357
358 // Glue code to access both player and IO inventories in a uniform way.
359 template <size_t MaxBags, size_t MaxWidth, size_t MaxHeight>
360 struct InventoryArray {
361 typedef INVENTORY_SLOT type[MaxBags][MaxWidth][MaxHeight];
362 typedef InventoryPos::index_type index_type;
index__anon52c49df60111::InventoryArray363 static INVENTORY_SLOT & index(type & data, index_type bag,
364 index_type x, index_type y) {
365 return data[bag][x][y];
366 }
index__anon52c49df60111::InventoryArray367 static const INVENTORY_SLOT & index(const type & data, index_type bag,
368 index_type x, index_type y) {
369 return data[bag][x][y];
370 }
371 };
372 template <size_t MaxWidth, size_t MaxHeight>
373 struct InventoryArray<1, MaxWidth, MaxHeight> {
374 typedef INVENTORY_SLOT type[MaxWidth][MaxHeight];
375 typedef InventoryPos::index_type index_type;
index__anon52c49df60111::InventoryArray376 static INVENTORY_SLOT & index(type & data, index_type bag,
377 index_type x, index_type y) {
378 ARX_UNUSED(bag);
379 return data[x][y];
380 }
index__anon52c49df60111::InventoryArray381 static const INVENTORY_SLOT & index(const type & data, index_type bag,
382 index_type x, index_type y) {
383 ARX_UNUSED(bag);
384 return data[x][y];
385 }
386 };
387
388 //! Compare items by their size and name
389 struct ItemSizeComaparator {
operator ()__anon52c49df60111::ItemSizeComaparator390 bool operator()(const Entity * a, const Entity * b) const {
391 int sizea = a->sizex * a->sizey * a->sizey;
392 int sizeb = b->sizex * b->sizey * b->sizey;
393 if(sizea != sizeb) {
394 return (sizea > sizeb);
395 }
396 int locname = a->locname.compare(b->locname);
397 if(locname != 0) {
398 return (locname < 0);
399 }
400 int name = a->long_name().compare(b->long_name());
401 if(name != 0) {
402 return (name < 0);
403 }
404 return (a < b);
405 }
406 };
407
408 // TODO this class should probably be used directly in player and IO objects
409 template <size_t MaxBags, size_t MaxWidth, size_t MaxHeight>
410 class Inventory {
411
412 typedef InventoryPos Pos;
413
414 public:
415
416 typedef InventoryArray<MaxBags, MaxWidth, MaxHeight> Array;
417 typedef typename Array::type array_type;
418 typedef unsigned short size_type;
419 typedef InventoryPos::index_type index_type;
420
421 private:
422
423 long io;
424 array_type & data;
425 size_type bags;
426 size_type width;
427 size_type height;
428
index(index_type bag,index_type x,index_type y)429 INVENTORY_SLOT & index(index_type bag, index_type x, index_type y) {
430 return Array::index(data, bag, x, y);
431 }
index(index_type bag,index_type x,index_type y) const432 const INVENTORY_SLOT & index(index_type bag, index_type x, index_type y) const {
433 return Array::index(data, bag, x, y);
434 }
435
index(const InventoryPos & pos)436 INVENTORY_SLOT & index(const InventoryPos & pos) {
437 return index(pos.bag, pos.x, pos.y);
438 }
index(const InventoryPos & pos) const439 const INVENTORY_SLOT & index(const InventoryPos & pos) const {
440 return index(pos.bag, pos.x, pos.y);
441 }
442
insertImpl(Entity * item)443 Pos insertImpl(Entity * item) {
444 arx_assert(item != NULL && (item->ioflags & IO_ITEM));
445 if(Pos pos = insertIntoStack(item)) {
446 return pos;
447 }
448 return insertIntoNewSlot(item);
449 }
450
insertImpl(Entity * item,const Pos & pos)451 Pos insertImpl(Entity * item, const Pos & pos) {
452 arx_assert(item != NULL && (item->ioflags & IO_ITEM));
453 if(insertIntoStackAt(item, pos)) {
454 return pos;
455 }
456 if(Pos newPos = insertIntoStack(item)) {
457 return newPos;
458 }
459 if(insertIntoNewSlotAt(item, pos)) {
460 return pos;
461 }
462 return insertIntoNewSlot(item);
463 }
464
removeAt(const Entity * item,const Pos & pos)465 void removeAt(const Entity * item, const Pos & pos) {
466
467 arx_assert(item != NULL && (item->ioflags & IO_ITEM));
468 arx_assert(pos.x + item->sizex <= width);
469 arx_assert(pos.y + item->sizey <= height);
470 arx_assert(index(pos).io == item);
471
472 LogDebug(" - " << pos << " remove " << item->long_name()
473 << " [" << item->_itemdata->count << '/'
474 << item->_itemdata->playerstacksize << "]: "
475 << int(item->sizex) << 'x' << int(item->sizey));
476
477 for(index_type j = pos.y; j < (pos.y + size_type(item->sizey)); j++) {
478 for(index_type i = pos.x; i < (pos.x + size_type(item->sizex)); i++) {
479 index(pos.bag, i, j).io = NULL;
480 index(pos.bag, i, j).show = 0;
481 }
482 }
483 }
484
insertIntoNewSlotAt(Entity * item,const Pos & pos)485 bool insertIntoNewSlotAt(Entity * item, const Pos & pos) {
486
487 if(!pos || pos.bag >= bags) {
488 return false;
489 }
490
491 if(pos.x + item->sizex > width || pos.y + item->sizey > height) {
492 return false;
493 }
494
495 arx_assert(item != NULL && (item->ioflags & IO_ITEM));
496
497 // Check if the whole area required by this item is empty
498 for(index_type j = pos.y; j < pos.y + item->sizey; j++) {
499 for(index_type i = pos.x; i < pos.x + item->sizex; i++) {
500 if(index(pos.bag, i, j).io != NULL) {
501 return false;
502 }
503 }
504 }
505
506 LogDebug(" - " << pos << " := " << item->long_name()
507 << " [" << item->_itemdata->count << '/'
508 << item->_itemdata->playerstacksize << "]: "
509 << int(item->sizex) << 'x' << int(item->sizey));
510
511 // Insert the item at the found position
512 for(index_type j = pos.y; j < (pos.y + item->sizey); j++) {
513 for (index_type i = pos.x; i < (pos.x + item->sizex); i++) {
514 index(pos.bag, i, j).io = item;
515 index(pos.bag, i, j).show = 0;
516 }
517 }
518 index(pos).show = 1;
519
520 return true;
521 }
522
insertIntoNewSlot(Entity * item)523 Pos insertIntoNewSlot(Entity * item) {
524
525 arx_assert(item != NULL && (item->ioflags & IO_ITEM));
526
527 for(index_type bag = 0; bag < bags; bag++) {
528 for(index_type i = 0; i < width + 1 - item->sizex; i++) {
529 for(index_type j = 0; j < height + 1 - item->sizey; j++) {
530
531 // Ignore already used inventory slots
532 if(index(bag, i, j).io != NULL) {
533 continue;
534 }
535
536 Pos pos(io, bag, i, j);
537 if(insertIntoNewSlotAt(item, pos)) {
538 return pos;
539 }
540 }
541 }
542 }
543
544 return Pos();
545 }
546
insertIntoStackAt(Entity * item,const Pos & pos)547 bool insertIntoStackAt(Entity * item, const Pos & pos) {
548
549 if(!pos || pos.bag >= bags) {
550 return false;
551 }
552
553 if(pos.x + item->sizex > width || pos.y + item->sizey > height) {
554 return false;
555 }
556
557 arx_assert(item != NULL && (item->ioflags & IO_ITEM));
558
559 Entity * io = index(pos).io;
560
561 // Ignore empty slots and different or non-stackeable items
562 if(!io || io->_itemdata->playerstacksize <= 1 || !IsSameObject(item, io)) {
563 return false;
564 }
565
566 // Ignore full stacks
567 if(io->_itemdata->count >= io->_itemdata->playerstacksize) {
568 return false;
569 }
570
571 // Get the number of items to add to the stack
572 short int remainingSpace = io->_itemdata->playerstacksize - io->_itemdata->count;
573 short int count = std::min(item->_itemdata->count, remainingSpace);
574
575 LogDebug(" - " << pos << " " << io->long_name()
576 << " [" << io->_itemdata->count << '/'
577 << io->_itemdata->playerstacksize << "] += "
578 << item->long_name() << " x" << count << '/' << item->_itemdata->count);
579
580 io->_itemdata->count += count, item->_itemdata->count -= count;
581
582 if(item->_itemdata->count != 0) {
583 // We inserted some of the items into the stack, but there was not enough
584 // space for all of them.
585 return false;
586 }
587
588 // Delete or hide the old item
589 if(item->scriptload) {
590 delete item;
591 } else {
592 item->show = SHOW_FLAG_KILLED;
593 }
594 return true;
595 }
596
insertIntoStack(Entity * item)597 Pos insertIntoStack(Entity * item) {
598
599 arx_assert(item != NULL && (item->ioflags & IO_ITEM));
600
601 // Try to add the items to an existing stack
602 for(index_type bag = 0; bag < bags; bag++) {
603 for(index_type i = 0; i < width + 1 - size_type(item->sizex); i++) {
604 for(index_type j = 0; j < height + 1 - size_type(item->sizey); j++) {
605 Pos pos(io, bag, i, j);
606 if(insertIntoStackAt(item, pos)) {
607 return pos;
608 }
609 }
610 }
611 }
612
613 return Pos();
614 }
615
616 public:
617
Inventory(long io,array_type & data,size_type bags,size_type width,size_type height)618 Inventory(long io, array_type & data, size_type bags, size_type width, size_type height)
619 : io(io), data(data), bags(bags), width(width), height(height) { }
620
Inventory(const Inventory & o)621 Inventory(const Inventory & o)
622 : io(o.io), data(o.data), bags(o.bags), width(o.width), height(o.height) { }
623
624 /*!
625 * Insert an item into the inventory
626 * The item will be added to existing stacks if possible.
627 * Otherwise the first empty slot will be used.
628 *
629 * Does not check if the item is already in the inventory!
630 *
631 * @param item the item to insert
632 *
633 * @return true if the item was inserted, false otherwise
634 */
insert(Entity * item)635 bool insert(Entity * item) {
636 if(item && (item->ioflags & IO_ITEM)) {
637 if(Pos pos = insertImpl(item)) {
638 ARX_INVENTORY_Declare_InventoryIn(get(pos));
639 return true;
640 }
641 }
642 return false;
643 }
644
645 /*!
646 * Insert an item into the inventory
647 * The item will be added to existing stacks if possible.
648 * Otherwise, the item will be inserted at the specified position.
649 * If that fails, the first empty slot will be used.
650 *
651 * Does not check if the item is already in the inventory!
652 *
653 * @param item the item to insert
654 *
655 * @return true if the item was inserted, false otherwise
656 */
insert(Entity * item,const Pos & pos)657 bool insert(Entity * item, const Pos & pos) {
658 if(item && (item->ioflags & IO_ITEM)) {
659 if(Pos newPos = insertImpl(item, pos)) {
660 ARX_INVENTORY_Declare_InventoryIn(get(newPos));
661 return true;
662 }
663 }
664 return false;
665 }
666
667 //! Sort the inventory and stack duplicate items
optimize()668 void optimize() {
669
670 LogDebug("collecting items");
671
672 // Collect all inventory items
673 vector<Entity *> items;
674 for(size_t bag = 0; bag < bags; bag++) {
675 for(size_t j = 0 ; j < height; j++) {
676 for(size_t i = 0 ; i < width; i++) {
677 INVENTORY_SLOT & slot = index(bag, i, j);
678 if(slot.io && slot.show) {
679 items.push_back(slot.io);
680 removeAt(slot.io, Pos(io, bag, i, j));
681 }
682 slot.io = NULL;
683 slot.show = 0;
684 }
685 }
686 }
687
688 // Sort the items by their size and name
689 std::sort(items.begin(), items.end(), ItemSizeComaparator());
690
691 LogDebug("sorting");
692 #ifdef ARX_DEBUG
693 BOOST_FOREACH(const Entity * item, items) {
694 LogDebug(" - " << item->long_name() << ": "
695 << int(item->sizex) << 'x' << int(item->sizey));
696 }
697 #endif
698
699 LogDebug("putting back items");
700
701 // Now put the items back into the inventory
702 BOOST_FOREACH(Entity * item, items) {
703 if(!insertImpl(item)) {
704 // TODO: oops - there was no space for the item
705 // ideally this should not happen, but the current sorting algorithm does not
706 // guarantee that the resulting order is at least as good as the existing one
707 LogDebug("could not insert " << item->long_name() << " after sorting inventory");
708 PutInFrontOfPlayer(item);
709 }
710 }
711 }
712
713 /*!
714 * Get the position of an item in the inventory.
715 *
716 * @return the position of the item
717 */
locate(const Entity * item) const718 Pos locate(const Entity * item) const {
719 for(size_t bag = 0; bag < bags; bag++) {
720 for(size_t i = 0; i < width; i++) {
721 for(size_t j = 0; j < height; j++) {
722 if(index(bag, i, j).io == item) {
723 return Pos(io, bag, i, j);
724 }
725 }
726 }
727 }
728 return Pos();
729 }
730
731 /*!
732 * Remove an item from the inventory.
733 * The item is not deleted.
734 *
735 * @return the old position of the item
736 */
remove(const Entity * item)737 Pos remove(const Entity * item) {
738 Pos pos = locate(item);
739 if(pos) {
740 /* TODO There was a bug cauing corrupted inventories where an item
741 * takes up more slots than specified by its size. Ideally, this should
742 * be fixed while loading old save games, but until then we just fix it
743 * here when removing items.
744 removeAt(item, pos);
745 */
746 for(size_t j = 0; j < height; j++) {
747 for(size_t i = 0; i < width; i++) {
748 if(index(pos.bag, i, j).io == item) {
749 index(pos.bag, i, j).io = NULL;
750 index(pos.bag, i, j).show = 0;
751 }
752 }
753 }
754 }
755 return pos;
756 }
757
get(const Pos & pos) const758 Entity * get(const Pos & pos) const {
759 return pos ? index(pos).io : NULL;
760 }
761
762 };
763
getPlayerInventory()764 Inventory<3, INVENTORY_X, INVENTORY_Y> getPlayerInventory() {
765 return Inventory<3, INVENTORY_X, INVENTORY_Y>(0, inventory, player.bag,
766 INVENTORY_X, INVENTORY_Y);
767 }
768
getIoInventory(Entity * io)769 Inventory<1, 20, 20> getIoInventory(Entity * io) {
770 arx_assert(io != NULL && io->inventory != NULL);
771 INVENTORY_DATA * inv = io->inventory;
772 return Inventory<1, 20, 20>(io->index(), inv->slot, 1, inv->sizex, inv->sizey);
773 }
774
775 } // anonymous namespace
776
777 PlayerInventory playerInventory;
778
locate(const Entity * item)779 PlayerInventory::Pos PlayerInventory::locate(const Entity * item) {
780 return getPlayerInventory().locate(item);
781 }
782
remove(const Entity * item)783 PlayerInventory::Pos PlayerInventory::remove(const Entity * item) {
784 return getPlayerInventory().remove(item);
785 }
786
insert(Entity * item)787 bool PlayerInventory::insert(Entity * item) {
788 if(item && (item->ioflags & IO_GOLD)) {
789 ARX_PLAYER_AddGold(item);
790 return true;
791 }
792 return getPlayerInventory().insert(item);
793 }
794
insert(Entity * item,const Pos & pos)795 bool PlayerInventory::insert(Entity * item, const Pos & pos) {
796 if(item && (item->ioflags & IO_GOLD)) {
797 ARX_PLAYER_AddGold(item);
798 return true;
799 }
800 return getPlayerInventory().insert(item, pos);
801 }
802
optimize()803 void PlayerInventory::optimize() {
804 getPlayerInventory().optimize();
805 }
806
giveToPlayer(Entity * item)807 bool giveToPlayer(Entity * item) {
808 if(playerInventory.insert(item)) {
809 return true;
810 } else {
811 PutInFrontOfPlayer(item);
812 return false;
813 }
814 }
815
giveToPlayer(Entity * item,const InventoryPos & pos)816 bool giveToPlayer(Entity * item, const InventoryPos & pos) {
817 if(playerInventory.insert(item, pos)) {
818 return true;
819 } else {
820 PutInFrontOfPlayer(item);
821 return false;
822 }
823 }
824
removeFromInventories(Entity * item)825 InventoryPos removeFromInventories(Entity * item) {
826
827 // TODO the item should know the inventory it is in and position
828
829 InventoryPos oldPos = playerInventory.remove(item);
830 if(oldPos) {
831 return oldPos;
832 }
833
834 for(size_t i = 1; i < entities.size(); i++) {
835 if(entities[i] && entities[i]->inventory) {
836 oldPos = getIoInventory(entities[i]).remove(item);
837 if(oldPos) {
838 return oldPos;
839 }
840 }
841 }
842
843 return InventoryPos();
844 }
845
locateInInventories(const Entity * item)846 InventoryPos locateInInventories(const Entity * item) {
847
848 InventoryPos pos = playerInventory.locate(item);
849 if(pos) {
850 return pos;
851 }
852
853 for(size_t i = 1; i < entities.size(); i++) {
854 if(entities[i] && entities[i]->inventory) {
855 pos = getIoInventory(entities[i]).locate(item);
856 if(pos) {
857 return pos;
858 }
859 }
860 }
861
862 return InventoryPos();
863 }
864
insertIntoInventory(Entity * item,const InventoryPos & pos)865 bool insertIntoInventory(Entity * item, const InventoryPos & pos) {
866
867 if(pos.io == 0) {
868 return giveToPlayer(item, pos);
869 }
870
871 if(ValidIONum(pos.io) && entities[pos.io]->inventory) {
872 if(getIoInventory(entities[pos.io]).insert(item, pos)) {
873 return true;
874 }
875 }
876
877 PutInFrontOfPlayer(item);
878 return false;
879 }
880
881 //*************************************************************************************
882 // bool CanBePutInInventory(Entity * io)
883 //-------------------------------------------------------------------------------------
884 // FUNCTION/RESULT:
885 // tries to put an object in player inventory
886 //*************************************************************************************
887 // TODO replace remaining uses of this with playerInventory.insert()
CanBePutInInventory(Entity * io)888 bool CanBePutInInventory(Entity * io)
889 {
890 if (io == NULL) return false;
891
892 if (io->ioflags & IO_MOVABLE) return false;
893
894 if(io->ioflags & IO_GOLD) {
895 ARX_PLAYER_AddGold(io);
896 return true;
897 }
898
899 long sx, sy;
900 long i, j, k, l;
901
902 sx = io->sizex;
903 sy = io->sizey;
904
905 // on essaie de le remettre à son ancienne place --------------------------
906 if (sInventory == 1 &&
907 (sInventoryX >= 0) &&
908 ((size_t)sInventoryX <= INVENTORY_X - sx) &&
909 (sInventoryY >= 0) &&
910 ((size_t)sInventoryY <= INVENTORY_Y - sy))
911 {
912 j = sInventoryY;
913 i = sInventoryX;
914
915 // first try to stack -------------------------------------------------
916 if (player.bag)
917 {
918 for (int iNbBag = 0; iNbBag < player.bag; iNbBag++)
919 {
920
921 Entity * ioo = inventory[iNbBag][i][j].io;
922
923 if ((ioo)
924 && (ioo->_itemdata->playerstacksize > 1)
925 && (IsSameObject(io, ioo)))
926 {
927 if (ioo->_itemdata->count < ioo->_itemdata->playerstacksize)
928 {
929 ioo->_itemdata->count += io->_itemdata->count;
930
931 if (ioo->_itemdata->count > ioo->_itemdata->playerstacksize)
932 {
933 io->_itemdata->count = ioo->_itemdata->count - ioo->_itemdata->playerstacksize;
934 ioo->_itemdata->count = ioo->_itemdata->playerstacksize;
935 }
936 else io->_itemdata->count = 0;
937
938 if(!io->_itemdata->count) {
939 io->destroy();
940 }
941
942 ARX_INVENTORY_Declare_InventoryIn(ioo);
943 sInventory = -1;
944 return true;
945 }
946 }
947 }
948 }
949
950
951 if (player.bag)
952 {
953 for (int iNbBag = 0; iNbBag < player.bag; iNbBag++)
954 {
955 if (inventory[iNbBag][i][j].io == NULL)
956 {
957 bool valid = true;
958
959 if ((sx == 0) || (sy == 0)) valid = false;
960
961 for (k = j; k < j + sy; k++)
962 for (l = i; l < i + sx; l++)
963 {
964 if (inventory[iNbBag][l][k].io != NULL) valid = false;
965 }
966
967 if (valid)
968 {
969 for (k = j; k < j + sy; k++)
970 for (l = i; l < i + sx; l++)
971 {
972 inventory[iNbBag][l][k].io = io;
973 inventory[iNbBag][l][k].show = 0;
974 }
975
976 inventory[iNbBag][i][j].show = 1;
977 ARX_INVENTORY_Declare_InventoryIn(io);
978 sInventory = -1;
979 return true;
980 }
981 }
982 }
983 }
984 }
985
986
987 if(player.bag) {
988 for (int iNbBag = 0; iNbBag < player.bag; iNbBag++) {
989 for(size_t i = 0; i <= INVENTORY_X - sx; i++) {
990 for(size_t j = 0; j <= INVENTORY_Y - sy; j++) {
991
992 Entity * ioo = inventory[iNbBag][i][j].io;
993
994 if ((ioo)
995 && (ioo->_itemdata->playerstacksize > 1)
996 && (IsSameObject(io, ioo)))
997 {
998 if (ioo->_itemdata->count < ioo->_itemdata->playerstacksize)
999 {
1000
1001 ioo->_itemdata->count += io->_itemdata->count;
1002
1003
1004 if (ioo->_itemdata->count > ioo->_itemdata->playerstacksize)
1005 {
1006 io->_itemdata->count = ioo->_itemdata->count - ioo->_itemdata->playerstacksize;
1007 ioo->_itemdata->count = ioo->_itemdata->playerstacksize;
1008 }
1009 else io->_itemdata->count = 0;
1010
1011 if(!io->_itemdata->count) {
1012 io->destroy();
1013 ARX_INVENTORY_Declare_InventoryIn(ioo);
1014 return true;
1015 }
1016 }
1017 }
1018 }
1019 }
1020 }
1021 }
1022
1023 if(player.bag) {
1024 for(int iNbBag = 0; iNbBag < player.bag; iNbBag++) {
1025 for(size_t i = 0; i <= INVENTORY_X - sx; i++) {
1026 for(size_t j = 0; j <= INVENTORY_Y - sy; j++) {
1027
1028 if (inventory[iNbBag][i][j].io == NULL)
1029 {
1030 bool valid = true;
1031
1032 if ((sx == 0) || (sy == 0)) valid = false;
1033
1034 for (size_t k = j; k < j + sy; k++)
1035 for (size_t l = i; l < i + sx; l++)
1036 {
1037 if (inventory[iNbBag][l][k].io != NULL) valid = false;
1038 }
1039
1040 if (valid)
1041 {
1042 for (size_t k = j; k < j + sy; k++)
1043 for (size_t l = i; l < i + sx; l++)
1044 {
1045 inventory[iNbBag][l][k].io = io;
1046 inventory[iNbBag][l][k].show = 0;
1047 }
1048
1049 inventory[iNbBag][i][j].show = 1;
1050 ARX_INVENTORY_Declare_InventoryIn(io);
1051 return true;
1052 }
1053 }
1054 }
1055 }
1056 }
1057 }
1058
1059 return false;
1060 }
1061
1062 //*************************************************************************************
1063 // bool CanBePutInSecondaryInventory(INVENTORY_DATA * id,Entity * io,long * xx,long * yy)
1064 //------------------------------------------------------------------------------------------------
1065 // FUNCTION/RESULT:
1066 // Tries to put an object in secondary inventory
1067 //*************************************************************************************
CanBePutInSecondaryInventory(INVENTORY_DATA * id,Entity * io,long * xx,long * yy)1068 bool CanBePutInSecondaryInventory(INVENTORY_DATA * id, Entity * io, long * xx, long * yy)
1069 {
1070 if (!id) return false;
1071
1072 if (!io) return false;
1073
1074 if (io->ioflags & IO_MOVABLE) return false;
1075
1076 long sx, sy;
1077 long i, j, k, l;
1078
1079 *xx = -1;
1080 *yy = -1;
1081
1082 sx = io->sizex;
1083 sy = io->sizey;
1084
1085 // on essaie de le remettre à son ancienne place
1086 if (sInventory == 2 &&
1087 (sInventoryX >= 0) &&
1088 (sInventoryX <= id->sizex - sx) &&
1089 (sInventoryY >= 0) &&
1090 (sInventoryY <= id->sizey - sy))
1091 {
1092 j = sInventoryY;
1093 i = sInventoryX;
1094 // first try to stack
1095
1096
1097 Entity * ioo = id->slot[i][j].io;
1098
1099 if (ioo)
1100 if ((ioo->_itemdata->playerstacksize > 1) &&
1101 (IsSameObject(io, ioo)))
1102 {
1103 if ((ioo->_itemdata->count < ioo->_itemdata->playerstacksize)
1104 && (ioo->durability == io->durability))
1105 {
1106 if (io->ioflags & IO_GOLD)
1107 {
1108 ioo->_itemdata->price += io->_itemdata->price;
1109 }
1110 else
1111 {
1112 ioo->_itemdata->count += io->_itemdata->count;
1113 ioo->scale = 1.f;
1114 }
1115
1116 io->destroy();
1117
1118 sInventory = -1;
1119 return true;
1120 }
1121 }
1122
1123
1124 ioo = id->slot[i][j].io;
1125
1126 if (!ioo)
1127 {
1128 long valid = 1;
1129
1130 if ((sx == 0) || (sy == 0)) valid = 0;
1131
1132 for (k = j; k < j + sy; k++)
1133 for (l = i; l < i + sx; l++)
1134 {
1135 if (id->slot[l][k].io != NULL)
1136 {
1137 valid = 0;
1138 break;
1139 }
1140 }
1141
1142 if (valid)
1143 {
1144 for (k = j; k < j + sy; k++)
1145 for (l = i; l < i + sx; l++)
1146 {
1147 id->slot[l][k].io = io;
1148 id->slot[l][k].show = 0;
1149 }
1150
1151 id->slot[i][j].show = 1;
1152 *xx = i;
1153 *yy = j;
1154 sInventory = -1;
1155 return true;
1156 }
1157 }
1158 }
1159
1160 for (j = 0; j <= id->sizey - sy; j++)
1161 for (i = 0; i <= id->sizex - sx; i++)
1162 {
1163 Entity * ioo = id->slot[i][j].io;
1164
1165 if (ioo)
1166 if ((ioo->_itemdata->playerstacksize > 1) &&
1167 (IsSameObject(io, ioo)))
1168 {
1169 if ((ioo->_itemdata->count < ioo->_itemdata->playerstacksize)
1170 && (ioo->durability == io->durability))
1171 {
1172 if (io->ioflags & IO_GOLD)
1173 {
1174 ioo->_itemdata->price += io->_itemdata->price;
1175 }
1176 else
1177 {
1178 ioo->_itemdata->count += io->_itemdata->count;
1179 ioo->scale = 1.f;
1180 }
1181
1182 io->destroy();
1183
1184 return true;
1185 }
1186 }
1187 }
1188
1189 for (j = 0; j <= id->sizey - sy; j++)
1190 for (i = 0; i <= id->sizex - sx; i++)
1191 {
1192 Entity * ioo = id->slot[i][j].io;
1193
1194 if (!ioo)
1195 {
1196 long valid = 1;
1197
1198 if ((sx == 0) || (sy == 0)) valid = 0;
1199
1200 for (k = j; k < j + sy; k++)
1201 for (l = i; l < i + sx; l++)
1202 {
1203 if (id->slot[l][k].io != NULL)
1204 {
1205 valid = 0;
1206 break;
1207 }
1208 }
1209
1210 if (valid)
1211 {
1212 for (k = j; k < j + sy; k++)
1213 for (l = i; l < i + sx; l++)
1214 {
1215 id->slot[l][k].io = io;
1216 id->slot[l][k].show = 0;
1217 }
1218
1219 id->slot[i][j].show = 1;
1220 *xx = i;
1221 *yy = j;
1222 return true;
1223 }
1224 }
1225 }
1226
1227 *xx = -1;
1228 *yy = -1;
1229
1230 return false;
1231 }
1232
1233 //*************************************************************************************
1234 // bool PutInInventory()
1235 //-------------------------------------------------------------------------------------
1236 // FUNCTION/RESULT:
1237 // Try to put DRAGINTER object in an inventory
1238 //*************************************************************************************
PutInInventory()1239 bool PutInInventory()
1240 {
1241 // Check Validity
1242 if ((!DRAGINTER)
1243 || (DRAGINTER->ioflags & IO_MOVABLE))
1244 return false;
1245
1246 short tx, ty;
1247 long sx, sy;
1248 long i, j;
1249
1250
1251 tx = ty = 0;
1252
1253 sx = DRAGINTER->sizex;
1254 sy = DRAGINTER->sizey;
1255
1256 // Check for backpack Icon
1257 if (MouseInRect((float)DANAESIZX - 35, (float)DANAESIZY - 113, (float)DANAESIZX - 35 + 32, (float)DANAESIZY - 113 + 32))
1258 {
1259 if (CanBePutInInventory(DRAGINTER))
1260 {
1261 if (DRAGINTER)
1262 DRAGINTER->show = SHOW_FLAG_IN_INVENTORY;
1263
1264 ARX_SOUND_PlayInterface(SND_INVSTD);
1265 Set_DragInter(NULL);
1266 }
1267
1268 return false;
1269 }
1270
1271 // First Look for Identical Item...
1272 if ((SecondaryInventory != NULL) && (InSecondaryInventoryPos(&DANAEMouse)))
1273 {
1274 Entity * io = (Entity *)SecondaryInventory->io;
1275
1276 float fcos = ARX_INTERACTIVE_GetPrice(DRAGINTER, io) / 3.0f; //>>1;
1277 long cos = checked_range_cast<long>(fcos);
1278 cos *= DRAGINTER->_itemdata->count;
1279 fcos = cos + cos * ((float)player.Full_Skill_Intuition) * 0.005f;
1280 cos = checked_range_cast<long>(fcos);
1281
1282
1283 if (io->ioflags & IO_SHOP)
1284 {
1285 if(!io->shop_category.empty() && DRAGINTER->groups.find(io->shop_category) == DRAGINTER->groups.end())
1286 return false;
1287
1288 if (cos <= 0) return false;
1289 }
1290
1291 Entity * ioo;
1292
1293 if (io->ioflags & IO_SHOP) // SHOP
1294 {
1295
1296 // Check shop group
1297 for (j = 0; j < SecondaryInventory->sizey; j++)
1298 for (i = 0; i < SecondaryInventory->sizex; i++)
1299 {
1300 ioo = (Entity *)SecondaryInventory->slot[i][j].io;
1301
1302 if (ioo)
1303 {
1304 if (IsSameObject(DRAGINTER, ioo))
1305 {
1306 ioo->_itemdata->count += DRAGINTER->_itemdata->count;
1307 ioo->scale = 1.f;
1308
1309 DRAGINTER->destroy();
1310
1311 ARX_PLAYER_AddGold(cos);
1312 ARX_SOUND_PlayInterface(SND_GOLD);
1313 ARX_SOUND_PlayInterface(SND_INVSTD);
1314 return true;
1315 }
1316 }
1317 }
1318 }
1319
1320
1321
1322 tx = DANAEMouse.x + static_cast<short>(InventoryX) - SHORT_INTERFACE_RATIO(2);
1323 ty = DANAEMouse.y - SHORT_INTERFACE_RATIO(13);
1324 tx = tx / SHORT_INTERFACE_RATIO(32);
1325 ty = ty / SHORT_INTERFACE_RATIO(32);
1326
1327
1328 if ((tx <= SecondaryInventory->sizex - sx) && (ty <= SecondaryInventory->sizey - sy))
1329 {
1330
1331 float fcos = ARX_INTERACTIVE_GetPrice(DRAGINTER, io) / 3.0f;
1332 long cos = checked_range_cast<long>(fcos);
1333 cos *= DRAGINTER->_itemdata->count;
1334 fcos = cos + cos * ((float)player.Full_Skill_Intuition) * 0.005f;
1335 cos = checked_range_cast<long>(fcos);
1336
1337 for (j = 0; j < sy; j++)
1338 for (i = 0; i < sx; i++)
1339 {
1340 if (SecondaryInventory->slot[tx+i][ty+j].io != NULL)
1341 {
1342 long xx, yy;
1343 DRAGINTER->show = SHOW_FLAG_IN_INVENTORY;
1344
1345 //Superposition d'objets
1346 Entity * ioo = SecondaryInventory->slot[tx+i][ty+j].io;
1347
1348 if ((ioo->_itemdata->playerstacksize > 1) &&
1349 (IsSameObject(DRAGINTER, ioo)) &&
1350 (ioo->_itemdata->count < ioo->_itemdata->playerstacksize))
1351 {
1352 ioo->_itemdata->count += DRAGINTER->_itemdata->count;
1353
1354 if (ioo->_itemdata->count > ioo->_itemdata->playerstacksize)
1355 {
1356 DRAGINTER->_itemdata->count = ioo->_itemdata->count - ioo->_itemdata->playerstacksize;
1357 ioo->_itemdata->count = ioo->_itemdata->playerstacksize;
1358 }
1359 else DRAGINTER->_itemdata->count = 0;
1360 }
1361
1362 if (DRAGINTER->_itemdata->count)
1363 {
1364 if (CanBePutInSecondaryInventory(SecondaryInventory, DRAGINTER, &xx, &yy))
1365 {
1366 if (io->ioflags & IO_SHOP) // SHOP
1367 {
1368 ARX_PLAYER_AddGold(cos);
1369 ARX_SOUND_PlayInterface(SND_GOLD);
1370 }
1371 }
1372 else return false;
1373 }
1374
1375 ARX_SOUND_PlayInterface(SND_INVSTD);
1376 Set_DragInter(NULL);
1377 return true;
1378 }
1379 }
1380
1381 if(DRAGINTER->ioflags & IO_GOLD) {
1382 ARX_PLAYER_AddGold(DRAGINTER);
1383 Set_DragInter(NULL);
1384 return true;
1385 }
1386
1387 for (j = 0; j < sy; j++)
1388 for (i = 0; i < sx; i++)
1389 {
1390 SecondaryInventory->slot[tx+i][ty+j].io = DRAGINTER;
1391 SecondaryInventory->slot[tx+i][ty+j].show = 0;
1392 }
1393
1394 if (io->ioflags & IO_SHOP) // SHOP
1395 {
1396 player.gold += cos;
1397 ARX_SOUND_PlayInterface(SND_GOLD);
1398 }
1399
1400 SecondaryInventory->slot[tx][ty].show = 1;
1401 DRAGINTER->show = SHOW_FLAG_IN_INVENTORY;
1402 ARX_SOUND_PlayInterface(SND_INVSTD);
1403 Set_DragInter(NULL);
1404 return true;
1405 }
1406 }
1407
1408 if (!(player.Interface & INTER_INVENTORY) && !(player.Interface & INTER_INVENTORYALL))
1409 return false;
1410
1411 if (InventoryY != 0) return false;
1412
1413 if (!InPlayerInventoryPos(&DANAEMouse)) return false;
1414
1415 int iBag = 0;
1416
1417
1418 float fCenterX = DANAECENTERX - INTERFACE_RATIO(320) + INTERFACE_RATIO(35);
1419 float fSizY = DANAESIZY - INTERFACE_RATIO(101) + INTERFACE_RATIO_LONG(InventoryY);
1420
1421 short iPosX = checked_range_cast<short>(fCenterX);
1422 short iPosY = checked_range_cast<short>(fSizY);
1423
1424
1425 if (player.Interface & INTER_INVENTORY)
1426 {
1427
1428 tx = DANAEMouse.x - iPosX;
1429 ty = DANAEMouse.y - iPosY;
1430 tx = tx / SHORT_INTERFACE_RATIO(32);
1431 ty = ty / SHORT_INTERFACE_RATIO(32);
1432
1433
1434 if ((tx >= 0) && (tx <= 16 - sx) && (ty >= 0) && (ty <= 3 - sy))
1435 iBag = sActiveInventory;
1436 else return false;
1437 }
1438 else
1439 {
1440 bool bOk = false;
1441
1442
1443 float fBag = (player.bag - 1) * INTERFACE_RATIO(-121);
1444
1445 short iY = checked_range_cast<short>(fBag);
1446
1447
1448
1449 //We must enter the for-loop to initialyze tx/ty
1450 arx_assert(0 < player.bag);
1451
1452
1453 for (int i = 0; i < player.bag; i++)
1454 {
1455 tx = DANAEMouse.x - iPosX;
1456 ty = DANAEMouse.y - iPosY - iY;
1457
1458 if ((tx >= 0) && (ty >= 0))
1459 {
1460
1461 tx = tx / SHORT_INTERFACE_RATIO(32);
1462 ty = ty / SHORT_INTERFACE_RATIO(32);
1463
1464 if ((tx >= 0) && (tx <= 16 - sx) && (ty >= 0) && (ty <= 3 - sy))
1465 {
1466 bOk = true;
1467 iBag = i;
1468 break;
1469 }
1470 }
1471
1472
1473 float fRatio = INTERFACE_RATIO(121);
1474
1475 iY += checked_range_cast<short>(fRatio);
1476
1477 }
1478
1479 if (!bOk)
1480 return false;
1481 }
1482
1483 if(DRAGINTER->ioflags & IO_GOLD) {
1484 ARX_PLAYER_AddGold(DRAGINTER);
1485 Set_DragInter(NULL);
1486 return true;
1487 }
1488
1489 for (j = 0; j < sy; j++)
1490 for (i = 0; i < sx; i++)
1491 {
1492 Entity * ioo = inventory[iBag][tx+i][ty+j].io;
1493
1494 if (ioo != NULL)
1495 {
1496 ARX_INVENTORY_IdentifyIO(ioo);
1497
1498 if ((ioo->_itemdata->playerstacksize > 1) &&
1499 (IsSameObject(DRAGINTER, ioo)) &&
1500 (ioo->_itemdata->count < ioo->_itemdata->playerstacksize))
1501 {
1502 ioo->_itemdata->count += DRAGINTER->_itemdata->count;
1503
1504 if (ioo->_itemdata->count > ioo->_itemdata->playerstacksize)
1505 {
1506 DRAGINTER->_itemdata->count = ioo->_itemdata->count - ioo->_itemdata->playerstacksize;
1507 ioo->_itemdata->count = ioo->_itemdata->playerstacksize;
1508 }
1509 else DRAGINTER->_itemdata->count = 0;
1510
1511 ioo->scale = 1.f;
1512 ARX_INVENTORY_Declare_InventoryIn(DRAGINTER);
1513
1514 if(!DRAGINTER->_itemdata->count) {
1515 DRAGINTER->destroy();
1516 }
1517
1518 ARX_SOUND_PlayInterface(SND_INVSTD);
1519 return true;
1520 }
1521
1522 return false;
1523 }
1524 }
1525
1526 for (j = 0; j < sy; j++)
1527 for (i = 0; i < sx; i++)
1528 {
1529 inventory[iBag][tx+i][ty+j].io = DRAGINTER;
1530 inventory[iBag][tx+i][ty+j].show = 0;
1531 }
1532
1533 inventory[iBag][tx][ty].show = 1;
1534
1535 ARX_INVENTORY_Declare_InventoryIn(DRAGINTER);
1536 ARX_SOUND_PlayInterface(SND_INVSTD);
1537 DRAGINTER->show = SHOW_FLAG_IN_INVENTORY;
1538 Set_DragInter(NULL);
1539 return true;
1540 }
1541 //*************************************************************************************
1542 // bool InSecondaryInventoryPos(EERIE_S2D * pos)
1543 //-------------------------------------------------------------------------------------
1544 // FUNCTION/RESULT:
1545 // Returns true if xx,yy is a position in secondary inventory
1546 //*************************************************************************************
InSecondaryInventoryPos(Vec2s * pos)1547 bool InSecondaryInventoryPos(Vec2s * pos)
1548 {
1549 if (SecondaryInventory != NULL)
1550 {
1551 short tx, ty;
1552
1553 tx = pos->x + checked_range_cast<short>(InventoryX) - SHORT_INTERFACE_RATIO(2);
1554 ty = pos->y - SHORT_INTERFACE_RATIO(13);
1555 tx = tx / SHORT_INTERFACE_RATIO(32);
1556 ty = ty / SHORT_INTERFACE_RATIO(32);
1557
1558
1559 if ((tx < 0) || (tx >= SecondaryInventory->sizex)) return false;
1560
1561 if ((ty < 0) || (ty >= SecondaryInventory->sizey)) return false;
1562
1563 return true;
1564 }
1565
1566 return false;
1567 }
1568
1569 //*************************************************************************************
1570 // bool InPlayerInventoryPos(EERIE_S2D * pos)
1571 //-------------------------------------------------------------------------------------
1572 // FUNCTION/RESULT:
1573 // Returns true if xx,yy is a position in player inventory
1574 //*************************************************************************************
InPlayerInventoryPos(Vec2s * pos)1575 bool InPlayerInventoryPos(Vec2s * pos)
1576 {
1577 if (PLAYER_INTERFACE_HIDE_COUNT) return false;
1578
1579
1580 float fCenterX = DANAECENTERX - INTERFACE_RATIO(320) + INTERFACE_RATIO(35);
1581 float fSizY = DANAESIZY - INTERFACE_RATIO(101) + INTERFACE_RATIO_LONG(InventoryY);
1582
1583 short iPosX = checked_range_cast<short>(fCenterX);
1584 short iPosY = checked_range_cast<short>(fSizY);
1585
1586 short tx, ty;
1587
1588 if (player.Interface & INTER_INVENTORY)
1589 {
1590 tx = pos->x - iPosX;
1591 ty = pos->y - iPosY;//-2;
1592
1593 if ((tx >= 0) && (ty >= 0))
1594 {
1595 tx = tx / SHORT_INTERFACE_RATIO(32);
1596 ty = ty / SHORT_INTERFACE_RATIO(32);
1597
1598 if ((tx >= 0) && ((size_t)tx <= INVENTORY_X) && (ty >= 0) && ((size_t)ty < INVENTORY_Y))
1599 return true;
1600 else
1601 return false;
1602 }
1603 }
1604
1605 else if (player.Interface & INTER_INVENTORYALL)
1606 {
1607 float fBag = (player.bag - 1) * INTERFACE_RATIO(-121);
1608
1609 short iY = checked_range_cast<short>(fBag);
1610
1611 if ((
1612 (pos->x >= iPosX) &&
1613 (pos->x <= iPosX + INVENTORY_X * INTERFACE_RATIO(32)) &&
1614 (pos->y >= iPosY + iY) &&
1615 (pos->y <= DANAESIZY)))
1616 return true;
1617
1618 for (int i = 0; i < player.bag; i++)
1619 {
1620 tx = pos->x - iPosX;
1621 ty = pos->y - iPosY - iY;
1622
1623 if ((tx >= 0) && (ty >= 0))
1624 {
1625 tx = tx / SHORT_INTERFACE_RATIO(32);
1626 ty = ty / SHORT_INTERFACE_RATIO(32);
1627
1628 if ((tx >= 0) && ((size_t)tx <= INVENTORY_X) && (ty >= 0) && ((size_t)ty < INVENTORY_Y))
1629 return true;
1630 }
1631
1632 float fRatio = INTERFACE_RATIO(121);
1633
1634 iY = checked_range_cast<short>(iY + fRatio);
1635 }
1636 }
1637
1638 return false;
1639 }
1640 //*************************************************************************************
1641 // bool InInventoryPos(EERIE_S2D * pos)
1642 //-------------------------------------------------------------------------------------
1643 // FUNCTION/RESULT:
1644 // Returns true if "pos" is a position in player inventory or in SECONDARY inventory
1645 //*************************************************************************************
InInventoryPos(Vec2s * pos)1646 bool InInventoryPos(Vec2s * pos)
1647 {
1648 if (InSecondaryInventoryPos(pos))
1649 return true;
1650
1651 return (InPlayerInventoryPos(pos));
1652 }
1653
1654 //*************************************************************************************
1655 // bool IsFlyingOverInventory(EERIE_S2D * pos)
1656 //-------------------------------------------------------------------------------------
1657 // FUNCTION/RESULT:
1658 // returns true if cursor is flying over any inventory
1659 //*************************************************************************************
IsFlyingOverInventory(Vec2s * pos)1660 bool IsFlyingOverInventory(Vec2s * pos)
1661 {
1662 // if(eMouseState==MOUSE_IN_WORLD) return false;
1663
1664 if (SecondaryInventory != NULL)
1665 {
1666
1667 short tx = pos->x + checked_range_cast<short>(InventoryX) - SHORT_INTERFACE_RATIO(2);
1668 short ty = pos->y - SHORT_INTERFACE_RATIO(13);
1669 tx /= SHORT_INTERFACE_RATIO(32);
1670 ty /= SHORT_INTERFACE_RATIO(32);
1671
1672
1673 if ((tx >= 0) && (tx <= SecondaryInventory->sizex) && (ty >= 0) && (ty <= SecondaryInventory->sizey))
1674 return true;
1675 }
1676
1677 return InPlayerInventoryPos(pos);
1678 }
1679
1680 //*************************************************************************************
1681 // Entity * GetFromInventory(EERIE_S2D * pos)
1682 //-------------------------------------------------------------------------------------
1683 // FUNCTION/RESULT:
1684 // Returns IO under position xx,yy in any INVENTORY or NULL if no IO
1685 // was found
1686 //*************************************************************************************
GetFromInventory(Vec2s * pos)1687 Entity * GetFromInventory(Vec2s * pos)
1688 {
1689 HERO_OR_SECONDARY = 0;
1690
1691 if (!IsFlyingOverInventory(pos))
1692 return NULL;
1693
1694 if (SecondaryInventory != NULL)
1695 {
1696 short tx = pos->x + checked_range_cast<short>(InventoryX) - SHORT_INTERFACE_RATIO(2);
1697 short ty = pos->y - SHORT_INTERFACE_RATIO(13);
1698
1699 if ((tx >= 0) && (ty >= 0))
1700 {
1701 tx = tx / SHORT_INTERFACE_RATIO(32);
1702 ty = ty / SHORT_INTERFACE_RATIO(32);
1703
1704 if ((tx >= 0) && (tx <= SecondaryInventory->sizex)
1705 && (ty >= 0) && (ty <= SecondaryInventory->sizey))
1706 {
1707 if (SecondaryInventory->slot[tx][ty].io == NULL)
1708 return NULL;
1709
1710 if (((player.Interface & INTER_STEAL) && (!ARX_PLAYER_CanStealItem(SecondaryInventory->slot[tx][ty].io))))
1711 return NULL;
1712
1713 Entity * io = SecondaryInventory->slot[tx][ty].io;
1714
1715 if (!(io->gameFlags & GFLAG_INTERACTIVITY))
1716 return NULL;
1717
1718 HERO_OR_SECONDARY = 2;
1719 return io;
1720 }
1721 }
1722 }
1723
1724 return GetInventoryObj(pos);
1725 }
1726
1727 //*************************************************************************************
1728 // bool GetItemWorldPosition( Entity * io,EERIE_3D * pos)
1729 //-------------------------------------------------------------------------------------
1730 // FUNCTION:
1731 // Gets real world position for an IO (can be used for non items)
1732 // (even in an inventory or being dragged)
1733 // RESULT:
1734 // Put the position in "pos". returns true if position was found
1735 // or false if object is invalid, or position not defined.
1736 //*************************************************************************************
GetItemWorldPosition(Entity * io,Vec3f * pos)1737 bool GetItemWorldPosition(Entity * io, Vec3f * pos)
1738 {
1739 // Valid IO ?
1740 if (!io) return false;
1741
1742 // Is this object being Dragged by player ?
1743 if (DRAGINTER == io)
1744 {
1745 // Set position to approximate center of player.
1746 pos->x = player.pos.x;
1747 pos->y = player.pos.y + 80.f;
1748 pos->z = player.pos.z;
1749 return true;
1750 }
1751
1752 // Not in scene ?
1753 if (io->show != SHOW_FLAG_IN_SCENE)
1754 {
1755 // Is it equiped ?
1756 if (IsEquipedByPlayer(io))
1757 {
1758 // in player inventory
1759 pos->x = player.pos.x;
1760 pos->y = player.pos.y + 80.f;
1761 pos->z = player.pos.z;
1762 return true;
1763 }
1764
1765 // Is it in any player inventory ?
1766 for(long iNbBag = 0; iNbBag < player.bag; iNbBag++) {
1767 for(size_t j = 0; j < INVENTORY_Y; j++) {
1768 for(size_t i = 0; i < INVENTORY_X; i++) {
1769 if(inventory[iNbBag][i][j].io == io) {
1770 pos->x = player.pos.x;
1771 pos->y = player.pos.y + 80.f;
1772 pos->z = player.pos.z;
1773 return true;
1774 }
1775 }
1776 }
1777 }
1778
1779 // Is it in any other IO inventory ?
1780 for(size_t i = 0; i < entities.size(); i++) {
1781 Entity * ioo = entities[i];
1782 if(ioo && ioo->inventory) {
1783 INVENTORY_DATA * id = ioo->inventory;
1784 for(long j = 0; j < id->sizey; j++) {
1785 for(long k = 0; k < id->sizex; k++) {
1786 if(id->slot[k][j].io == io) {
1787 *pos = ioo->pos;
1788 return true;
1789 }
1790 }
1791 }
1792 }
1793 }
1794 }
1795
1796 // Default position.
1797 *pos = io->pos;
1798 return true;
1799 }
1800
1801 //*************************************************************************************
1802 // bool GetItemWorldPositionSound( Entity * io,EERIE_3D * pos)
1803 //-------------------------------------------------------------------------------------
1804 // FUNCTION:
1805 // Gets real world position for an IO to spawn a sound
1806 //*************************************************************************************
GetItemWorldPositionSound(const Entity * io,Vec3f * pos)1807 bool GetItemWorldPositionSound(const Entity * io, Vec3f * pos) {
1808
1809 if(!io) {
1810 return false;
1811 }
1812
1813 if (DRAGINTER == io) {
1814 ARX_PLAYER_FrontPos(pos);
1815 return true;
1816 }
1817
1818 if(io->show != SHOW_FLAG_IN_SCENE) {
1819
1820 if(IsEquipedByPlayer(io)) {
1821 // in player inventory
1822 ARX_PLAYER_FrontPos(pos);
1823 return true;
1824 }
1825
1826 if(player.bag) {
1827 for(int iNbBag = 0; iNbBag < player.bag; iNbBag++) {
1828 for(size_t j = 0; j < INVENTORY_Y; j++) {
1829 for(size_t i = 0; i < INVENTORY_X; i++) {
1830 if(inventory[iNbBag][i][j].io == io) {
1831 // in player inventory
1832 ARX_PLAYER_FrontPos(pos);
1833 return true;
1834 }
1835 }
1836 }
1837 }
1838 }
1839
1840 for(size_t i = 0; i < entities.size(); i++) {
1841 Entity * ioo = entities[i];
1842 if(ioo && ioo->inventory) {
1843 INVENTORY_DATA * id = ioo->inventory;
1844 for(long j = 0; j < id->sizey; j++) {
1845 for(long k = 0; k < id->sizex; k++) {
1846 if(id->slot[k][j].io == io) {
1847 *pos = ioo->pos;
1848 return true;
1849 }
1850 }
1851 }
1852 }
1853 }
1854 }
1855
1856 *pos = io->pos;
1857 return true;
1858 }
1859
1860 //*************************************************************************************
1861 // void RemoveFromAllInventories(Entity * io)
1862 //-------------------------------------------------------------------------------------
1863 // FUNCTION:
1864 // Seeks an IO in all Inventories to remove it
1865 //*************************************************************************************
RemoveFromAllInventories(const Entity * io)1866 void RemoveFromAllInventories(const Entity * io) {
1867
1868 if(!io) {
1869 return;
1870 }
1871
1872 // Seek IO in Player Inventory/ies
1873 playerInventory.remove(io);
1874
1875 // Seek IO in Other IO's Inventories
1876 for(size_t i = 0; i < entities.size(); i++) {
1877 if(entities[i] != NULL) {
1878 if(entities[i]->inventory != NULL) {
1879 INVENTORY_DATA * id = entities[i]->inventory;
1880 for(long j = 0; j < id->sizey; j++) {
1881 for(long k = 0; k < id->sizex; k++) {
1882 if(id->slot[k][j].io == io) {
1883 id->slot[k][j].io = NULL;
1884 id->slot[k][j].show = 1;
1885 }
1886 }
1887 }
1888 }
1889 }
1890 }
1891 }
1892
1893 //*************************************************************************************
1894 // Seeks an IO in all Inventories to replace it by another IO
1895 //*************************************************************************************
CheckForInventoryReplaceMe(Entity * io,Entity * old)1896 void CheckForInventoryReplaceMe(Entity * io, Entity * old) {
1897
1898 for(size_t i = 0; i < entities.size(); i++) {
1899 if(entities[i] != NULL) {
1900 if(entities[i]->inventory != NULL) {
1901 INVENTORY_DATA * id = entities[i]->inventory;
1902
1903 for(long j = 0; j < id->sizey; j++) {
1904 for(long k = 0; k < id->sizex; k++) {
1905 if (id->slot[k][j].io == old) {
1906 long xx, yy;
1907 if(CanBePutInSecondaryInventory(id, io, &xx, &yy)) {
1908 return;
1909 }
1910 PutInFrontOfPlayer(io);
1911 return;
1912 }
1913 }
1914 }
1915 }
1916 }
1917 }
1918 }
1919
1920 //*************************************************************************************
1921 // Takes an object from an inventory (be it player's or secondary inventory)
1922 // at screen position "xx,yy"
1923 // Puts that object in player's "hand" (cursor)
1924 // returns true if an object was taken false elseway
1925 //*************************************************************************************
TakeFromInventory(Vec2s * pos)1926 bool TakeFromInventory(Vec2s * pos)
1927 {
1928 long i, j;
1929 Entity * io = GetFromInventory(pos);
1930 Entity * ioo;
1931
1932 if (io == NULL) return false;
1933
1934 if (SecondaryInventory != NULL)
1935 {
1936 if (InSecondaryInventoryPos(pos))
1937 {
1938 ioo = (Entity *)SecondaryInventory->io;
1939
1940 if (ioo->ioflags & IO_SHOP) // SHOP !
1941 {
1942 {
1943 if (io->ioflags & IO_ITEM) // Just in case...
1944 {
1945 long cos = ARX_INTERACTIVE_GetPrice(io, ioo);
1946
1947 float fcos = cos - cos * ((float)player.Full_Skill_Intuition) * 0.005f;
1948 cos = checked_range_cast<long>(fcos);
1949
1950 if (player.gold < cos)
1951 {
1952 return false;
1953 }
1954
1955 ARX_SOUND_PlayInterface(SND_GOLD);
1956 player.gold -= cos;
1957
1958 if(io->_itemdata->count > 1) {
1959 ioo = CloneIOItem(io);
1960 ioo->show = SHOW_FLAG_NOT_DRAWN;
1961 ioo->scriptload = 1;
1962 ioo->_itemdata->count = 1;
1963 io->_itemdata->count--;
1964 ARX_SOUND_PlayInterface(SND_INVSTD);
1965 Set_DragInter(ioo);
1966 return true;
1967 }
1968 }
1969 }
1970 }
1971 else if ((io->ioflags & IO_ITEM) && io->_itemdata->count > 1) {
1972
1973 if(!GInput->actionPressed(CONTROLS_CUST_STEALTHMODE)) {
1974 ioo = CloneIOItem(io);
1975 ioo->show = SHOW_FLAG_NOT_DRAWN;
1976 ioo->scriptload = 1;
1977 ioo->_itemdata->count = 1;
1978 io->_itemdata->count--;
1979 ARX_SOUND_PlayInterface(SND_INVSTD);
1980 Set_DragInter(ioo);
1981 sInventory = 2;
1982
1983
1984 float fCalcX = (pos->x + InventoryX - INTERFACE_RATIO(2)) / INTERFACE_RATIO(32);
1985 float fCalcY = (pos->y - INTERFACE_RATIO(13)) / INTERFACE_RATIO(32);
1986
1987 sInventoryX = checked_range_cast<short>(fCalcX);
1988 sInventoryY = checked_range_cast<short>(fCalcY);
1989
1990 //ARX_INVENTORY_Object_Out(SecondaryInventory->io, ioo);
1991
1992 ARX_INVENTORY_IdentifyIO(ioo);
1993 return true;
1994 }
1995 }
1996
1997 }
1998
1999 for (j = 0; j < SecondaryInventory->sizey; j++)
2000 for (i = 0; i < SecondaryInventory->sizex; i++)
2001 {
2002 if (SecondaryInventory->slot[i][j].io == io)
2003 {
2004 SecondaryInventory->slot[i][j].io = NULL;
2005 SecondaryInventory->slot[i][j].show = 1;
2006 sInventory = 2;
2007
2008 float fCalcX = (pos->x + InventoryX - INTERFACE_RATIO(2)) / INTERFACE_RATIO(32);
2009 float fCalcY = (pos->y - INTERFACE_RATIO(13)) / INTERFACE_RATIO(32);
2010
2011 sInventoryX = checked_range_cast<short>(fCalcX);
2012 sInventoryY = checked_range_cast<short>(fCalcY);
2013
2014 }
2015 }
2016 }
2017
2018
2019 float fCenterX = DANAECENTERX - INTERFACE_RATIO(320) + INTERFACE_RATIO(35);
2020 float fSizY = DANAESIZY - INTERFACE_RATIO(101) + INTERFACE_RATIO_LONG(InventoryY);
2021
2022 int iPosX = checked_range_cast<int>(fCenterX);
2023 int iPosY = checked_range_cast<int>(fSizY);
2024
2025 if(InPlayerInventoryPos(pos)) {
2026 if(!GInput->actionPressed(CONTROLS_CUST_STEALTHMODE)) {
2027 if((io->ioflags & IO_ITEM) && io->_itemdata->count > 1) {
2028 if(io->_itemdata->count - 1 > 0) {
2029
2030 ioo = AddItem(io->classPath());
2031 ioo->show = SHOW_FLAG_NOT_DRAWN;
2032 ioo->_itemdata->count = 1;
2033 io->_itemdata->count--;
2034 ioo->scriptload = 1;
2035 ARX_SOUND_PlayInterface(SND_INVSTD);
2036 Set_DragInter(ioo);
2037 RemoveFromAllInventories(ioo);
2038 sInventory = 1;
2039
2040 float fX = (pos->x - iPosX) / INTERFACE_RATIO(32);
2041 float fY = (pos->y - iPosY) / INTERFACE_RATIO(32);
2042
2043 sInventoryX = checked_range_cast<short>(fX);
2044 sInventoryY = checked_range_cast<short>(fY);
2045
2046 SendInitScriptEvent(ioo);
2047 ARX_INVENTORY_IdentifyIO(ioo);
2048 return true;
2049 }
2050 }
2051 }
2052 }
2053
2054 if(player.bag) {
2055 for(int iNbBag = 0; iNbBag < player.bag; iNbBag++) {
2056 for(size_t j = 0; j < INVENTORY_Y; j++) {
2057 for(size_t i = 0; i < INVENTORY_X; i++) {
2058 if (inventory[iNbBag][i][j].io == io) {
2059
2060 inventory[iNbBag][i][j].io = NULL;
2061 inventory[iNbBag][i][j].show = 1;
2062 sInventory = 1;
2063
2064 float fX = (pos->x - iPosX) / INTERFACE_RATIO(32);
2065 float fY = (pos->y - iPosY) / INTERFACE_RATIO(32);
2066
2067 sInventoryX = checked_range_cast<short>(fX);
2068 sInventoryY = checked_range_cast<short>(fY);
2069 }
2070 }
2071 }
2072 }
2073 }
2074
2075 Set_DragInter(io);
2076
2077 RemoveFromAllInventories(io);
2078 ARX_INVENTORY_IdentifyIO(io);
2079 return true;
2080 }
2081
IsInPlayerInventory(Entity * io)2082 bool IsInPlayerInventory(Entity * io) {
2083
2084 for(long iNbBag = 0; iNbBag < player.bag; iNbBag ++) {
2085 for(size_t j = 0; j < INVENTORY_Y; j++) {
2086 for(size_t i = 0; i < INVENTORY_X; i++) {
2087 if(inventory[iNbBag][i][j].io == io) {
2088 return true;
2089 }
2090 }
2091 }
2092 }
2093
2094 return false;
2095 }
2096
IsInSecondaryInventory(Entity * io)2097 bool IsInSecondaryInventory(Entity * io) {
2098
2099 if(SecondaryInventory) {
2100 for(long j = 0; j < SecondaryInventory->sizey; j++) {
2101 for(long i = 0; i < SecondaryInventory->sizex; i++) {
2102 if(SecondaryInventory->slot[i][j].io == io) {
2103 return true;
2104 }
2105 }
2106 }
2107 }
2108
2109 return false;
2110 }
2111
SendInventoryObjectCommand(const string & _lpszText,ScriptMessage _lCommand)2112 void SendInventoryObjectCommand(const string & _lpszText, ScriptMessage _lCommand) {
2113
2114 if(player.bag) {
2115 for(int iNbBag = 0; iNbBag < player.bag; iNbBag++) {
2116 for(size_t j = 0; j < INVENTORY_Y; j++) {
2117 for(size_t i = 0; i < INVENTORY_X; i++) {
2118
2119 if(inventory[iNbBag][i][j].io && inventory[iNbBag][i][j].io->obj) {
2120 Entity * item = inventory[iNbBag][i][j].io;
2121 for(size_t lTex = 0; lTex < item->obj->texturecontainer.size(); lTex++) {
2122 if(!item->obj->texturecontainer.empty()) {
2123 if(item->obj->texturecontainer[lTex]) {
2124 if(item->obj->texturecontainer[lTex]->m_texName == _lpszText) {
2125 if(item->gameFlags & GFLAG_INTERACTIVITY) {
2126 SendIOScriptEvent(item, _lCommand);
2127 }
2128 return;
2129 }
2130 }
2131 }
2132 }
2133 }
2134 }
2135 }
2136 }
2137 }
2138 }
2139
ARX_INVENTORY_GetTorchLowestDurability()2140 Entity * ARX_INVENTORY_GetTorchLowestDurability() {
2141
2142 Entity * io = NULL;
2143
2144 if(player.bag) {
2145 for(int iNbBag = 0; iNbBag < player.bag; iNbBag++) {
2146 for(size_t j = 0; j < INVENTORY_Y; j++) {
2147 for(size_t i = 0; i < INVENTORY_X; i++) {
2148 if(inventory[iNbBag][i][j].io) {
2149 if(inventory[iNbBag][i][j].io->locname == "description_torch") {
2150 if(!io) {
2151 io = inventory[iNbBag][i][j].io;
2152 } else {
2153 if(inventory[iNbBag][i][j].io->durability < io->durability) {
2154 io = inventory[iNbBag][i][j].io;
2155 }
2156 }
2157 }
2158 }
2159 }
2160 }
2161 }
2162 }
2163
2164 return io;
2165 }
2166
ARX_INVENTORY_IdentifyIO(Entity * _pIO)2167 void ARX_INVENTORY_IdentifyIO(Entity * _pIO) {
2168 if(_pIO && (_pIO->ioflags & IO_ITEM) && _pIO->_itemdata->equipitem) {
2169 if(player.Full_Skill_Object_Knowledge + player.Full_Attribute_Mind
2170 >= _pIO->_itemdata->equipitem->elements[IO_EQUIPITEM_ELEMENT_Identify_Value].value) {
2171 SendIOScriptEvent(_pIO, SM_IDENTIFY);
2172 }
2173 }
2174 }
2175
ARX_INVENTORY_IdentifyAll()2176 void ARX_INVENTORY_IdentifyAll() {
2177
2178 if(player.bag) {
2179 for(int iNbBag = 0; iNbBag < player.bag; iNbBag++) {
2180 for(size_t j = 0; j < INVENTORY_Y; j++) {
2181 for(size_t i = 0; i < INVENTORY_X; i++) {
2182 Entity * io = inventory[iNbBag][i][j].io;
2183 if(io && (io->ioflags & IO_ITEM) && io->_itemdata->equipitem) {
2184 if(player.Full_Skill_Object_Knowledge + player.Full_Attribute_Mind
2185 >= io->_itemdata->equipitem->elements[IO_EQUIPITEM_ELEMENT_Identify_Value].value) {
2186 SendIOScriptEvent(io, SM_IDENTIFY);
2187 }
2188 }
2189 }
2190 }
2191 }
2192 }
2193 }
2194
2195 extern bool bInventoryClosing;
2196
2197 //-----------------------------------------------------------------------------
ARX_INVENTORY_OpenClose(Entity * _io)2198 void ARX_INVENTORY_OpenClose(Entity * _io)
2199 {
2200 if ((_io && (SecondaryInventory == _io->inventory)) || (_io == NULL)) // CLOSING
2201 {
2202 if (SecondaryInventory && (SecondaryInventory->io != NULL))
2203 SendIOScriptEvent(SecondaryInventory->io, SM_INVENTORY2_CLOSE);
2204
2205 InventoryDir = -1;
2206 TSecondaryInventory = SecondaryInventory;
2207 SecondaryInventory = NULL;
2208 EERIEMouseButton &= ~4;
2209
2210 if (DRAGGING) DRAGGING = 0;
2211 }
2212 else
2213 {
2214 if (TSecondaryInventory
2215 && TSecondaryInventory->io) SendIOScriptEvent(TSecondaryInventory->io, SM_INVENTORY2_CLOSE);
2216
2217 InventoryDir = 1;
2218 TSecondaryInventory = SecondaryInventory = _io->inventory;
2219
2220 if (SecondaryInventory && SecondaryInventory->io != NULL)
2221 {
2222 if (SendIOScriptEvent(SecondaryInventory->io, SM_INVENTORY2_OPEN) == REFUSE)
2223 {
2224 InventoryDir = -1;
2225 TSecondaryInventory = SecondaryInventory = NULL;
2226 return;
2227 }
2228 }
2229
2230 if (player.Interface & INTER_COMBATMODE)
2231 {
2232 ARX_INTERFACE_Combat_Mode(0);
2233 }
2234
2235 if(!config.input.autoReadyWeapon) {
2236 TRUE_PLAYER_MOUSELOOK_ON = false;
2237 }
2238
2239 if (SecondaryInventory && SecondaryInventory->io
2240 && (SecondaryInventory->io->ioflags & IO_SHOP))
2241 ARX_INVENTORY_ReOrder();
2242
2243 EERIEMouseButton &= ~4;
2244
2245 if (DRAGGING) DRAGGING = 0;
2246 }
2247
2248 if (player.Interface & INTER_INVENTORYALL)
2249 {
2250 ARX_SOUND_PlayInterface(SND_BACKPACK, 0.9F + 0.2F * rnd());
2251 bInventoryClosing = true;
2252 }
2253 }
2254
2255 //-----------------------------------------------------------------------------
ARX_INVENTORY_TakeAllFromSecondaryInventory()2256 void ARX_INVENTORY_TakeAllFromSecondaryInventory()
2257 {
2258 bool bSound = false;
2259
2260 if (TSecondaryInventory)
2261 {
2262
2263 (void)checked_range_cast<short>(TSecondaryInventory->sizey);
2264 (void)checked_range_cast<short>(TSecondaryInventory->sizex);
2265
2266
2267 for (long j = 0; j < TSecondaryInventory->sizey; j++)
2268 for (long i = 0; i < TSecondaryInventory->sizex; i++)
2269 {
2270 if (TSecondaryInventory->slot[i][j].io && TSecondaryInventory->slot[i][j].show)
2271 {
2272 long sx = TSecondaryInventory->slot[i][j].io->sizex;
2273 long sy = TSecondaryInventory->slot[i][j].io->sizey;
2274 Entity * io = TSecondaryInventory->slot[i][j].io;
2275
2276 if (!(io->ioflags & IO_GOLD))
2277 RemoveFromAllInventories(io);
2278
2279 if(playerInventory.insert(io)) {
2280 bSound = true;
2281 } else {
2282 sInventory = 2;
2283
2284 sInventoryX = static_cast<short>(i);
2285 sInventoryY = static_cast<short>(j);
2286
2287 sx = i;
2288 sy = j;
2289 CanBePutInSecondaryInventory(TSecondaryInventory, io, &sx, &sy);
2290 }
2291 }
2292 }
2293 }
2294
2295 if (bSound)
2296 ARX_SOUND_PlayInterface(SND_INVSTD);
2297 else
2298 ARX_SOUND_PlayInterface(SND_INVSTD, 0.1f);
2299 }
2300
2301 //-----------------------------------------------------------------------------
ARX_INVENTORY_ReOrder()2302 void ARX_INVENTORY_ReOrder()
2303 {
2304 if (TSecondaryInventory)
2305 {
2306
2307 (void)checked_range_cast<short>(TSecondaryInventory->sizey);
2308 (void)checked_range_cast<short>(TSecondaryInventory->sizex);
2309
2310
2311 for (long j = 0; j < TSecondaryInventory->sizey; j++)
2312 for (long i = 0; i < TSecondaryInventory->sizex; i++)
2313 {
2314 if (TSecondaryInventory->slot[i][j].io && TSecondaryInventory->slot[i][j].show)
2315 {
2316 long sx = TSecondaryInventory->slot[i][j].io->sizex;
2317 long sy = TSecondaryInventory->slot[i][j].io->sizey;
2318 Entity * io = TSecondaryInventory->slot[i][j].io;
2319
2320 RemoveFromAllInventories(io);
2321 long x, y;
2322 sInventory = 2;
2323 sInventoryX = 0;
2324 sInventoryY = 0;
2325
2326 if (CanBePutInSecondaryInventory(TSecondaryInventory, io, &x, &y))
2327 {
2328 }
2329 else
2330 {
2331 sInventory = 2;
2332
2333 sInventoryX = static_cast<short>(i);
2334 sInventoryY = static_cast<short>(j);
2335
2336 sx = i;
2337 sy = j;
2338 CanBePutInSecondaryInventory(TSecondaryInventory, io, &sx, &sy);
2339 }
2340 }
2341 }
2342 }
2343 }
2344