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.
22 #include "Interface.h"
23 #include "Inventory.h"
24 #include "STOImporter.h"
27 STOImporter::STOImporter(void)
33 STOImporter::~STOImporter(void)
35 if (str
&& autoFree
) {
40 bool STOImporter::Open(DataStream
* stream
, bool autoFree
)
45 if (str
&& this->autoFree
) {
49 this->autoFree
= autoFree
;
51 str
->Read( Signature
, 8 );
52 if (strncmp( Signature
, "STORV1.0", 8 ) == 0) {
54 } else if (strncmp( Signature
, "STORV1.1", 8 ) == 0) {
56 } else if (strncmp( Signature
, "STORV9.0", 8 ) == 0) {
58 } else if (strncmp( Signature
, "STORV0.0", 8 ) == 0) {
59 //GemRB's internal version with all known fields supported
62 printf( "[STOImporter]: This file is not a valid STO File\n" );
69 Store
* STOImporter::GetStore(Store
*s
)
76 // saving in original version requires the original version
77 // otherwise it is set to 0 at construction time
78 if (core
->SaveAsOriginal
) {
82 str
->ReadDword( &s
->Type
);
83 str
->ReadDword( &s
->StoreName
);
84 str
->ReadDword( &s
->Flags
);
85 str
->ReadDword( &s
->SellMarkup
);
86 str
->ReadDword( &s
->BuyMarkup
);
87 str
->ReadDword( &s
->DepreciationRate
);
88 str
->ReadWord( &s
->StealFailureChance
);
89 str
->ReadWord( &s
->Capacity
); //will be overwritten for V9.0
90 str
->Read( s
->unknown
, 8 );
91 str
->ReadDword( &s
->PurchasedCategoriesOffset
);
92 str
->ReadDword( &s
->PurchasedCategoriesCount
);
93 str
->ReadDword( &s
->ItemsOffset
);
94 str
->ReadDword( &s
->ItemsCount
);
95 str
->ReadDword( &s
->Lore
);
96 str
->ReadDword( &s
->IDPrice
);
97 str
->ReadResRef( s
->RumoursTavern
);
98 str
->ReadDword( &s
->DrinksOffset
);
99 str
->ReadDword( &s
->DrinksCount
);
100 str
->ReadResRef( s
->RumoursTemple
);
101 str
->ReadDword( &s
->AvailableRooms
);
102 for (i
= 0; i
< 4; i
++) {
103 str
->ReadDword( &s
->RoomPrices
[i
] );
105 str
->ReadDword( &s
->CuresOffset
);
106 str
->ReadDword( &s
->CuresCount
);
107 str
->Read( s
->unknown2
, 36 );
109 if (version
== 90) { //iwd stores
112 str
->ReadDword( &tmp
);
113 s
->Capacity
= (ieWord
) tmp
;
114 str
->Read( s
->unknown3
, 80 );
116 memset( s
->unknown3
, 0, 80 );
119 //Allocation must be done in the same place as destruction.
120 //Yeah, this is intentionally so ugly, someone who doesn't like this
122 core
->DoTheStoreHack(s
);
124 str
->Seek( s
->PurchasedCategoriesOffset
, GEM_STREAM_START
);
125 GetPurchasedCategories( s
);
127 str
->Seek( s
->ItemsOffset
, GEM_STREAM_START
);
128 for (i
= 0; i
< s
->ItemsCount
; i
++) {
129 STOItem
*item
= s
->items
[i
];
131 //it is important to handle this field as signed
132 if (item
->InfiniteSupply
>0) {
133 //if there are no triggers, GetRealStockSize is simpler
134 //also it is compatible only with pst/gemrb saved stores
139 str
->Seek( s
->DrinksOffset
, GEM_STREAM_START
);
140 for (i
= 0; i
< s
->DrinksCount
; i
++) {
141 GetDrink(s
->drinks
+i
);
144 str
->Seek( s
->CuresOffset
, GEM_STREAM_START
);
145 for (i
= 0; i
< s
->CuresCount
; i
++) {
152 void STOImporter::GetItem(STOItem
*it
)
154 str
->ReadResRef( it
->ItemResRef
);
155 str
->ReadWord( &it
->PurchasedAmount
);
156 for (int i
=0;i
<CHARGE_COUNTERS
;i
++) {
157 str
->ReadWord( it
->Usages
+i
);
159 str
->ReadDword( &it
->Flags
);
160 str
->ReadDword( &it
->AmountInStock
);
161 //if there was no item on stock, how this could be 0
162 //we hack-fix this here so it won't cause trouble
163 if (!it
->AmountInStock
) {
164 it
->AmountInStock
= 1;
167 Item
*item
= gamedata
->GetItem( it
->ItemResRef
);
169 if (!item
->LoreToID
) {
170 it
->Flags
|= IE_INV_ITEM_IDENTIFIED
;
172 gamedata
->FreeItem( item
, it
->ItemResRef
, false );
174 str
->ReadDword( (ieDword
*) &it
->InfiniteSupply
);
179 if (it
->InfiniteSupply
) {
180 it
->InfiniteSupply
=-1;
182 str
->ReadDword( (ieDword
*) &tmp
);
184 it
->InfiniteSupply
=tmp
;
186 str
->Read( it
->unknown2
, 56 );
188 case 0: //gemrb version stores trigger ref in infinitesupply
189 memset( it
->unknown2
, 0, 56 );
192 if (it
->InfiniteSupply
) {
193 it
->InfiniteSupply
=-1;
195 memset( it
->unknown2
, 0, 56 );
199 void STOImporter::GetDrink(STODrink
*dr
)
201 str
->ReadResRef( dr
->RumourResRef
);
202 str
->ReadDword( &dr
->DrinkName
);
203 str
->ReadDword( &dr
->Price
);
204 str
->ReadDword( &dr
->Strength
);
207 void STOImporter::GetCure(STOCure
*cu
)
209 str
->ReadResRef( cu
->CureResRef
);
210 str
->ReadDword( &cu
->Price
);
213 void STOImporter::GetPurchasedCategories(Store
* s
)
215 for (unsigned int i
= 0; i
< s
->PurchasedCategoriesCount
; i
++) {
216 str
->ReadDword( &s
->purchased_categories
[i
] );
220 //call this before any write, it updates offsets!
221 int STOImporter::GetStoredFileSize(Store
*s
)
223 int headersize
, itemsize
;
226 switch (s
->version
) {
228 //capacity on a dword and 80 bytes of crap
229 headersize
= 156 + 84;
234 //trigger ref on a dword and 56 bytes of crap
243 s
->DrinksOffset
= headersize
;
244 headersize
+= s
->DrinksCount
* 20; //8+4+4+4
247 s
->CuresOffset
= headersize
;
248 headersize
+= s
->CuresCount
* 12; //8+4
251 s
->PurchasedCategoriesOffset
= headersize
;
252 headersize
+= s
->PurchasedCategoriesCount
* sizeof(ieDword
);
255 s
->ItemsOffset
= headersize
;
256 headersize
+= s
->ItemsCount
* itemsize
;
261 int STOImporter::PutPurchasedCategories(DataStream
*stream
, Store
* s
)
263 for (unsigned int i
= 0; i
< s
->PurchasedCategoriesCount
; i
++) {
264 stream
->WriteDword( s
->purchased_categories
+i
);
269 int STOImporter::PutHeader(DataStream
*stream
, Store
*s
)
275 version
= s
->version
;
276 memcpy( Signature
, "STORV0.0", 8);
277 Signature
[5]+=version
/10;
278 Signature
[7]+=version
%10;
279 stream
->Write( Signature
, 8);
280 stream
->WriteDword( &s
->Type
);
281 stream
->WriteDword( &s
->StoreName
);
282 stream
->WriteDword( &s
->Flags
);
283 stream
->WriteDword( &s
->SellMarkup
);
284 stream
->WriteDword( &s
->BuyMarkup
);
285 stream
->WriteDword( &s
->DepreciationRate
);
286 stream
->WriteWord( &s
->StealFailureChance
);
289 case 10: case 0: // bg2, gemrb
290 tmpWord
= s
->Capacity
;
296 stream
->WriteWord( &tmpWord
);
298 stream
->Write( s
->unknown
, 8);
299 stream
->WriteDword( &s
->PurchasedCategoriesOffset
);
300 stream
->WriteDword( &s
->PurchasedCategoriesCount
);
301 stream
->WriteDword( &s
->ItemsOffset
);
302 stream
->WriteDword( &s
->ItemsCount
);
303 stream
->WriteDword( &s
->Lore
);
304 stream
->WriteDword( &s
->IDPrice
);
305 stream
->WriteResRef( s
->RumoursTavern
);
306 stream
->WriteDword( &s
->DrinksOffset
);
307 stream
->WriteDword( &s
->DrinksCount
);
308 stream
->WriteResRef( s
->RumoursTemple
);
309 stream
->WriteDword( &s
->AvailableRooms
);
310 for (int i
=0;i
<4;i
++) {
311 stream
->WriteDword( s
->RoomPrices
+i
);
313 stream
->WriteDword( &s
->CuresOffset
);
314 stream
->WriteDword( &s
->CuresCount
);
315 stream
->Write (s
->unknown3
, 36); //use these as padding
317 tmpDword
= s
->Capacity
;
318 stream
->WriteDword( &tmpDword
);
319 stream
->Write( s
->unknown3
, 80); //writing out original fillers
324 int STOImporter::PutItems(DataStream
*stream
, Store
*store
)
326 for (unsigned int ic
=0;ic
<store
->ItemsCount
;ic
++) {
327 STOItem
*it
= store
->items
[ic
];
329 stream
->WriteResRef( it
->ItemResRef
);
330 stream
->WriteWord( &it
->PurchasedAmount
);
331 for (unsigned int i
=0;i
<CHARGE_COUNTERS
;i
++) {
332 stream
->WriteWord( it
->Usages
+i
);
334 stream
->WriteDword( &it
->Flags
);
335 stream
->WriteDword( &it
->AmountInStock
);
337 stream
->WriteDword( (ieDword
*) &it
->InfiniteSupply
);
338 stream
->WriteDword( (ieDword
*) &it
->InfiniteSupply
);
339 stream
->Write( it
->unknown2
, 56);
341 stream
->WriteDword( (ieDword
*) &it
->InfiniteSupply
);
347 int STOImporter::PutCures(DataStream
*stream
, Store
*s
)
349 for (unsigned int i
=0;i
<s
->CuresCount
;i
++) {
350 STOCure
*c
= s
->cures
+i
;
351 stream
->WriteResRef( c
->CureResRef
);
352 stream
->WriteDword( &c
->Price
);
357 int STOImporter::PutDrinks(DataStream
*stream
, Store
*s
)
359 for (unsigned int i
=0;i
<s
->DrinksCount
;i
++) {
360 STODrink
*d
= s
->drinks
+i
;
361 stream
->WriteResRef( d
->RumourResRef
); //?
362 stream
->WriteDword( &d
->DrinkName
);
363 stream
->WriteDword( &d
->Price
);
364 stream
->WriteDword( &d
->Strength
);
369 //saves the store into a datastream, be it memory or file
370 int STOImporter::PutStore(DataStream
*stream
, Store
*store
)
374 if (!stream
|| !store
) {
378 ret
= PutHeader( stream
, store
);
383 ret
= PutDrinks( stream
, store
);
388 ret
= PutCures( stream
, store
);
393 ret
= PutPurchasedCategories (stream
, store
);
398 ret
= PutItems( stream
, store
);
403 #include "plugindef.h"
405 GEMRB_PLUGIN(0x1CDFC160, "STO File Importer")
406 PLUGIN_CLASS(IE_STO_CLASS_ID
, STOImporter
)