melee / ranged effects
[gemrb.git] / gemrb / core / Store.cpp
blob5d60994b6f76c8650d8c57f87139c67e3d21271a
1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 //This class represents .sto (store) files of the game.
22 //Inns, pubs, temples, backpacks are also implemented by stores.
24 #include "Store.h"
26 #include "win32def.h"
28 #include "Game.h"
29 #include "GameData.h"
30 #include "Interface.h"
31 #include "Item.h"
32 #include "GameScript/GameScript.h"
34 Store::Store(void)
36 HasTriggers = false;
37 purchased_categories = NULL;
38 drinks = NULL;
39 cures = NULL;
40 version = 0;
41 StoreOwnerID = 0;
44 Store::~Store(void)
46 unsigned int i;
48 for (i = 0; i < items.size(); i++) {
49 if (items[i]->trigger)
50 items[i]->trigger->Release();
51 delete( items[i] );
53 if(drinks)
54 free(drinks);
55 if(cures)
56 free(cures);
57 if (purchased_categories)
58 free( purchased_categories );
61 bool Store::IsItemAvailable(unsigned int slot) const
63 Game * game = core->GetGame();
64 //0 - not infinite, not conditional
65 //-1 - infinite
66 //other - pst trigger ref
68 Trigger *trigger = items[slot]->trigger;
69 if (trigger) {
70 return trigger->Evaluate(game->GetPC(game->GetSelectedPCSingle(), false))!=0;
72 return true;
75 int Store::GetRealStockSize()
77 int count=ItemsCount;
78 if (!HasTriggers) {
79 return count;
81 for (unsigned int i=0;i<ItemsCount;i++) {
82 if (!IsItemAvailable(i) ) {
83 count--;
86 return count;
89 int Store::AcceptableItemType(ieDword type, ieDword invflags, bool pc) const
91 int ret;
93 //don't allow any movement of undroppable items
94 if (invflags&IE_INV_ITEM_UNDROPPABLE ) {
95 ret = 0;
96 } else {
97 ret = IE_STORE_BUY|IE_STORE_SELL|IE_STORE_STEAL;
99 if (invflags&IE_INV_ITEM_UNSTEALABLE) {
100 ret &= ~IE_STORE_STEAL;
102 if (!(invflags&IE_INV_ITEM_IDENTIFIED) ) {
103 ret |= IE_STORE_ID;
105 if (pc && (Type<STT_BG2CONT) ) {
106 //can't sell critical items
107 if (!(invflags&IE_INV_ITEM_DESTRUCTIBLE )) {
108 ret &= ~IE_STORE_SELL;
110 //don't allow selling of non destructible items
111 //don't allow selling of critical items (they could still be put in bags)
112 if ((invflags&(IE_INV_ITEM_DESTRUCTIBLE|IE_INV_ITEM_CRITICAL))!=IE_INV_ITEM_DESTRUCTIBLE) {
113 ret &= ~IE_STORE_SELL;
116 //check if store buys stolen items
117 if ((invflags&IE_INV_ITEM_STOLEN) && !(Type&IE_STORE_FENCE) ) {
118 ret &= ~IE_STORE_SELL;
122 if (!pc) {
123 return ret;
126 for (ieDword i=0;i<PurchasedCategoriesCount;i++) {
127 if (type==purchased_categories[i]) {
128 return ret;
132 //Even if the store doesn't purchase the item, it can still ID it
133 return ret & ~IE_STORE_SELL;
136 STOCure *Store::GetCure(unsigned int idx) const
138 if (idx>=CuresCount) {
139 return NULL;
141 return cures+idx;
144 STODrink *Store::GetDrink(unsigned int idx) const
146 if (idx>=DrinksCount) {
147 return NULL;
149 return drinks+idx;
152 //We need this weirdness for PST item lookup
153 STOItem *Store::GetItem(unsigned int idx)
155 if (!HasTriggers) {
156 if (idx>=items.size()) {
157 return NULL;
159 return items[idx];
162 for (unsigned int i=0;i<ItemsCount;i++) {
163 if (IsItemAvailable(i)) {
164 if (!idx) {
165 return items[i];
167 idx--;
170 return NULL;
173 unsigned int Store::FindItem(const ieResRef itemname, bool usetrigger) const
175 for (unsigned int i=0;i<ItemsCount;i++) {
176 if (usetrigger) {
177 if (!IsItemAvailable(i) ) {
178 continue;
181 STOItem *temp = items[i];
182 if (!strnicmp(itemname, temp->ItemResRef, 8) ) {
183 return i;
186 return (unsigned int) -1;
189 STOItem *Store::FindItem(CREItem *item, bool exact)
191 for (unsigned int i=0;i<ItemsCount;i++) {
192 if (!IsItemAvailable(i) ) {
193 continue;
195 STOItem *temp = items[i];
197 if (strnicmp(item->ItemResRef, temp->ItemResRef, 8) ) {
198 continue;
200 if(exact) {
201 if (temp->InfiniteSupply==-1) {
202 return temp;
204 //check if we could simply merge the item into the stock or need a new entry
205 if ((temp->StackAmount>=99) || memcmp(temp->Usages, item->Usages, sizeof(item->Usages))) {
206 continue;
209 return temp;
211 return NULL;
214 //some stores can recharge items
215 void Store::RechargeItem(CREItem *item)
217 //is there any flag which store can recharge?
218 Item *itm = gamedata->GetItem(item->ItemResRef);
219 if (!itm) {
220 return;
222 if (!itm->LoreToID) {
223 item->Flags |= IE_INV_ITEM_IDENTIFIED;
225 //gemrb extension, some shops won't recharge items
226 if (!(Flags&IE_STORE_RECHARGE)) {
227 for (int i=0;i<CHARGE_COUNTERS;i++) {
228 ITMExtHeader *h = itm->GetExtHeader(i);
229 if (!h) {
230 item->Usages[i]=0;
231 continue;
233 if (h->RechargeFlags&IE_ITEM_RECHARGE) {
234 item->Usages[i] = h->Charges;
238 gamedata->FreeItem(itm, item->ItemResRef, 0);
241 void Store::AddItem(CREItem *item)
243 RechargeItem(item);
244 STOItem *temp = FindItem(item, true);
246 if (temp) {
247 if (temp->InfiniteSupply!=-1) {
248 temp->StackAmount++;
250 return;
253 temp = new STOItem();
254 //It is important to initialize these fields, if STOItem ever changes to
255 //a real class from struct, make sure the fields are cleared
256 memset( temp, 0, sizeof (STOItem ) );
257 memcpy( temp, item, sizeof( CREItem ) );
258 items.push_back (temp );
259 ItemsCount++;
262 void Store::RemoveItem( unsigned int idx )
264 if (items.size()!=ItemsCount) {
265 printMessage("Store","Inconsistent store", LIGHT_RED);
266 abort();
268 if (ItemsCount<=idx) {
269 return;
271 items.erase(items.begin()+idx);
272 ItemsCount--;
275 ieDword Store::GetOwnerID() const
277 return StoreOwnerID;
280 void Store::SetOwnerID(ieDword owner)
282 StoreOwnerID = owner;