/*! \file gameevents.cpp \brief The event handling of ASC */ /* This file is part of Advanced Strategic Command; http://www.asc-hq.de Copyright (C) 1994-2005 Martin Bickel and Marc Schellenberger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "global.h" #include "buildingtype.h" #include "vehicletype.h" #include "newfont.h" #include "typen.h" #include "basegfx.h" #include "gameevent_dialogs.h" #include "spfst.h" #include "loaders.h" #include "gameevents.h" #include "dlg_box.h" #include "dialog.h" #include "errors.h" #include "itemrepository.h" #include "messagedlg.h" #include "mapdisplay.h" #ifdef sgmain # include "gamedlg.h" # include "viewcalculation.h" # include "resourcenet.h" #endif extern void repaintdisplay(); const int EventActionNum = 21; const int EventTriggerNum = 18; void viewtextmessage ( int id, int player ) { ASCString txt = readtextmessage( id ); if ( !txt.empty() ) { int to; if ( player < 8 ) to = (1 << player); else to = 0xff; new Message ( txt, actmap, to ); #ifdef sgmain if ( player == actmap->actplayer ) viewunreadmessages ( ); #endif } else displaymessage( "Message %d not found", 1, id ); } ///////////////////////////////////////////////////////////////////////////// // Trigger void TriggerNothing::readData( tnstream& stream ) { int version = stream.readInt(); } void TriggerNothing::writeData( tnstream& stream ) { stream.writeInt(1); } EventTrigger::State TurnPassed::getState( int player ) { if ( gamemap->time.turn() > turn || (gamemap->time.turn() == turn && gamemap->time.move() >= move )) return finally_fulfilled; else return unfulfilled; } void TurnPassed::arm() { GameTime t; t.set ( turn, move ); gamemap->eventTimes.push_back ( t ); sort( gamemap->eventTimes.begin(), gamemap->eventTimes.end(), GameTime::comp ); } void TurnPassed::readData( tnstream& stream ) { int version = stream.readInt(); turn = stream.readInt(); move = stream.readInt(); } void TurnPassed::writeData( tnstream& stream ) { stream.writeInt(1); stream.writeInt( turn ); stream.writeInt( move ); } void TurnPassed::setup() { turn = editInt( "turn", turn ); move = editInt( "move", move ); } ASCString TurnPassed::getName() const { ASCString s; s.format( "turn %d , move %d passed ", turn, move ); return s; } ASCString BuildingPositionTrigger::getName() const { ASCString s = "Building "; if ( gamemap->getField(pos) && gamemap->getField(pos)->building ) s += gamemap->getField(pos)->building->getName(); else s += " "; return s; } void BuildingPositionTrigger::setup() { getxy_building( &pos.x, &pos.y ); } EventTrigger::State BuildingConquered::getState( int player ) { pfield fld = gamemap->getField ( pos ); if( !fld ) { displaymessage ("invalid event - map field not found!", 1); return finally_failed; } if ( !fld->building ) return finally_failed; if ( fld->building->getOwner() == player ) return fulfilled; else return unfulfilled; } void BuildingConquered::arm() { if( !gamemap->getField ( pos ) ) { displaymessage ("invalid event - map field not found!", 1); return; } pbuilding bld = gamemap->getField ( pos )->building; if ( bld ) bld->conquered.connect( SigC::slot( *this, &BuildingConquered::triggered )); } void BuildingConquered::triggered() { if ( isFulfilled() ) eventReady(); } EventTrigger::State BuildingLost::getState( int player ) { State s = BuildingConquered::getState ( player ); if ( s == fulfilled) return unfulfilled; if ( s == unfulfilled ) return fulfilled; return s; } void BuildingLost::arm() { if( !gamemap->getField ( pos ) ) { displaymessage ("invalid event - map field not found!", 1); return; } pbuilding bld = gamemap->getField ( pos )->building; if ( bld ) { bld->conquered.connect( SigC::slot( *this, &BuildingConquered::triggered )); bld->destroyed.connect( SigC::slot( *this, &BuildingConquered::triggered )); } } void PositionTrigger::readData( tnstream& stream ) { int version = stream.readInt(); pos.read( stream ); } void PositionTrigger::writeData( tnstream& stream ) { stream.writeInt(1); pos.write( stream ); } EventTrigger::State BuildingDestroyed::getState( int player ) { if( !gamemap->getField ( pos ) ) { displaymessage ("invalid event - map field not found!", 1); return finally_fulfilled; } pfield fld = gamemap->getField ( pos ); if ( !fld->building ) return finally_fulfilled; else return unfulfilled; } EventTrigger::State BuildingSeen::getState( int player ) { if( !gamemap->getField ( pos ) ) { displaymessage ("invalid event - map field not found!", 1); return finally_fulfilled; } pbuilding bld = gamemap->getField ( pos )->building; if ( !bld ) return finally_failed; int cnt = 0; for ( int x = 0; x < 4; x++ ) for ( int y = 0; y < 6; y++ ) { if ( bld->typ->getpicture ( BuildingType::LocalCoordinate(x, y) ) ) { pfield fld = bld->getField ( BuildingType::LocalCoordinate( x, y) ); if ( fld ) { int vis = (fld-> visible >> (player*2) ) & 3; if ( bld->typ->buildingheight >= chschwimmend && bld->typ->buildingheight <= chhochfliegend ) { if ( vis >= visible_now ) cnt++; } else { if ( vis == visible_all ) cnt++; } } } } if ( cnt ) return finally_fulfilled; else return unfulfilled; } void BuildingSeen::arm() { if( !gamemap->getField ( pos ) ) { displaymessage ("invalid event - map field not found!", 1); return; } pbuilding bld = gamemap->getField ( pos )->building; if ( bld ) { bld->connection |= cconnection_seen; #ifdef sgmain buildingSeen.connect( SigC::slot( *this, &BuildingSeen::triggered )); #endif } } void BuildingSeen::triggered() { if ( isFulfilled() ) eventReady(); } EventTrigger::State AllBuildingsLost::getState( int player ) { if ( gamemap->player[player].buildingList.empty() ) return fulfilled; else return unfulfilled; } ASCString AllBuildingsLost::getName() const { return "All Buildings Lost"; } EventTrigger::State AllUnitsLost::getState( int player ) { if ( gamemap->player[player].vehicleList.empty() ) return fulfilled; else return unfulfilled; } ASCString AllUnitsLost::getName() const { return "All Units Lost"; } void UnitTrigger::readData ( tnstream& stream ) { int version = stream.readInt(); unitID = stream.readInt(); } void UnitTrigger::writeData ( tnstream& stream ) { stream.writeInt(1); stream.writeInt( unitID ); } ASCString UnitTrigger::getName() const { ASCString s = "unit "; if ( gamemap->getUnit( unitID )) s += gamemap->getUnit( unitID )->getName(); else s += ""; return s; } void UnitTrigger::setup() { unitID = selectunit ( unitID ); } void UnitTrigger::triggered() { state( -1 ); eventReady(); } void UnitLost::arm() { pvehicle veh = gamemap->getUnit( unitID ); if ( veh ) { veh->destroyed.connect( SigC::slot( *this, &UnitLost::triggered )); veh->conquered.connect( SigC::slot( *this, &UnitLost::triggered )); } } EventTrigger::State UnitLost::getState( int player ) { pvehicle veh = gamemap->getUnit( unitID ); if ( !veh ) return finally_fulfilled; if ( veh->getOwner() != player ) return fulfilled; return unfulfilled; } ASCString UnitLost::getName() const { return UnitTrigger::getName() + " lost"; } EventTrigger::State UnitConquered::getState( int player ) { pvehicle veh = gamemap->getUnit( unitID ); if ( !veh ) return finally_failed; if ( veh->getOwner() == player ) return fulfilled; return unfulfilled; } ASCString UnitConquered::getName() const { return UnitTrigger::getName() + " conquered"; } void UnitConquered::arm() { pvehicle veh = gamemap->getUnit( unitID ); if ( veh ) veh->conquered.connect( SigC::slot( *this, &UnitConquered::triggered )); } EventTrigger::State UnitDestroyed::getState( int player ) { pvehicle veh = gamemap->getUnit( unitID ); if ( !veh ) return finally_fulfilled; return unfulfilled; } ASCString UnitDestroyed::getName() const { return UnitTrigger::getName() + " destroyed"; } void UnitDestroyed::arm() { pvehicle veh = gamemap->getUnit( unitID ); if ( veh ) veh->destroyed.connect( SigC::slot( *this, &UnitDestroyed::triggered )); } EventTrigger::State EventTriggered::getState( int player ) { for ( tmap::Events::iterator i = gamemap->events.begin(); i != gamemap->events.end(); ++i ) if ( (*i)->id == eventID && (*i)->status == Event::Executed ) return finally_fulfilled; return unfulfilled; } void EventTriggered::readData ( tnstream& stream ) { stream.readInt(); eventID = stream.readInt(); } void EventTriggered::writeData ( tnstream& stream ) { stream.writeInt(1); stream.writeInt( eventID ); } Event* EventTriggered::getTargetEventName() const { for ( tmap::Events::iterator i = gamemap->events.begin(); i != gamemap->events.end(); ++i ) if ( (*i)->id == eventID ) return *i; return NULL; } ASCString EventTriggered::getName() const { Event* e = getTargetEventName(); if ( e ) { ASCString s = "Event "; if ( !e->description.empty() ) s += e->description; else s += e->action->getName(); s += " triggered"; return s; } else return "Event triggered"; } void EventTriggered::setup() { vector eventIDs; vector eventnames; int fnd = -1; int counter = 0; for ( tmap::Events::iterator i = gamemap->events.begin(); i != gamemap->events.end(); ++i ) { eventnames.push_back( (*i)->action->getName() + " : " + (*i)->description ); eventIDs.push_back ( (*i)->id ); if ( (*i)->id == eventID ) fnd = counter; ++counter; } int res = chooseString ( "select event", eventnames, fnd ); if ( res >= 0) eventID = eventIDs[res]; } void EventTriggered::arm() { Event* e = getTargetEventName(); if ( e ) e->executed.connect( SigC::slot( *this, &EventTriggered::triggered)); } void EventTriggered::triggered() { state( -1 ); eventReady(); } EventTrigger::State AllEnemyUnitsDestroyed::getState( int player ) { for ( int i = 0; i < 8; i++ ) if ( getdiplomaticstatus2( player*8, i*8 ) != capeace ) if ( !gamemap->player[i].vehicleList.empty() ) return unfulfilled; return fulfilled; } ASCString AllEnemyUnitsDestroyed::getName() const { return "All enemy units destroyed"; } void AllEnemyUnitsDestroyed::arm() { ContainerBase::anyContainerDestroyed.connect( SigC::slot( *this, &AllEnemyUnitsDestroyed::triggered)); } void AllEnemyUnitsDestroyed::triggered() { if ( isFulfilled() ) eventReady(); } EventTrigger::State AllEnemyBuildingsDestroyed::getState( int player ) { for ( int i = 0; i < 8; i++ ) if ( getdiplomaticstatus2( player*8, i*8 ) != capeace ) if ( !gamemap->player[i].buildingList.empty() ) return unfulfilled; return fulfilled; } ASCString AllEnemyBuildingsDestroyed::getName() const { return "All enemy buildings destroyed"; } void AllEnemyBuildingsDestroyed::arm() { ContainerBase::anyContainerDestroyed.connect( SigC::slot( *this, &AllEnemyBuildingsDestroyed::triggered)); } void AllEnemyBuildingsDestroyed::triggered() { if ( isFulfilled() ) eventReady(); } EventTrigger::State SpecificUnitEntersPolygon::getState( int player ) { found = false; operate(); if ( found ) return fulfilled; else return unfulfilled; } void SpecificUnitEntersPolygon::fieldOperator( const MapCoordinate& mc ) { pfield fld = gamemap->getField ( mc ); if ( !arming ) { if ( fld && fld->vehicle ) if ( fld->vehicle->networkid == unitID || unitID == -1 ) found = true; Vehicle* veh = gamemap->getUnit( unitID ); if ( veh ) if ( mc.x == veh->getPosition().x && mc.y == veh->getPosition().y ) found = true; } else fld->connection |= cconnection_areaentered_specificunit; } void SpecificUnitEntersPolygon::readData ( tnstream& stream ) { stream.readInt(); readMapModificationData( stream ); unitID = stream.readInt(); } void SpecificUnitEntersPolygon::writeData ( tnstream& stream ) { stream.writeInt(1); writeMapModificationData( stream ); stream.writeInt( unitID ); } ASCString SpecificUnitEntersPolygon::getName() const { ASCString s; if ( unitID > 0 && gamemap->getUnit( unitID )) { s = "unit "; s += gamemap->getUnit( unitID )->getName(); } else s = "any unit"; s += " enters polygon"; return s; } void SpecificUnitEntersPolygon::setup() { FieldAddressing::setup(); unitID = selectunit ( unitID ); } void SpecificUnitEntersPolygon::arm () { #ifdef sgmain arming = true; operate(); arming = false; fieldCrossed.connect( SigC::slot( *this, &SpecificUnitEntersPolygon::triggered)); Vehicle* veh = gamemap->getUnit( unitID ); if ( veh ) veh->connection |= cconnection_areaentered_specificunit; #endif } void SpecificUnitEntersPolygon::triggered() { if ( isFulfilled() ) eventReady(); } EventTrigger::State AnyUnitEntersPolygon::getState( int player ) { found = false; operate(); if ( found ) return finally_fulfilled; else return unfulfilled; } void AnyUnitEntersPolygon::fieldOperator( const MapCoordinate& mc ) { pfield fld = gamemap->getField ( mc ); if ( !arming ) { if ( fld && fld->vehicle ) if ( (1 << fld->vehicle->getOwner()) & player ) found = true; if ( fld && fld->building ) for ( int i = 0; i < 32; ++i ) if ( fld->building->loading[i] ) if ( (1 << fld->building->loading[i]->getOwner()) & player ) found = true; } else { fld->connection |= cconnection_areaentered_anyunit; } } void AnyUnitEntersPolygon::readData ( tnstream& stream ) { stream.readInt(); readMapModificationData( stream ); player = stream.readInt(); } void AnyUnitEntersPolygon::writeData ( tnstream& stream ) { stream.writeInt(1); writeMapModificationData( stream ); stream.writeInt( player ); } ASCString AnyUnitEntersPolygon::getName() const { ASCString s = "any unit from "; for ( int i = 0; i < 8; ++i ) if ( player & ( 1 << i)) { s += gamemap->player[i].getName(); s += " "; } s += " enters polygon"; return s; } void AnyUnitEntersPolygon::setup() { FieldAddressing::setup(); playerselall( &player ); } void AnyUnitEntersPolygon::arm() { #ifdef sgmain arming = true; operate(); arming = false; fieldCrossed.connect( SigC::slot( *this, &AnyUnitEntersPolygon::triggered)); #endif } void AnyUnitEntersPolygon::triggered() { if ( isFulfilled() ) eventReady(); } EventTrigger::State ResourceTribute::getState( int player ) { if ( payingPlayer < 0 || gamemap->tribute.avail[payingPlayer][player] + gamemap->tribute.paid[player][payingPlayer] < demand ) return unfulfilled; else return finally_fulfilled; } void ResourceTribute::readData ( tnstream& stream ) { stream.readInt(); payingPlayer = stream.readInt(); demand.read ( stream ); } void ResourceTribute::writeData ( tnstream& stream ) { stream.writeInt( 1 ); stream.writeInt( payingPlayer ); demand.write ( stream ); } ASCString ResourceTribute::getName() const { ASCString s; s.format ( "Resource tribute: %d E ; %d M ; %d F", demand.energy, demand.material, demand.fuel ); return s; } void ResourceTribute::setup() { payingPlayer = editInt( "Paying Player", payingPlayer ); demand.energy = editInt( "energy", demand.energy ); demand.material = editInt( "material", demand.material ); demand.fuel = editInt( "fuel", demand.fuel ); } void ResourceTribute::arm() { #ifdef sgmain tributeTransferred.connect( SigC::slot( *this, &ResourceTribute::triggered)); #endif } void ResourceTribute::triggered() { if ( isFulfilled() ) eventReady(); } ///////////////////////////////////////////////////////////////////////////// // Actions void Action_Nothing::readData( tnstream& stream ) { stream.readInt(); } void Action_Nothing::writeData( tnstream& stream ) { stream.writeInt(1); } ASCString EventAction::getName() { return EventActionName[actionID]; } void WindChange::execute( MapDisplayInterface* md ) { if ( speed != -1 ) gamemap->weather.windSpeed = speed; if ( direction != -1 ) gamemap->weather.windDirection = direction; resetallbuildingpicturepointers(); if ( md ) md->updateDashboard(); } void WindChange::readData( tnstream& stream ) { int version = stream.readInt(); speed = stream.readInt(); direction = stream.readInt(); } void WindChange::writeData( tnstream& stream ) { stream.writeInt(1); stream.writeInt( speed ); stream.writeInt( direction ); } void WindChange::setup() { speed = editInt("Wind Speed", speed, 0, 255); direction = editInt("Wind Direction", direction, 0, 5); } void ChangeGameParameter::execute( MapDisplayInterface* md ) { if ( parameterNum >= 0 ) if ( gameParameterChangeableByEvent [ parameterNum ] ) gamemap->setgameparameter( GameParameter(parameterNum) , parameterValue ); } void ChangeGameParameter::readData( tnstream& stream ) { int version = stream.readInt(); parameterNum = stream.readInt(); parameterValue = stream.readInt(); } void ChangeGameParameter::writeData( tnstream& stream ) { stream.writeInt(1); stream.writeInt( parameterNum ); stream.writeInt( parameterValue ); } void ChangeGameParameter::setup() { int nr = selectgameparameter( parameterNum ); if ( (nr >= 0) && ( nr < gameparameternum) ) { if ( gameParameterChangeableByEvent[ nr ] ) { int org = parameterValue; if ( org < gameParameterLowerLimit[nr] && org > gameParameterUpperLimit[nr] ) org = gameparameterdefault[nr]; parameterValue = getid("Parameter Val", org, gameParameterLowerLimit[nr], gameParameterUpperLimit[nr]); parameterNum = nr; } else displaymessage("This parameter cannot be changed by events",1); } } void DisplayMessage::execute( MapDisplayInterface* md ) { viewtextmessage ( messageNum , gamemap->actplayer ); } void DisplayMessage::readData( tnstream& stream ) { int version = stream.readInt(); messageNum = stream.readInt(); } void DisplayMessage::writeData( tnstream& stream ) { stream.writeInt(1); stream.writeInt( messageNum ); } void DisplayMessage::setup() { messageNum = editInt ( "Message ID", messageNum ); } void FieldAddressing::setpointabs ( int x, int y ) { fieldOperator ( MapCoordinate(x,y) ); } void FieldAddressing::operate ( ) { if ( addressingMode == singleField ) { for ( Fields::iterator i = fields.begin(); i != fields.end(); ++i ) fieldOperator ( *i ); } if ( addressingMode == poly ) { for ( Polygons::iterator i = polygons.begin(); i != polygons.end(); ++i ) paintPolygon ( *i ); } if ( addressingMode == global ) { for ( int y = 0; y < gameMap->ysize; ++y ) for ( int x = 0; x < gameMap->xsize; ++x ) fieldOperator ( MapCoordinate ( x, y )); } } void FieldAddressing::setField ( const MapCoordinate& pos ) { addressingMode = singleField; fields.clear(); fields.push_back ( pos ); } void FieldAddressing::setPolygon ( const Poly_gon& poly_gon ) { addressingMode = poly; polygons.clear(); polygons.push_back ( poly_gon ); } void FieldAddressing::setGlobal() { addressingMode = global; } void FieldAddressing::readMapModificationData ( tnstream& stream ) { int version = stream.readInt(); addressingMode = AddressingMode ( stream.readInt() ); if ( addressingMode == singleField ) readClassContainer( fields, stream ); if ( addressingMode == poly ) readClassContainer( polygons, stream ); } void FieldAddressing::setup () { vector entries; entries.push_back ( "none" ); entries.push_back ( "Single Fields"); entries.push_back ( "Polygons" ); entries.push_back ( "global"); int c = chooseString ( "choose operation target", entries, addressingMode ); if ( c < 0 ) return; addressingMode = AddressingMode( c ); switch ( addressingMode ) { case singleField: selectFields( fields ); break; case poly: if ( !polygons.size() ) polygons.push_back ( Poly_gon() ); editpolygon ( polygons[0] ); break; } } void FieldAddressing::writeMapModificationData ( tnstream& stream ) { stream.writeInt( 1000 ); stream.writeInt ( addressingMode ); if ( addressingMode == singleField ) writeClassContainer ( fields, stream ); if ( addressingMode == poly ) writeClassContainer ( polygons, stream ); } void MapModificationEvent::execute( MapDisplayInterface* md ) { operate(); if ( md ) { md->displayMap(); md->updateDashboard(); } } void WeatherChange :: readData ( tnstream& stream ) { int version = stream.readInt(); weather = stream.readInt(); readMapModificationData ( stream ); } void WeatherChange :: writeData ( tnstream& stream ) { stream.writeInt( 1 ); stream.writeInt( weather ); writeMapModificationData ( stream ); } void WeatherChange :: fieldOperator( const MapCoordinate& mc ) { pfield field = gamemap->getField ( mc ); if ( field ) { if ( field->typ->terraintype->weather[ weather ] ) field->typ = field->typ->terraintype->weather[ weather ]; else field->typ = field->typ->terraintype->weather[ 0 ]; field->setparams(); } } void WeatherChange :: setup () { FieldAddressing::setup(); chooseWeather( weather ); } void MapChange :: readData ( tnstream& stream ) { int version = stream.readInt(); terrainID = stream.readInt(); readMapModificationData ( stream ); } void MapChange :: writeData ( tnstream& stream ) { stream.writeInt( 1 ); stream.writeInt( terrainID ); writeMapModificationData ( stream ); } void MapChange :: fieldOperator( const MapCoordinate& mc ) { TerrainType* typ = terrainTypeRepository.getObject_byID ( terrainID ); if ( !typ ) return; pfield field = gamemap->getField ( mc ); if ( field ) { int w = field->getweather(); if (typ->weather[w] == NULL) w = 0; field->typ = typ->weather[ w ]; field->setparams(); } } void MapChange :: setup () { FieldAddressing::setup(); chooseTerrain( terrainID ); } void AddObject :: readData ( tnstream& stream ) { int version = stream.readInt(); objectID = stream.readInt(); readMapModificationData ( stream ); } void AddObject :: writeData ( tnstream& stream ) { stream.writeInt( 1 ); stream.writeInt( objectID ); writeMapModificationData ( stream ); } void AddObject :: fieldOperator( const MapCoordinate& mc ) { ObjectType* obj = objectTypeRepository.getObject_byID ( objectID ); if ( !obj ) return; pfield field = gamemap->getField ( mc ); if ( field ) { field->addobject ( obj, -1, true ); field->setparams(); } } void AddObject :: setup () { FieldAddressing::setup(); chooseObject( objectID ); } void RemoveAllObjects :: readData ( tnstream& stream ) { int version = stream.readInt(); readMapModificationData ( stream ); } void RemoveAllObjects :: writeData ( tnstream& stream ) { stream.writeInt( 1 ); writeMapModificationData ( stream ); } void RemoveAllObjects :: fieldOperator( const MapCoordinate& mc ) { pfield field = gamemap->getField ( mc ); if ( field ) { field->objects.clear(); field->setparams(); } } void RemoveAllObjects :: setup () { FieldAddressing::setup(); } void MapChangeCompleted :: execute( MapDisplayInterface* md ) { checkobjectsforremoval(); checkunitsforremoval (); if ( md ) { md->displayMap(); md->updateDashboard(); } } void ChangeBuildingDamage::readData ( tnstream& stream ) { int version = stream.readInt(); damage = stream.readInt(); position.read ( stream ); } void ChangeBuildingDamage::writeData ( tnstream& stream ) { stream.writeInt( 1); stream.writeInt( damage ); position.write ( stream ); } void ChangeBuildingDamage::execute( MapDisplayInterface* md ) { pfield fld = gamemap->getField ( position ); if ( fld && fld->building ) { if ( damage >= 100 ) { delete fld->building; fld->building = NULL; if ( md ) { md->displayMap(); md->updateDashboard(); } } else { fld->building->damage = damage; if ( md ) md->updateDashboard(); } } } void ChangeBuildingDamage::setup() { getxy_building ( &position.x, &position.y ); damage = editInt("new building damage", damage, 0, 100); } void NextMap::readData ( tnstream& stream ) { int version = stream.readInt(); mapID = stream.readInt(); } void NextMap::writeData ( tnstream& stream ) { stream.writeInt( 1); stream.writeInt( mapID ); } void NextMap::execute( MapDisplayInterface* md ) { throw LoadNextMap(mapID); } void NextMap::setup() { mapID = editInt("ID of next map", mapID, 0, maxint); } void LoseMap::execute( MapDisplayInterface* md ) { if ( !gamemap->continueplaying ) { displaymessage ( "You have been defeated !", 3 ); delete gamemap; gamemap = NULL; throw NoMapLoaded(); } } void DisplayEllipse::readData ( tnstream& stream ) { int version = stream.readInt(); x1 = stream.readInt(); x2 = stream.readInt(); y1 = stream.readInt(); y2 = stream.readInt(); alignRight = stream.readInt(); alignBottom = stream.readInt(); } void DisplayEllipse::writeData ( tnstream& stream ) { stream.writeInt( 1 ); stream.writeInt( x1 ); stream.writeInt( x2 ); stream.writeInt( y1 ); stream.writeInt( y2 ); stream.writeInt( alignRight ); stream.writeInt( alignBottom ); } void DisplayEllipse::execute( MapDisplayInterface* md ) { if ( !gamemap->ellipse ) gamemap->ellipse = new EllipseOnScreen; if ( alignRight ) { // x orientation gamemap->ellipse->x1 = agmp->resolutionx - ( 640 - x1 ); gamemap->ellipse->x2 = agmp->resolutionx - ( 640 - x2 ); } else { gamemap->ellipse->x1 = x1; gamemap->ellipse->x2 = x2; } if ( alignBottom ) { // y orientation gamemap->ellipse->y1 = agmp->resolutiony - ( 480 - y1 ); gamemap->ellipse->y2 = agmp->resolutiony - ( 480 - y2 ); } else { gamemap->ellipse->y1 = y1; gamemap->ellipse->y2 = y2; } gamemap->ellipse->color = white; gamemap->ellipse->precision = 0.15; gamemap->ellipse->active = 1; if ( md ) md->updateDashboard(); } void DisplayEllipse::setup() { x1 = getid("x1",x1,0,639); y1 = getid("y1",y1,0,479); x2 = getid("x2",x2,0,639); y2 = getid("y2",y2,0,479); alignRight = choice_dlg("x orientation","~l~eft","~r~ight") - 1; alignBottom = choice_dlg("y orientation","~t~op","~b~ottom") - 1; } void RemoveEllipse::execute( MapDisplayInterface* md ) { if ( gamemap->ellipse ) { gamemap->ellipse->active = 0; if ( md ) md->repaintDisplay(); } } void ChangeBuildingOwner :: readData ( tnstream& stream ) { int version = stream.readInt(); pos.read( stream ); newOwner = stream.readInt(); } void ChangeBuildingOwner :: writeData ( tnstream& stream ) { stream.writeInt( 1 ); pos.write( stream ); stream.writeInt ( newOwner ); } void ChangeBuildingOwner :: setup () { getxy_building( &pos.x, &pos.y ); newOwner = getid("new owner",newOwner,0,8); } void ChangeBuildingOwner :: execute( MapDisplayInterface* md ) { pfield fld = gamemap->getField ( pos ); if ( fld && fld->building ) { fld->building->convert ( newOwner ); #ifdef sgmain evaluateviewcalculation ( gamemap ); #endif if ( md ) { md->displayMap(); md->updateDashboard(); } } } void DisplayImmediateMessage::execute( MapDisplayInterface* md ) { if ( !message.empty() ) { new Message ( message, gamemap, 1 << gamemap->actplayer ); #ifdef sgmain viewunreadmessages ( ); #endif } } void DisplayImmediateMessage::readData( tnstream& stream ) { int version = stream.readInt(); message = stream.readString(); } void DisplayImmediateMessage::writeData( tnstream& stream ) { stream.writeInt(1); stream.writeString( message ); } void DisplayImmediateMessage::setup() { MultilineEdit mle ( message, "Message" ); mle.init(); mle.run(); mle.done(); } void AddProductionCapability :: readData ( tnstream& stream ) { int version = stream.readInt(); pos.read( stream ); vehicleTypeID = stream.readInt(); } void AddProductionCapability :: writeData ( tnstream& stream ) { stream.writeInt( 1 ); pos.write( stream ); stream.writeInt ( vehicleTypeID ); } void AddProductionCapability :: setup () { getxy_building( &pos.x, &pos.y ); chooseVehicleType( vehicleTypeID ); } void AddProductionCapability :: execute( MapDisplayInterface* md ) { pfield fld = gamemap->getField ( pos ); if ( fld && fld->building && vehicleTypeID >= 0 ) { int i = 0; while ( i < 32 && fld->building->production[i] ) ++i; if ( i < 32 && !fld->building->production[i] ) fld->building->production[i] = gamemap->getvehicletype_byid(vehicleTypeID); } } void ChangeDiplomaticStatus :: readData ( tnstream& stream ) { int version = stream.readInt(); proposingPlayer = stream.readInt(); targetPlayer = stream.readInt(); proposal = Proposal(stream.readInt()); } void ChangeDiplomaticStatus :: writeData ( tnstream& stream ) { stream.writeInt( 1 ); stream.writeInt ( proposingPlayer ); stream.writeInt ( targetPlayer ); stream.writeInt ( proposal ); } void ChangeDiplomaticStatus :: setup () { proposingPlayer = editInt("Announcing Player",proposingPlayer,0,7); targetPlayer = editInt("Receiving Player",targetPlayer,0,7); vector list; list.push_back ( "Propose Peace"); list.push_back ( "Declare War"); list.push_back ( "Sneak Attack"); proposal = Proposal ( chooseString ( "Action", list, proposal )); } void ChangeDiplomaticStatus :: execute( MapDisplayInterface* md ) { if ( proposal == Peace ) gamemap->alliances[targetPlayer][proposingPlayer] = capeaceproposal; else if ( proposal == War ) gamemap->alliances[targetPlayer][proposingPlayer] = cawarannounce; else { gamemap->alliances[targetPlayer][proposingPlayer] = canewsetwar2; } } void SetViewSharing :: readData ( tnstream& stream ) { int version = stream.readInt(); viewingPlayer = stream.readInt(); providingPlayer = stream.readInt(); enable = stream.readInt(); } void SetViewSharing :: writeData ( tnstream& stream ) { stream.writeInt( 1 ); stream.writeInt ( viewingPlayer ); stream.writeInt ( providingPlayer ); stream.writeInt ( enable ); } void SetViewSharing :: setup () { viewingPlayer = editInt("Viewing Player",viewingPlayer,0,7); providingPlayer = editInt("Providing Player",providingPlayer,0,7); vector list; list.push_back ( "Disable View Sharing"); list.push_back ( "Enable View Sharing"); enable = chooseString ( "Action", list, enable ); } void SetViewSharing :: execute( MapDisplayInterface* md ) { if ( !gamemap->shareview ) gamemap->shareview = new tmap::Shareview; if ( enable ) gamemap->shareview->mode[providingPlayer][viewingPlayer] = true; else gamemap->shareview->mode[providingPlayer][viewingPlayer] = false; #ifdef sgmain computeview( gamemap ); #endif if ( md ) { md->displayMap(); md->updateDashboard(); } } void AddResources :: readData ( tnstream& stream ) { int version = stream.readInt(); res.read( stream ); pos.read( stream ); } void AddResources :: writeData ( tnstream& stream ) { stream.writeInt( 1 ); res.write( stream ); pos.write( stream ); } void AddResources :: setup () { getxy_building( &pos.x, &pos.y ); res.energy = editInt("Energy",res.energy,minint); res.material = editInt("Material",res.material,minint); res.fuel = editInt("Fuel",res.fuel ,minint); } void AddResources :: execute( MapDisplayInterface* md ) { pfield fld = gamemap->getField ( pos ); if ( fld && fld->building ) fld->building->putResource( res, 0 ); } void Reinforcements :: readData ( tnstream& stream ) { int version = stream.readInt(); objectNum = stream.readInt(); buf.readfromstream ( &stream ); } void Reinforcements :: writeData ( tnstream& stream ) { stream.writeInt( 1 ); stream.writeInt( objectNum ); buf.writetostream ( &stream ); } void Reinforcements :: setup () { vector list; list.push_back ( "Append units / buildings"); list.push_back ( "Reposition and reselect units / buildings"); list.push_back ( "Clear buffer and select other units / buildings"); int i = chooseString ( "Choose Action", list, 0 ); if ( i == 2 ){ buf.clear(); objectNum = 0; } if ( i == 1 ){ execute( NULL ); buf.clear(); objectNum = 0; } displaymessage("use space to select the units/buildings\nfinish the selection by pressing enter",3); int res; do { int x,y; res = selectfield(&x,&y); if ( res == 2 ) { pfield fld = gamemap->getField ( x, y ); if ( fld->vehicle ) { tmemorystream stream ( &buf, tnstream::appending ); stream.writeInt( ReinfVehicle ); fld->vehicle->write ( stream ); objectNum++; delete fld->vehicle; fld->vehicle = NULL; } else if ( fld->building ) { tmemorystream stream ( &buf, tnstream::appending ); stream.writeInt( ReinfBuilding ); fld->building->write ( stream ); objectNum++; delete fld->building; fld->building = NULL; } } } while ( res == 2 ); /* enddo */ } class FindUnitPlacementPos : public SearchFields { Vehicle* vehicle; public: FindUnitPlacementPos ( pmap gamemap, Vehicle* veh ) : SearchFields ( gamemap ), vehicle(veh) { initsearch(MapCoordinate(veh->xpos, veh->ypos),0,10); startsearch(); }; void testfield ( const MapCoordinate& pos ) { pfield fld = gamemap->getField( pos ); if ( fld && !fld->vehicle ) { if ( fieldAccessible( fld, vehicle, -2, NULL, true ) == 2 ) { fld->vehicle = vehicle; fld->vehicle->setnewposition ( pos ); fld->vehicle->addview(); cancelSearch = true; } } }; }; void Reinforcements :: execute( MapDisplayInterface* md ) { int cnt = 0; tmemorystream stream ( &buf, tnstream::reading ); while ( cnt < objectNum ) { Type type = Type(stream.readInt()); if ( type == ReinfVehicle ) { try { Vehicle* veh = Vehicle::newFromStream( gamemap, stream, ++gamemap->unitnetworkid ); FindUnitPlacementPos fupp( gamemap, veh ); } catch ( InvalidID err ) { displaymessage( "Error executing event 'Reinforcements'\n" + err.getMessage(), 1); throw ShutDownMap(); } } if ( type == ReinfBuilding ) { Building* bld = Building::newFromStream ( gamemap, stream ); #if 0 MapCoordinate pos = bld->getPosition(); for ( int x = 0; x < 4; x++ ) for ( int y = 0; y < 6; y++ ) if ( bld->typ->getpicture ( BuildingType::LocalCoordinate( x , y ) )) { pfield field = gamemap->getField( bld->typ->getFieldCoordinate( pos, BuildingType::LocalCoordinate( x, y) )); if ( !field ) { delete bld; // displaymessage("building does not fit here", 1 ); return; } /* if ( !bld->typ->terrainaccess.accessible ( field->bdt ) ) { delete bld; displaymessage("building does can not be build here", 1 ); return; } */ if ( field->vehicle ) { delete field->vehicle; field->vehicle = NULL; } if ( field->building ) { delete field->building; field->building = NULL; } } bld->chainbuildingtofield( pos ); #endif bld->resetPicturePointers (); gamemap->calculateAllObjects(); bld->addview(); } ++cnt; } #ifdef sgmain evaluateviewcalculation ( gamemap ); // computeview ( gamemap ); #endif if ( md ) { md->displayMap(); md->updateDashboard(); } } namespace { const bool r1 = triggerFactory::Instance().registerClass( Trigger_TurnPassed, ObjectCreator ); const bool r2 = triggerFactory::Instance().registerClass( Trigger_UnitLost, ObjectCreator ); const bool r3 = triggerFactory::Instance().registerClass( Trigger_UnitConquered, ObjectCreator ); const bool r4 = triggerFactory::Instance().registerClass( Trigger_UnitDestroyed, ObjectCreator ); const bool r5 = triggerFactory::Instance().registerClass( Trigger_AllBuildingsLost, ObjectCreator ); const bool r6 = triggerFactory::Instance().registerClass( Trigger_AllUnitsLost, ObjectCreator ); const bool r7 = triggerFactory::Instance().registerClass( Trigger_NothingFalse, ObjectCreator ); const bool r8 = triggerFactory::Instance().registerClass( Trigger_NothingTrue , ObjectCreator ); const bool r9 = triggerFactory::Instance().registerClass( Trigger_BuildingConquered,ObjectCreator ); const bool r10= triggerFactory::Instance().registerClass( Trigger_BuildingLost, ObjectCreator ); const bool r11= triggerFactory::Instance().registerClass( Trigger_BuildingDestroyed,ObjectCreator ); const bool r12= triggerFactory::Instance().registerClass( Trigger_BuildingSeen, ObjectCreator ); const bool r13= triggerFactory::Instance().registerClass( Trigger_EventTriggered, ObjectCreator ); const bool r14= triggerFactory::Instance().registerClass( Trigger_AllEnemyBuildingsDestroyed, ObjectCreator ); const bool r15= triggerFactory::Instance().registerClass( Trigger_AllEnemyUnitsDestroyed, ObjectCreator ); const bool r16= triggerFactory::Instance().registerClass( Trigger_SpecificUnitEntersPolygon,ObjectCreator ); const bool r17= triggerFactory::Instance().registerClass( Trigger_AnyUnitEntersPolygon,ObjectCreator ); const bool r18= triggerFactory::Instance().registerClass( Trigger_ResourceTribute, ObjectCreator ); const bool s0 = actionFactory::Instance().registerClass( EventAction_Nothing, ObjectCreator ); const bool s1 = actionFactory::Instance().registerClass( EventAction_DisplayMessage, ObjectCreator ); const bool s2 = actionFactory::Instance().registerClass( EventAction_WindChange, ObjectCreator ); const bool s3 = actionFactory::Instance().registerClass( EventAction_ChangeGameParameter, ObjectCreator ); const bool s4 = actionFactory::Instance().registerClass( EventAction_WeatherChange, ObjectCreator ); const bool s5 = actionFactory::Instance().registerClass( EventAction_MapChange, ObjectCreator ); const bool s6 = actionFactory::Instance().registerClass( EventAction_AddObject, ObjectCreator ); const bool s7 = actionFactory::Instance().registerClass( EventAction_MapChangeCompleted, ObjectCreator ); const bool s8 = actionFactory::Instance().registerClass( EventAction_ChangeBuildingDamage, ObjectCreator ); const bool s9 = actionFactory::Instance().registerClass( EventAction_NextMap, ObjectCreator ); const bool s10 = actionFactory::Instance().registerClass( EventAction_LoseMap, ObjectCreator ); const bool s11 = actionFactory::Instance().registerClass( EventAction_DisplayEllipse, ObjectCreator ); const bool s12 = actionFactory::Instance().registerClass( EventAction_RemoveEllipse, ObjectCreator ); const bool s13 = actionFactory::Instance().registerClass( EventAction_ChangeBuildingOwner, ObjectCreator ); const bool s14 = actionFactory::Instance().registerClass( EventAction_RemoveAllObjects, ObjectCreator ); const bool s15 = actionFactory::Instance().registerClass( EventAction_DisplayImmediateMessage, ObjectCreator ); const bool s16 = actionFactory::Instance().registerClass( EventAction_AddProductionCapabiligy, ObjectCreator ); const bool s17 = actionFactory::Instance().registerClass( EventAction_ChangeDiplomaticStatus, ObjectCreator ); const bool s18 = actionFactory::Instance().registerClass( EventAction_AddResources, ObjectCreator ); const bool s19 = actionFactory::Instance().registerClass( EventAction_Reinforcements, ObjectCreator ); const bool s20 = actionFactory::Instance().registerClass( EventAction_SetViewSharing, ObjectCreator ); };