Dialog: "Compile" dialog triggers on read, rather than execution.
[gemrb.git] / gemrb / plugins / STOImporter / STOImporter.cpp
blobe127f64f6882c3187fb9959992c65a417dfef1d1
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 #include "win32def.h"
22 #include "Interface.h"
23 #include "Inventory.h"
24 #include "STOImporter.h"
25 #include "GameData.h"
27 STOImporter::STOImporter(void)
29 str = NULL;
30 autoFree = false;
33 STOImporter::~STOImporter(void)
35 if (str && autoFree) {
36 delete( str );
40 bool STOImporter::Open(DataStream* stream, bool autoFree)
42 if (stream == NULL) {
43 return false;
45 if (str && this->autoFree) {
46 delete( str );
48 str = stream;
49 this->autoFree = autoFree;
50 char Signature[8];
51 str->Read( Signature, 8 );
52 if (strncmp( Signature, "STORV1.0", 8 ) == 0) {
53 version = 10;
54 } else if (strncmp( Signature, "STORV1.1", 8 ) == 0) {
55 version = 11;
56 } else if (strncmp( Signature, "STORV9.0", 8 ) == 0) {
57 version = 90;
58 } else if (strncmp( Signature, "STORV0.0", 8 ) == 0) {
59 //GemRB's internal version with all known fields supported
60 version = 0;
61 } else {
62 printf( "[STOImporter]: This file is not a valid STO File\n" );
63 return false;
66 return true;
69 Store* STOImporter::GetStore(Store *s)
71 unsigned int i;
73 if (!s)
74 return NULL;
76 // saving in original version requires the original version
77 // otherwise it is set to 0 at construction time
78 if (core->SaveAsOriginal) {
79 s->version = version;
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
110 ieDword tmp;
112 str->ReadDword( &tmp );
113 s->Capacity = (ieWord) tmp;
114 str->Read( s->unknown3, 80 );
115 } else {
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
121 //may fix it.
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];
130 GetItem(item);
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
135 s->HasTriggers=true;
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++) {
146 GetCure(s->cures+i);
149 return s;
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;
166 //another hack-fix
167 Item *item = gamedata->GetItem( it->ItemResRef );
168 if (item) {
169 if (!item->LoreToID) {
170 it->Flags |= IE_INV_ITEM_IDENTIFIED;
172 gamedata->FreeItem( item, it->ItemResRef, false );
174 str->ReadDword( (ieDword *) &it->InfiniteSupply );
175 ieDwordSigned tmp;
177 switch (version) {
178 case 11: //pst
179 if (it->InfiniteSupply) {
180 it->InfiniteSupply=-1;
182 str->ReadDword( (ieDword *) &tmp );
183 if (tmp>0) {
184 it->InfiniteSupply=tmp;
186 str->Read( it->unknown2, 56 );
187 break;
188 case 0: //gemrb version stores trigger ref in infinitesupply
189 memset( it->unknown2, 0, 56 );
190 break;
191 default:
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;
225 //header
226 switch (s->version) {
227 case 90:
228 //capacity on a dword and 80 bytes of crap
229 headersize = 156 + 84;
230 itemsize = 28;
231 break;
232 case 11:
233 headersize = 156;
234 //trigger ref on a dword and 56 bytes of crap
235 itemsize = 28 + 60;
236 default:
237 headersize = 156;
238 itemsize = 28;
239 break;
242 //drinks
243 s->DrinksOffset = headersize;
244 headersize += s->DrinksCount * 20; //8+4+4+4
246 //cures
247 s->CuresOffset = headersize;
248 headersize += s->CuresCount * 12; //8+4
250 //purchased items
251 s->PurchasedCategoriesOffset = headersize;
252 headersize += s->PurchasedCategoriesCount * sizeof(ieDword);
254 //items
255 s->ItemsOffset = headersize;
256 headersize += s->ItemsCount * itemsize;
258 return headersize;
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 );
266 return 0;
269 int STOImporter::PutHeader(DataStream *stream, Store *s)
271 char Signature[8];
272 ieDword tmpDword;
273 ieWord tmpWord;
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);
288 switch (version) {
289 case 10: case 0: // bg2, gemrb
290 tmpWord = s->Capacity;
291 break;
292 default:
293 tmpWord = 0;
294 break;
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
316 if (version==90) {
317 tmpDword = s->Capacity;
318 stream->WriteDword( &tmpDword);
319 stream->Write( s->unknown3, 80); //writing out original fillers
321 return 0;
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 );
336 if (version==11) {
337 stream->WriteDword( (ieDword *) &it->InfiniteSupply);
338 stream->WriteDword( (ieDword *) &it->InfiniteSupply);
339 stream->Write( it->unknown2, 56);
340 } else {
341 stream->WriteDword( (ieDword *) &it->InfiniteSupply );
344 return 0;
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);
354 return 0;
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);
366 return 0;
369 //saves the store into a datastream, be it memory or file
370 int STOImporter::PutStore(DataStream *stream, Store *store)
372 int ret;
374 if (!stream || !store) {
375 return -1;
378 ret = PutHeader( stream, store);
379 if (ret) {
380 return ret;
383 ret = PutDrinks( stream, store);
384 if (ret) {
385 return ret;
388 ret = PutCures( stream, store);
389 if (ret) {
390 return ret;
393 ret = PutPurchasedCategories (stream, store);
394 if (ret) {
395 return ret;
398 ret = PutItems( stream, store);
400 return ret;
403 #include "plugindef.h"
405 GEMRB_PLUGIN(0x1CDFC160, "STO File Importer")
406 PLUGIN_CLASS(IE_STO_CLASS_ID, STOImporter)
407 END_PLUGIN()