00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <stdio.h>
00026
00027 #include <cstring>
00028
00029 #include "global.h"
00030 #include "prehistoricevents.h"
00031 #include "gameeventsystem.h"
00032 #include "gameevents.h"
00033 #include "dialog.h"
00034 #include "buildings.h"
00035 #include "gamemap.h"
00036
00037
00038 enum { cemessage, ceweatherchange, cenewtechnology, celosecampaign, cerunscript, cenewtechnologyresearchable,
00039
00040 cemapchange, ceeraseevent, cecampaignend, cenextmap, cereinforcement, ceweatherchangecomplete,
00041
00042 cenewvehicledeveloped, cepalettechange, cealliancechange, cewindchange, cenothing,
00043
00044 cegameparamchange, ceellipse, ceremoveellipse, cechangebuildingdamage, ceaddobject };
00045
00046
00047 extern const char* ceventtrigger[];
00048
00049 enum { ceventt_turn = 1 , ceventt_buildingconquered, ceventt_buildinglost, ceventt_buildingdestroyed, ceventt_unitlost,
00050
00051 ceventt_technologyresearched, ceventt_event, ceventt_unitconquered, ceventt_unitdestroyed,
00052
00053 ceventt_allenemyunitsdestroyed, ceventt_allunitslost, ceventt_allenemybuildingsdestroyed,
00054
00055 ceventt_allbuildingslost, ceventt_energytribute, ceventt_materialtribute, ceventt_fueltribute,
00056
00057 ceventt_any_unit_enters_polygon, ceventt_specific_unit_enters_polygon, ceventt_building_seen, ceventt_irrelevant };
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163 #pragma pack(1)
00164
00165 typedef class tevent* pevent ;
00166
00167 class PrehistoricEventStructure {
00168 public:
00169 union {
00170 struct { Uint16 saveas; char action, num; }a;
00171 int id;
00172 } ;
00173
00174 char player;
00175
00176
00177 char description[20];
00178
00179 union {
00180 void* rawdata;
00181 char* chardata;
00182 int* intdata;
00183 };
00184
00185 int datasize;
00186 pevent next;
00187 int conn;
00188 Uint16 trigger[4];
00189
00190 class LargeTriggerData {
00191 public:
00192
00193 class PolygonEntered {
00194 public:
00195 int dataSize;
00196 int dummy;
00197 int vehiclenetworkid;
00198 int* data;
00199 int tempnwid;
00200 int tempxpos;
00201 int tempypos;
00202 int color;
00203 int reserved[7];
00204 PolygonEntered ( void );
00205 PolygonEntered ( const PolygonEntered& poly );
00206 ~PolygonEntered ( );
00207 };
00208
00209 GameTime time;
00210 int xpos, ypos;
00211 int networkid;
00212 Building* building;
00213 int dummy;
00214 int mapid;
00215 int id;
00216 PrehistoricEventStructure::LargeTriggerData::PolygonEntered* unitpolygon;
00217 int reserved[32];
00218 LargeTriggerData ( void );
00219 LargeTriggerData ( const LargeTriggerData& data );
00220 ~LargeTriggerData();
00221 };
00222
00223 LargeTriggerData* trigger_data[4];
00224
00225 char triggerconnect[4];
00226 char triggerstatus[4];
00227
00228
00229
00230 GameTime triggertime;
00231
00232
00233 struct {
00234 int turn;
00235 int move;
00236 } delayedexecution;
00237
00238
00239
00240
00241
00242
00243 PrehistoricEventStructure();
00244 ~PrehistoricEventStructure();
00245
00246
00247
00248
00249 };
00250
00251 #pragma pack()
00252
00253
00254 extern const char* cconnections[6];
00255 #define cconnection_destroy 1
00256 #define cconnection_conquer 2
00257 #define cconnection_lose 4
00258 #define cconnection_seen 8
00259 #define cconnection_areaentered_anyunit 16
00260 #define cconnection_areaentered_specificunit 32
00261
00262
00263
00264
00265 const int ceventtriggernum = 21;
00266 extern const char* ceventtriggerconn[];
00267 #define ceventtrigger_and 1
00268 #define ceventtrigger_or 2
00269 #define ceventtrigger_not 4
00270 #define ceventtrigger_klammerauf 8
00271 #define ceventtrigger_2klammerauf 16
00272 #define ceventtrigger_2klammerzu 32
00273 #define ceventtrigger_klammerzu 64
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283 #define ceventactionnum 22
00284 extern const char* ceventactions[ceventactionnum];
00285
00286
00287
00288
00290 const char* cconnections[6] = {"destroyed", "conquered", "lost", "seen", "area entererd by any unit", "area entered by specific unit"};
00291
00292 const char* ceventtriggerconn[8] = {"AND ", "OR ", "NOT ", "( ", "(( ", ")) ", ") ", "Clear "};
00293
00295 const char* ceventactions[ceventactionnum] = {"message", "weather change", "new technology discovered", "lose campaign", "run script + next map",
00296 "new technology researchable", "map change", "discarded [ was erase event ]", "end campaign", "next map",
00297 "reinforcement","weather change completed", "new vehicle developed","palette change",
00298 "alliance change","wind change", "nothing", "change game parameter","paint ellipse","remove ellipse",
00299 "change building damage", "add object"};
00300
00301 const char* ceventtrigger[ceventtriggernum] = {"*NONE*", "turn/move >=", "building conquered", "building lost",
00302 "building destroyed", "unit lost", "technology researched",
00303 "event", "unit conquered", "unit destroyed", "all enemy units destroyed",
00304 "all units lost", "all enemy buildings destroyed/captured", "all buildings lost",
00305 "energy tribute <", "material tribute <", "fuel tribute <",
00306 "any unit enters polygon", "specific unit enters polygon", "building is seen", "irrelevant (used internally)"};
00307
00308 Event* readOldEvent( pnstream stream, GameMap* gamemap, map<int,int>& eventTranslation, map<EventTriggered*,int>& eventTriggerEvents );
00309
00310
00311 void readOldEventLists ( pnstream stream, bool passedEvents, GameMap* spfld )
00312 {
00313 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
00314
00315 if ( sizeof(int*) != 4 ) {
00316 displaymessage ("Unable to load map " + stream->getLocation() + " in old file format on a non-32 bit machine\nPlease convert this file to the new file format on a 32 bit little endian machine and try again",1);
00317 throw tfileerror();
00318 }
00319
00320 map<int,int> eventTranslation;
00321 map<EventTriggered*,int> eventTriggerEvents;
00322
00323 int j = stream->readInt();
00324 if ( j )
00325 for (int k = 1; k <= j; k++) {
00326 Event* ev = readOldEvent ( stream, spfld, eventTranslation, eventTriggerEvents );
00327 if ( ev )
00328 spfld->events.push_back ( ev );
00329 }
00330
00331 if ( passedEvents ) {
00332 int j = stream->readInt();
00333 if ( j )
00334 for (int k = 1; k <= j; k++) {
00335 Event* ev = readOldEvent ( stream, spfld, eventTranslation, eventTriggerEvents );
00336 if ( ev ) {
00337 ev->status = Event::Executed;
00338 spfld->events.push_back ( ev );
00339 }
00340 }
00341 }
00342
00343 for ( map<EventTriggered*,int>::iterator i = eventTriggerEvents.begin(); i != eventTriggerEvents.end(); ++i ) {
00344 map<int,int>::iterator e = eventTranslation.find ( i->second );
00345 if ( e == eventTranslation.end() ) {
00346 displaymessage ("Could not find oldEvent-ID for setting the event Trigger",1);
00347 return;
00348 }
00349
00350 i->first->setEventID ( e->second );
00351 }
00352 #else
00353 displaymessage ("Unable to load map " + stream->getLocation() + " in old file format on a big endian machine\nPlease convert this file to the new file format on a little endian machine and try again",1);
00354 throw tfileerror();
00355 #endif
00356 }
00357
00358
00359 PrehistoricEventStructure::LargeTriggerData::PolygonEntered :: PolygonEntered ( void )
00360 {
00361 dataSize = 0;
00362 vehiclenetworkid = 0;
00363 data = NULL;
00364 tempnwid = 0;
00365 tempxpos = 0;
00366 tempypos = 0;
00367 color = 0;
00368 memset ( reserved, 0, sizeof ( reserved ));
00369 }
00370
00371 PrehistoricEventStructure::LargeTriggerData::PolygonEntered :: PolygonEntered ( const PrehistoricEventStructure::LargeTriggerData::PolygonEntered& poly )
00372 {
00373 dataSize = poly.dataSize;
00374 vehiclenetworkid = poly.vehiclenetworkid;
00375 if ( poly.data ) {
00376 data = new int [dataSize];
00377 for ( int i = 0; i < dataSize; i++ )
00378 data[i] = poly.data[i];
00379 } else
00380 data = NULL;
00381 tempnwid = poly.tempnwid;
00382 tempxpos = poly.tempxpos;
00383 tempypos = poly.tempypos;
00384 color = poly.color;
00385 memcpy ( reserved, poly.reserved, sizeof ( reserved ));
00386 }
00387
00388 PrehistoricEventStructure::LargeTriggerData::PolygonEntered :: ~PolygonEntered ( )
00389 {
00390 if ( data ) {
00391 delete[] data;
00392 data = NULL;
00393 }
00394 }
00395
00396
00397 PrehistoricEventStructure::LargeTriggerData :: LargeTriggerData ( void )
00398 {
00399 time.abstime = 0;
00400 xpos = -1;
00401 ypos = -1;
00402 building = NULL;
00403 mapid = 0;
00404 id = -1;
00405 unitpolygon = NULL;
00406 networkid = 0;
00407 memset ( reserved, 0, sizeof ( reserved ));
00408 }
00409
00410 PrehistoricEventStructure::LargeTriggerData :: LargeTriggerData ( const LargeTriggerData& data )
00411 {
00412 time = data.time;
00413 xpos = data.xpos;
00414 ypos = data.ypos;
00415 networkid = data.networkid;
00416 building = data.building;
00417 mapid = data.mapid;
00418 id = data.id;
00419 if ( data.unitpolygon ) {
00420 unitpolygon = new PrehistoricEventStructure::LargeTriggerData::PolygonEntered ( *data.unitpolygon );
00421 } else
00422 unitpolygon = NULL;
00423 }
00424
00425 PrehistoricEventStructure::LargeTriggerData :: ~LargeTriggerData ( )
00426 {
00427 if ( unitpolygon ) {
00428 delete unitpolygon;
00429 unitpolygon = NULL;
00430 }
00431 }
00432
00433 PrehistoricEventStructure :: PrehistoricEventStructure()
00434 {
00435 a.action= 255;
00436 a.saveas = 0;
00437 a.num = 0;
00438 player = 0;
00439 rawdata = NULL;
00440 next = NULL;
00441 datasize = 0;
00442 conn = 0;
00443 for ( int i = 0; i < 4; i++) {
00444 trigger[i] = 0;
00445 triggerstatus[i] = 0;
00446 triggerconnect[i] = 0;
00447 triggertime.set( -1, -1 );
00448 trigger_data[i] = new LargeTriggerData;
00449 }
00450 delayedexecution.turn = 0;
00451 delayedexecution.move = 0;
00452 description[0] = 0;
00453 triggertime.abstime = -1;
00454 }
00455
00456
00457
00458 PrehistoricEventStructure :: ~PrehistoricEventStructure ()
00459 {
00460 for ( int i = 0; i < 4; i++ )
00461 if ( trigger_data[i] ) {
00462 delete trigger_data[i];
00463 trigger_data[i] = NULL;
00464 }
00465
00466 if ( rawdata ) {
00467 asc_free( rawdata );
00468 rawdata = NULL;
00469 }
00470 }
00471
00472
00473
00474
00475
00476
00477 Event* readOldEvent( pnstream stream, GameMap* gamemap, map<int,int>& eventTranslation, map<EventTriggered*,int>& eventTriggerEvents )
00478 {
00479
00481
00482
00483
00485
00486 map<EventTriggered*,int> localEventTriggerEvents;
00487
00488 Event* ev = new Event( *gamemap );
00489
00490 PrehistoricEventStructure event1;
00491
00492 int magic = stream->readInt();
00493 int version;
00494 if ( magic == -1 ) {
00495 version = stream->readInt();
00496 stream->readdata ( &event1, 85 );
00497 } else {
00498 memcpy ( &event1, &magic, sizeof ( magic ));
00499 int* pi = (int*) &event1;
00500 pi++;
00501 stream->readdata ( pi, 85 - sizeof ( int ));
00502 version = 0;
00503 }
00504
00505 if ( version > 2 )
00506 throw tinvalidversion ( "OldEvent", 2, version );
00507
00508 if ( event1.datasize && event1.rawdata ) {
00509 event1.rawdata = asc_malloc ( event1.datasize );
00510 stream->readdata ( event1.rawdata, event1.datasize );
00511 } else {
00512 event1.datasize = 0;
00513 event1.rawdata = NULL;
00514 }
00515
00516 EventAction* ea = NULL;
00517
00518 switch ( event1.a.action ) {
00519 case cewindchange: ea = new WindChange ( event1.intdata[0], event1.intdata[3] );
00520 break;
00521 case cegameparamchange: ea = new ChangeGameParameter( event1.intdata[0], event1.intdata[1] );
00522 break;
00523 case cemessage: ea = new DisplayMessage ( event1.a.saveas );
00524 break;
00525 case cenothing: ea = new Action_Nothing();
00526 break;
00527 case cechangebuildingdamage: ea = new ChangeBuildingDamage( MapCoordinate( event1.intdata[0], event1.intdata[1]), event1.intdata[2] );
00528 break;
00529 case ceweatherchangecomplete:ea = new MapChangeCompleted();
00530 break;
00531 case cenextmap: ea = new NextMap( event1.a.saveas );
00532 break;
00533 case celosecampaign: ea = new LoseMap();
00534 break;
00535 case ceaddobject: {
00536 AddObject* ao = new AddObject( event1.intdata[2] );
00537 ao->setField ( MapCoordinate( event1.intdata[0], event1.intdata[1] ));
00538 ea = ao;
00539 }
00540 break;
00541 case ceellipse: ea = new DisplayEllipse( event1.intdata[0], event1.intdata[1], event1.intdata[2], event1.intdata[3], event1.intdata[4], event1.intdata[5] );
00542 break;
00543 case ceremoveellipse: ea = new RemoveEllipse();
00544 break;
00545 case ceweatherchange: {
00546 WeatherChange* wc = new WeatherChange( event1.intdata[0] );
00547 if ( event1.intdata[1] == 0 ) {
00548 Poly_gon poly;
00549 if ( event1.intdata[2] > 1 )
00550 displaymessage("Only the first polygon will be used!", 1 );
00551
00552 for ( int i = 0; i < event1.intdata[3]; ++i )
00553 poly.vertex.push_back ( MapCoordinate( event1.intdata[4+2*i], event1.intdata[5+2*i] ));
00554
00555 wc->setPolygon ( poly );
00556 } else
00557 wc->setGlobal();
00558 ea = wc;
00559 }
00560 break;
00561 case cemapchange: {
00562 MapChange* mc = new MapChange( event1.intdata[0] );
00563 Poly_gon poly;
00564 for ( int i = 0; i < event1.intdata[4]; ++i )
00565 poly.vertex.push_back ( MapCoordinate( event1.intdata[5+2*i], event1.intdata[6+2*i] ));
00566
00567 mc->setPolygon ( poly );
00568 ea = mc;
00569 }
00570 break;
00571
00572 default: displaymessage("The event action %s has not been converted and will be missing!", 1, ceventactions[int(event1.a.action)] );
00573 };
00574
00575 if ( ea ) {
00576 ev->action = ea;
00577 ea->setMap ( gamemap );
00578 }
00579
00580 int ANDcounter = 0;
00581 int ORcounter = 0;
00582 bool missingConnection = false;
00583
00584 for (int m = 0; m <= 3; m++) {
00585
00586 EventTrigger* et = 0;
00587
00588 event1.trigger_data[m] = new PrehistoricEventStructure::LargeTriggerData;
00589 if ( event1.trigger[m] ) {
00590 if ((event1.trigger[m] == ceventt_buildingconquered) ||
00591 (event1.trigger[m] == ceventt_buildinglost) ||
00592 (event1.trigger[m] == ceventt_buildingdestroyed) ||
00593 (event1.trigger[m] == ceventt_building_seen )) {
00594
00595 Sint16 xpos, ypos;
00596 stream->readdata2 ( xpos );
00597 stream->readdata2 ( ypos );
00598
00599 event1.trigger_data[m]->xpos = xpos;
00600 event1.trigger_data[m]->ypos = ypos;
00601
00602 switch ( event1.trigger[m] ) {
00603 case ceventt_buildingconquered: et = new BuildingConquered ( MapCoordinate( xpos, ypos ));
00604 break;
00605 case ceventt_buildinglost: et = new BuildingLost ( MapCoordinate( xpos, ypos ));
00606 break;
00607 case ceventt_buildingdestroyed: et = new BuildingDestroyed ( MapCoordinate( xpos, ypos ));
00608 break;
00609 case ceventt_building_seen: et = new BuildingSeen ( MapCoordinate( xpos, ypos ));
00610 break;
00611 };
00612
00613 }
00614
00615 if ((event1.trigger[m] == ceventt_unitconquered) ||
00616 (event1.trigger[m] == ceventt_unitlost) ||
00617 (event1.trigger[m] == ceventt_unitdestroyed)) {
00618
00619 if ( version == 0 ) {
00620 Sint16 xpos, ypos;
00621 stream->readdata2 ( xpos );
00622 stream->readdata2 ( ypos );
00623 event1.trigger_data[m]->xpos = xpos;
00624 event1.trigger_data[m]->ypos = ypos;
00625 event1.trigger_data[m]->networkid = -1;
00626
00627 displaymessage("The event trigger %s has not been converted and will be missing!", 1, ceventtrigger[event1.trigger[m]] );
00628
00629 } else {
00630 stream->readdata2( event1.trigger_data[m]->xpos );
00631 stream->readdata2( event1.trigger_data[m]->ypos );
00632 stream->readdata2( event1.trigger_data[m]->networkid );
00633
00634 switch ( event1.trigger[m] ) {
00635 case ceventt_unitconquered: et = new UnitConquered ( event1.trigger_data[m]->networkid );
00636 break;
00637 case ceventt_unitlost: et = new UnitLost ( event1.trigger_data[m]->networkid );
00638 break;
00639 case ceventt_unitdestroyed: et = new UnitDestroyed ( event1.trigger_data[m]->networkid );
00640 break;
00641 };
00642 }
00643 }
00644
00645 if ( event1.trigger[m] == ceventt_event ) {
00646 stream->readdata2 ( event1.trigger_data[m]->id );
00647 EventTriggered* ett = new EventTriggered();
00648 et = ett;
00649 localEventTriggerEvents[ett] = event1.trigger_data[m]->id;
00650 }
00651
00652 if ( event1.trigger[m] == ceventt_technologyresearched ) {
00653 stream->readdata2 ( event1.trigger_data[m]->id );
00654 }
00655
00656 if ( version >=2 ) {
00657 if ( event1.trigger[m] == ceventt_allenemybuildingsdestroyed ) {
00658 stream->readdata2 ( event1.trigger_data[m]->id );
00659 et = new AllEnemyBuildingsDestroyed;
00660 }
00661
00662 if (event1.trigger[m] == ceventt_allenemyunitsdestroyed ) {
00663 stream->readdata2 ( event1.trigger_data[m]->id );
00664 et = new AllEnemyUnitsDestroyed;
00665 }
00666 }
00667
00668 if (event1.trigger[m] == ceventt_turn) {
00669 stream->readdata2 ( event1.trigger_data[m]->time.abstime );
00670 et = new TurnPassed ( event1.trigger_data[m]->time.turn(), event1.trigger_data[m]->time.move() );
00671 }
00672 if (event1.trigger[m] == ceventt_any_unit_enters_polygon ||
00673 event1.trigger[m] == ceventt_specific_unit_enters_polygon) {
00674 stream->readInt();
00675 event1.trigger_data[m]->unitpolygon = new PrehistoricEventStructure::LargeTriggerData::PolygonEntered;
00676 stream->readdata2( *event1.trigger_data[m]->unitpolygon );
00677 event1.trigger_data[m]->unitpolygon->data = new int [ event1.trigger_data[m]->unitpolygon->dataSize ];
00678 stream->readdata( event1.trigger_data[m]->unitpolygon->data, event1.trigger_data[m]->unitpolygon->dataSize * sizeof(int) );
00679 if ( event1.trigger_data[m]->unitpolygon->vehiclenetworkid ) {
00680 stream->readdata2( event1.trigger_data[m]->unitpolygon->tempxpos );
00681 stream->readdata2( event1.trigger_data[m]->unitpolygon->tempypos );
00682 stream->readdata2( event1.trigger_data[m]->unitpolygon->tempnwid );
00683 event1.trigger_data[m]->unitpolygon->vehiclenetworkid = event1.trigger_data[m]->unitpolygon->tempnwid;
00684 }
00685
00686 Poly_gon pg;
00687 for( int i = 0; i < event1.trigger_data[m]->unitpolygon->data[1]; ++i )
00688 pg.vertex.push_back ( MapCoordinate( event1.trigger_data[m]->unitpolygon->data[2+2*i], event1.trigger_data[m]->unitpolygon->data[3+2*i] ));
00689
00690 if ( event1.trigger[m] == ceventt_any_unit_enters_polygon ) {
00691 AnyUnitEntersPolygon* auep = new AnyUnitEntersPolygon ( event1.trigger_data[m]->unitpolygon->color );
00692 auep->setPolygon ( pg );
00693 et = auep;
00694 } else {
00695 SpecificUnitEntersPolygon* suep = new SpecificUnitEntersPolygon ( event1.trigger_data[m]->unitpolygon->vehiclenetworkid );
00696 suep->setPolygon ( pg );
00697 et = suep;
00698 }
00699 }
00700
00701 if (event1.trigger[m] == ceventt_allbuildingslost )
00702 et = new AllBuildingsLost();
00703
00704 if (event1.trigger[m] == ceventt_allunitslost )
00705 et = new AllUnitsLost();
00706
00707 if ( event1.triggerconnect[m] & ceventtrigger_not )
00708 if ( et )
00709 et->invert = true;
00710
00711 if ( event1.triggerconnect[m] & ceventtrigger_and )
00712 ++ANDcounter;
00713
00714 if ( event1.triggerconnect[m] & ceventtrigger_or )
00715 ++ORcounter;
00716
00717 if ( event1.triggerconnect[m] & ( ceventtrigger_klammerauf | ceventtrigger_2klammerauf | ceventtrigger_klammerzu | ceventtrigger_2klammerzu ))
00718 missingConnection = true;
00719
00720 if ( et ) {
00721 ev->trigger.push_back ( et );
00722 et->setMap ( gamemap );
00723 et->setEvent ( ev );
00724 } else
00725 displaymessage("The trigger %d (%s) for event %s could not be converted !", 1,m,ceventtrigger[event1.trigger[m]],event1.description );
00726
00727 }
00728
00729 }
00730
00731 if ( ANDcounter & ORcounter )
00732 missingConnection = true;
00733
00734 if ( missingConnection )
00735 displaymessage("The connection of the triggers for event %s could not be completely converted !", 1,event1.description );
00736
00737
00738
00739 if ( ev && ev->action ) {
00740 if ( ANDcounter > ORcounter )
00741 ev->triggerConnection = Event::AND;
00742 else
00743 ev->triggerConnection = Event::OR;
00744
00745 ev->description = event1.description;
00746
00747 eventTranslation[event1.id] = ev->id;
00748 eventTriggerEvents.insert( localEventTriggerEvents.begin(), localEventTriggerEvents.end() );
00749 return ev;
00750 } else {
00751 delete ev;
00752 return NULL;
00753 }
00754 }
00755
00756