1 /*
2 * Seven Kingdoms: Ancient Adversaries
3 *
4 * Copyright 1997,1998 Enlight Software Ltd.
5 *
6 * This program 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 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 //Filename : OTOWNRES.CPP
22 //Description : Town resource object
23
24 #include <OSYS.h>
25 #include <OGAMESET.h>
26 #include <OWORLD.h>
27 #include <OIMGRES.h>
28 #include <ORACERES.h>
29 #include <OTOWNRES.h>
30
31 //---------- define constant ------------//
32
33 #define TOWN_LAYOUT_DB "TOWNLAY"
34 #define TOWN_SLOT_DB "TOWNSLOT"
35 #define TOWN_BUILD_TYPE_DB "TOWNBTYP"
36 #define TOWN_BUILD_DB "TOWNBULD"
37 #define TOWN_NAME_DB "TOWNNAME"
38
39 //------- Begin of function TownRes::TownRes -----------//
40
TownRes()41 TownRes::TownRes()
42 {
43 init_flag=0;
44 }
45 //--------- End of function TownRes::TownRes -----------//
46
47
48 //---------- Begin of function TownRes::init -----------//
49 //
50 // This function must be called after a map is generated.
51 //
init()52 void TownRes::init()
53 {
54 deinit();
55
56 //----- open town material bitmap resource file -------//
57
58 String str;
59
60 str = DIR_RES;
61 str += "I_TOWN.RES";
62
63 res_bitmap.init_imported(str,1); // 1-read all into buffer
64
65 //------- load database information --------//
66
67 load_town_slot(); // load_town_slot() must be called first before load_town_layout(), as load_town_layout() accesses town_slot_array
68 load_town_layout();
69 load_town_build_type();
70 load_town_build();
71 load_town_name();
72
73 init_flag=1;
74 }
75 //---------- End of function TownRes::init -----------//
76
77
78 //---------- Begin of function TownRes::deinit -----------//
79
deinit()80 void TownRes::deinit()
81 {
82 if( init_flag )
83 {
84 mem_del(town_layout_array);
85 mem_del(town_slot_array);
86 mem_del(town_build_array);
87 mem_del(town_build_type_array);
88 mem_del(town_name_array);
89 mem_del(town_name_used_array);
90
91 res_bitmap.deinit();
92
93 init_flag=0;
94 }
95 }
96 //---------- End of function TownRes::deinit -----------//
97
98
99 //------- Begin of function TownRes::load_town_layout -------//
100 //
101 // Read in information from TOWNLAY.DBF.
102 //
load_town_layout()103 void TownRes::load_town_layout()
104 {
105 TownLayoutRec *townLayoutRec;
106 TownLayout *townLayout;
107 TownSlot *townSlot;
108 int i, j;
109 Database *dbTownLayout = game_set.open_db(TOWN_LAYOUT_DB);
110
111 town_layout_count = (short) dbTownLayout->rec_count();
112 town_layout_array = (TownLayout*) mem_add( sizeof(TownLayout)*town_layout_count );
113
114 //------ read in town layout info array -------//
115
116 memset( town_layout_array, 0, sizeof(TownLayout) * town_layout_count );
117
118 for( i=0 ; i<town_layout_count ; i++ )
119 {
120 townLayoutRec = (TownLayoutRec*) dbTownLayout->read(i+1);
121 townLayout = town_layout_array+i;
122
123 townLayout->first_slot_recno = misc.atoi(townLayoutRec->first_slot, TownLayoutRec::FIRST_SLOT_LEN);
124 townLayout->slot_count = misc.atoi(townLayoutRec->slot_count, TownLayoutRec::SLOT_COUNT_LEN);
125
126 // ###### begin Gilbert 9/9 ########//
127 // townLayout->ground_bitmap_ptr = image_spict.get_ptr( misc.nullify(townLayoutRec->ground_name, TownLayoutRec::GROUND_NAME_LEN) );
128 townLayout->ground_bitmap_ptr = image_tpict.get_ptr( misc.nullify(townLayoutRec->ground_name, TownLayoutRec::GROUND_NAME_LEN) );
129 // ###### end Gilbert 9/9 ########//
130
131 err_if( townLayout->slot_count > MAX_TOWN_LAYOUT_SLOT )
132 err_now( "Error: MAX_TOWN_LAYOUT_SLOT limit exceeded." );
133
134 //----- calculate min_population & max_population -----//
135
136 townSlot = town_slot_array+townLayout->first_slot_recno-1;
137
138 for( j=0 ; j<townLayout->slot_count ; j++, townSlot++ )
139 {
140 if( townSlot->build_type==TOWN_OBJECT_HOUSE ) // if there is a building in this slot
141 townLayout->build_count++;
142 }
143 }
144 }
145 //--------- End of function TownRes::load_town_layout ---------//
146
147
148 //------- Begin of function TownRes::load_town_slot -------//
149 //
150 // Read in information from TOWNSLOT.DBF.
151 //
load_town_slot()152 void TownRes::load_town_slot()
153 {
154 TownSlotRec *townSlotRec;
155 TownSlot *townSlot;
156 int i;
157 Database *dbTownSlot = game_set.open_db(TOWN_SLOT_DB);
158
159 town_slot_count = (short) dbTownSlot->rec_count();
160 town_slot_array = (TownSlot*) mem_add( sizeof(TownSlot)*town_slot_count );
161
162 //------ read in town slot info array -------//
163
164 memset( town_slot_array, 0, sizeof(TownSlot) * town_slot_count );
165
166 for( i=0 ; i<town_slot_count ; i++ )
167 {
168 townSlotRec = (TownSlotRec*) dbTownSlot->read(i+1);
169 townSlot = town_slot_array+i;
170
171 townSlot->base_x = misc.atoi(townSlotRec->base_x, TownSlotRec::POS_LEN);
172 townSlot->base_y = misc.atoi(townSlotRec->base_y, TownSlotRec::POS_LEN);
173
174 townSlot->build_type = misc.atoi(townSlotRec->type_id, TownSlotRec::TYPE_ID_LEN);
175 townSlot->build_code = misc.atoi(townSlotRec->build_code, TownSlotRec::BUILD_CODE_LEN);
176
177 err_when( townSlot->build_type == TOWN_OBJECT_FARM &&
178 (townSlot->build_code < 1 || townSlot->build_code > 9) );
179 }
180 }
181 //--------- End of function TownRes::load_town_slot ---------//
182
183
184 //------- Begin of function TownRes::load_town_build_type -------//
185 //
186 // Read in information from TOWNBTYP.DBF.
187 //
load_town_build_type()188 void TownRes::load_town_build_type()
189 {
190 TownBuildTypeRec *buildTypeRec;
191 TownBuildType *buildType;
192 int i;
193 Database *dbTownBuildType = game_set.open_db(TOWN_BUILD_TYPE_DB);
194
195 town_build_type_count = (short) dbTownBuildType->rec_count();
196 town_build_type_array = (TownBuildType*) mem_add( sizeof(TownBuildType)*town_build_type_count );
197
198 //------ read in TownBuildType info array -------//
199
200 memset( town_build_type_array, 0, sizeof(TownBuildType) * town_build_type_count );
201
202 for( i=0 ; i<town_build_type_count ; i++ )
203 {
204 buildTypeRec = (TownBuildTypeRec*) dbTownBuildType->read(i+1);
205 buildType = town_build_type_array+i;
206
207 buildType->first_build_recno = misc.atoi(buildTypeRec->first_build, TownBuildTypeRec::FIRST_BUILD_LEN);
208 buildType->build_count = misc.atoi(buildTypeRec->build_count, TownBuildTypeRec::BUILD_COUNT_LEN);
209 }
210 }
211 //--------- End of function TownRes::load_town_build_type ---------//
212
213
214 //------- Begin of function TownRes::load_town_build -------//
215 //
216 // Read in information from TOWNBULD.DBF.
217 //
load_town_build()218 void TownRes::load_town_build()
219 {
220 TownBuildRec *townBuildRec;
221 TownBuild *townBuild;
222 int i;
223 uint32_t bitmapOffset;
224 Database *dbTownBuild = game_set.open_db(TOWN_BUILD_DB);
225
226 town_build_count = (short) dbTownBuild->rec_count();
227 town_build_array = (TownBuild*) mem_add( sizeof(TownBuild)*town_build_count );
228
229 err_when( town_build_count > 255 ); // BYTE is used in TownZone::slot_array[]
230
231 //------ read in town build info array -------//
232
233 memset( town_build_array, 0, sizeof(TownBuild) * town_build_count );
234
235 for( i=0 ; i<town_build_count ; i++ )
236 {
237 townBuildRec = (TownBuildRec*) dbTownBuild->read(i+1);
238 townBuild = town_build_array+i;
239
240 townBuild->build_type = misc.atoi(townBuildRec->type_id, TownBuildRec::TYPE_ID_LEN);
241 townBuild->build_code = misc.atoi(townBuildRec->build_code, TownBuildRec::BUILD_CODE_LEN);
242 townBuild->race_id = misc.atoi(townBuildRec->race_id, TownBuildRec::RACE_ID_LEN);
243
244 memcpy( &bitmapOffset, townBuildRec->bitmap_ptr, sizeof(uint32_t) );
245
246 townBuild->bitmap_ptr = res_bitmap.read_imported(bitmapOffset);
247 townBuild->bitmap_width = *((short*)townBuild->bitmap_ptr);
248 townBuild->bitmap_height = *(((short*)townBuild->bitmap_ptr)+1);
249 }
250 }
251 //--------- End of function TownRes::load_town_build ---------//
252
253
254 //------- Begin of function TownRes::load_town_name -------//
255 //
256 // Read in information from TOWNNAME.DBF.
257 //
258 // Note: race_res must be initialized before calling this function.
259 //
load_town_name()260 void TownRes::load_town_name()
261 {
262 TownNameRec *townNameRec;
263 TownName *townName;
264 int i;
265 Database *dbTownName = game_set.open_db(TOWN_NAME_DB);
266
267 town_name_count = dbTownName->rec_count();
268 town_name_array = (TownName*) mem_add( sizeof(TownName)*town_name_count );
269 town_name_used_array = (unsigned char*) mem_add( sizeof(town_name_used_array[0]) * town_name_count ); // store the used_count separately from town_name_array to faciliate file saving
270
271 memset( town_name_used_array, 0, sizeof(town_name_used_array[0]) * town_name_count );
272
273 //------ read in TownName info array -------//
274
275 int raceId=0;
276
277 for( i=1 ; i<=town_name_count ; i++ )
278 {
279 townNameRec = (TownNameRec*) dbTownName->read(i);
280 townName = town_name_array+i-1;
281
282 misc.rtrim_fld( townName->name, townNameRec->name, townNameRec->NAME_LEN );
283
284 if( townName->name[0]=='@' ) // next race
285 {
286 int j;
287 for( j=1 ; j<=MAX_RACE ; j++ )
288 {
289 if( strcmp( race_res[j]->code, townName->name+1 ) == 0 )
290 break;
291 }
292
293 err_when( j > MAX_RACE );
294
295 if( raceId )
296 race_res[raceId]->town_name_count = i-race_res[raceId]->first_town_name_recno;
297
298 raceId = j;
299 race_res[raceId]->first_town_name_recno = i+1;
300 }
301 }
302
303 //-- set the town_name_count of the last town in TOWNNAME.DBF --//
304
305 race_res[raceId]->town_name_count = i-race_res[raceId]->first_town_name_recno;
306 }
307 //--------- End of function TownRes::load_town_name ---------//
308
309
310 //---------- Begin of function TownRes::scan_build -----------//
311 //
312 // Set the given slot with a building that fits the given criteria
313 //
314 // <int> slotId - the slot id. of the current town section to be set.
315 // <int> raceId - one of the building selection criteria
316 // (0-any race)
317 //
318 // return : <int> townBuildId - the id. of the town building
319 //
scan_build(int slotId,int raceId)320 int TownRes::scan_build(int slotId, int raceId)
321 {
322 enum { MAX_SCAN_ID = 100 };
323
324 TownSlot* townSlot = town_res.get_slot(slotId);
325 TownBuildType* buildType;
326 TownBuild* townBuild;
327 int i, buildRecno, matchCount=0;
328 int scanIdArray[MAX_SCAN_ID];
329
330 //---- get the building type of the slot ------//
331
332 buildType = town_res.get_build_type(townSlot->build_type);
333
334 err_if( buildType->build_count==0 )
335 err_here();
336
337 //------ scan_build buildings of the specified type ------//
338
339 buildRecno = buildType->first_build_recno;
340 townBuild = town_res.get_build(buildRecno); // the pointer to the first building of the specified type
341
342 for( i=buildType->build_count ; i>0 ; i--, townBuild++, buildRecno++ )
343 {
344 if( townBuild->build_code == townSlot->build_code )
345 {
346 if( !raceId || townBuild->race_id == raceId )
347 {
348 scanIdArray[matchCount] = buildRecno;
349
350 if( ++matchCount >= MAX_SCAN_ID )
351 break;
352 }
353 }
354 }
355
356 //--- pick one from those plants that match the criteria ---//
357
358 if( matchCount > 0 )
359 {
360 int buildId = scanIdArray[misc.random(matchCount)];
361
362 #ifdef DEBUG
363 town_res.get_build( buildId ); // get_build() will error if buildId is not valid
364 #endif
365
366 return buildId;
367 }
368 else
369 return 0;
370 }
371 //---------- End of function TownRes::scan_build -----------//
372
373 #ifdef DEBUG
374
375 //---------- Begin of function TownRes::get_layout -----------//
376
get_layout(int recNo)377 TownLayout* TownRes::get_layout(int recNo)
378 {
379 err_if( recNo<1 || recNo>town_layout_count )
380 err_now( "TownRes::get_layout()" );
381
382 return town_layout_array+recNo-1;
383 }
384 //------------ End of function TownRes::get_layout -----------//
385
386
387 //---------- Begin of function TownRes::get_slot -----------//
388
get_slot(int recNo)389 TownSlot* TownRes::get_slot(int recNo)
390 {
391 err_if( recNo<1 || recNo>town_slot_count )
392 err_now( "TownRes::get_slot()" );
393
394 return town_slot_array+recNo-1;
395 }
396 //------------ End of function TownRes::get_slot -----------//
397
398
399 //---------- Begin of function TownRes::get_build_type -----------//
400
get_build_type(int recNo)401 TownBuildType* TownRes::get_build_type(int recNo)
402 {
403 err_if( recNo<1 || recNo>town_build_type_count )
404 err_now( "TownRes::get_build_type()" );
405
406 return town_build_type_array+recNo-1;
407 }
408 //------------ End of function TownRes::get_build_type -----------//
409
410
411 //---------- Begin of function TownRes::get_build -----------//
412
get_build(int recNo)413 TownBuild* TownRes::get_build(int recNo)
414 {
415 err_if( recNo<1 || recNo>town_build_count )
416 err_now( "TownRes::get_build()" );
417
418 return town_build_array+recNo-1;
419 }
420 //------------ End of function TownRes::get_build -----------//
421
422 #endif
423
424 //---------- Begin of function TownRes::get_name -----------//
425
get_name(int recNo)426 char* TownRes::get_name(int recNo)
427 {
428 err_if( recNo<1 || recNo>town_name_count )
429 err_now( "TownRes::get_name()" );
430
431 return town_name_array[recNo-1].name;
432 }
433 //------------ End of function TownRes::get_name -----------//
434
435
436 //--------- Begin of function TownRes::get_new_name_id ----------//
437 //
get_new_name_id(int raceId)438 int TownRes::get_new_name_id(int raceId)
439 {
440 RaceInfo* raceInfo = race_res[raceId];
441
442 err_when( raceInfo->town_name_used_count > raceInfo->town_name_count );
443
444 int townNameId;
445
446 //----- if all town names have been used already -----//
447 //--- scan the town name one by one and pick an unused one ---//
448
449 if( raceInfo->town_name_used_count == raceInfo->town_name_count )
450 {
451 int nameId = misc.random(raceInfo->town_name_count)+1; // this is the id. of one race only
452
453 for( int i=raceInfo->town_name_count ; i>0 ; i-- )
454 {
455 if( ++nameId > raceInfo->town_name_count )
456 nameId = 1;
457
458 if( town_name_used_array[raceInfo->first_town_name_recno+nameId-2]==0 ) // -2 is the total of two -1, (one with first_town_name_recno, another with town_name_used_array[]
459 break;
460 }
461
462 townNameId = raceInfo->first_town_name_recno + nameId - 1;
463 }
464 else
465 {
466 raceInfo->town_name_used_count++;
467
468 townNameId = raceInfo->first_town_name_recno + raceInfo->town_name_used_count - 1;
469 }
470
471 err_when( townNameId < 1 || townNameId > town_name_count );
472
473 town_name_used_array[townNameId-1]++;
474
475 return townNameId;
476 }
477 //--------- End of function TownRes::get_new_name_id ----------//
478
479
480 //--------- Begin of function TownRes::free_name_id ----------//
481 //
482 // Free an used name id.
483 //
free_name_id(int townNameId)484 void TownRes::free_name_id(int townNameId)
485 {
486 town_name_used_array[townNameId-1]--;
487 }
488 //--------- End of function TownRes::free_name_id ----------//
489