/*************************************************************************** resourcenet.cpp - description ------------------- begin : Tue Jan 28 2001 copyright : (C) 2001 by Martin Bickel email : bickel@asc-hq.org ***************************************************************************/ /*! \file resourcenet.cpp \brief Handling the connection of buildings by pipelines, powerlines etc. */ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #include "typen.h" #include "vehicletype.h" #include "buildingtype.h" #include "spfst.h" #include "resourcenet.h" #include "mapalgorithms.h" #include "dlg_box.h" #include "dialog.h" SigC::Signal0 tributeTransferred; void MapNetwork :: searchfield ( int x, int y, int dir ) { int s; pfield fld = actmap->getField ( x, y ); if ( !fld ) return; int arr[sidenum]; do { if ( fld->a.temp ) return; #ifdef netdebug cursor.gotoxy ( a, b ); displaymap(); #endif if ( fld->building ) { searchbuilding ( x, y ); return; } fld->a.temp = 1; int d = fieldavail( x, y ); if ( d <= 0 ) return; searchvehicle ( x, y ); int olddir = dir + sidenum/2; while (olddir >= sidenum ) olddir -= sidenum; int r = 0; for (s = 0; s < sidenum; s++) { if ( (d & (1 << s)) && ( s != olddir )) { arr[ r ] = s; r++; } } if (r > 1) { // Kreuzungsstelle for ( s = 0; s < r; s++) { int nx = x; int ny = y; getnextfield ( nx, ny, arr[s] ); searchfield( nx, ny, arr[s] ); if ( searchfinished() ) return ; } return; } else if ( r == 1 ) { dir = arr[0]; getnextfield ( x, y, dir ); fld = actmap->getField( x, y ); if ( !fld ) return; } else return; } while ( 1 ); } void MapNetwork :: searchvehicle ( int x, int y ) { if ( pass == 2 ) { pfield newfield = actmap->getField ( x, y ); if ( newfield ) if ( !newfield->a.temp2 ) if ( newfield->vehicle ) { checkvehicle ( newfield->vehicle ); newfield->a.temp2 = 1; } } } void MapNetwork :: searchbuilding ( int x, int y ) { pbuilding bld = actmap->getField( x, y )->building; if ( !bld ) return; pfield entry = bld->getEntryField(); if ( entry->a.temp ) return; if ( pass == 1 ) checkbuilding( bld ); entry->a.temp = 1; if ( !searchfinished() ) for( int i = 0; i < 4; i++ ) for ( int j = 0; j < 6; j++ ) { MapCoordinate mc = bld->getFieldCoordinates ( BuildingType::LocalCoordinate(i, j) ); pfield fld2 = actmap->getField ( mc ); if ( fld2 && fld2->building == bld ) for ( int d = 0; d < sidenum; d++ ) { int xp2 = mc.x; int yp2 = mc.y; getnextfield ( xp2, yp2, d ); pfield newfield = actmap->getField ( xp2, yp2 ); if ( newfield && newfield->building != bld && !newfield->a.temp ) searchfield ( xp2, yp2, d ); searchvehicle ( xp2, yp2 ); } /* endfor */ } } int MapNetwork :: instancesrunning = 0; MapNetwork :: MapNetwork ( pmap gamemap, int checkInstances ) : actmap ( gamemap ) { if ( checkInstances ) { if ( instancesrunning ) displaymessage(" fatal error at MapNetwork; there are other running instances ", 2 ); } // else displaymessage("warning: Mapnetwork instance check disabled !", 1 ); // this could be resolved by using the different bits of field->a.temp instancesrunning++; pass = 1; } MapNetwork :: ~MapNetwork () { instancesrunning--; } void MapNetwork :: searchAllVehiclesNextToBuildings ( int player ) { pass++; for ( tmap::Player::VehicleList::iterator j = actmap->player[player].vehicleList.begin(); j != actmap->player[player].vehicleList.end(); j++ ) { MapCoordinate3D mc = (*j)->getPosition(); for ( int s = 0; s < sidenum; s++ ) { pfield fld = actmap->getField ( getNeighbouringFieldCoordinate ( mc, s )); if ( fld ) { pbuilding bld = fld->building; if ( bld && bld->color == (*j)->color ) { pfield fld2 = actmap->getField( (*j)->getPosition()); if ( !fld2->a.temp2 ) { fld2->a.temp2 = 1; checkvehicle ( *j ); } } } } } } void MapNetwork :: start ( int x, int y ) { if ( globalsearch() == 2 ) { for ( int i = 0; i < 8; i++ ) if ( actmap->player[i].exist() ) { for ( tmap::Player::BuildingList::iterator j = actmap->player[i].buildingList.begin(); j != actmap->player[i].buildingList.end(); j++ ) checkbuilding(*j); // if ( !searchfinished() ) actmap->cleartemps(7); searchAllVehiclesNextToBuildings ( i ); actmap->cleartemps(7); } } else if ( globalsearch() == 1 ) { actmap->cleartemps(7); startposition.x = x; startposition.y = y; searchfield ( x, y, -1 ); actmap->cleartemps(7); if ( !searchfinished() ) { pass++; startposition.x = x; startposition.y = y; searchfield ( x, y, -1 ); actmap->cleartemps(7); } } else if ( globalsearch() == 0 ) { pfield fld = actmap->getField ( x, y ); if ( fld ) if ( fld->building ) { if ( pass == 1 ) checkbuilding( fld->building ); } else if ( fld->vehicle ) if ( pass == 2 ) checkvehicle ( fld->vehicle ); } } int ResourceNet :: fieldavail ( int x, int y ) { pfield fld = actmap->getField ( x, y ); /* pobject o = fld->checkforobject ( pipelineobject ) ; if ( o ) return o->dir; else */ if ( fld ) { TerrainBits tb = getTerrainBitType(cbpipeline); assert( resourcetype >= 0 ); if ( resourcetype == 0) tb |= getTerrainBitType(cbpowerline); if ( (fld->bdt & tb).any() ) { int d = 0; for ( int i = 0; i < sidenum; i++ ) { int xp = x; int yp = y; getnextfield ( xp, yp , i ); pfield fld2 = actmap->getField ( xp, yp ); if ( fld2 ) if ( (fld2->bdt & tb).any() || fld2->building ) d |= ( 1 << i ); } return d; } else return 0; } return 0; } int StaticResourceNet :: getresource ( int x, int y, int resource, int _need, int _queryonly, int _player, int _scope ) { if ( actmap->isResourceGlobal ( resource )) scope = 3; else scope = _scope; player = _player; resourcetype = resource; got = 0; need = _need; queryonly = _queryonly; if (scope == 3 && player == 8 ) // neutral player has no map-wide pool scope = 0; start ( x , y ); return got; } int StaticResourceNet :: searchfinished ( void ) { return got >= need; } GetResource :: GetResource ( pmap gamemap, int scope ) : StaticResourceNet ( gamemap, scope ) { memset ( tributegot, 0, sizeof ( tributegot )); } void GetResource :: checkvehicle ( pvehicle v ) { if ( v->color/8 == player && resourcetype == 0 ) got += v->getResource( need-got, Resources::Energy, queryonly ); } void GetResource :: checkbuilding ( pbuilding b ) { if ( b->color/8 == player ) { if ((b->netcontrol & (cnet_stopenergyoutput << resourcetype)) == 0) { int toget = need-got; if ( b->actstorage.resource( resourcetype ) < 0 ) { displaymessage("map corruption detected; building %s storage for %d/%d is negative!",1,resourceNames[resourcetype],b->getEntry().x, b->getEntry().y ); b->actstorage.resource( resourcetype ) = 0; } if ( b->actstorage.resource( resourcetype ) < toget ) toget = b->actstorage.resource( resourcetype ); if ( !queryonly ) b->actstorage.resource( resourcetype ) -= toget; got += toget; } } else if ( b->color/8 < 8 ) { // no neutral buildings // Codeguard reports "Pointer arithmetic in invalid memory". Whats wrong here ? // Resources tttt = actmap->tribute.avail[ b->color / 8 ][ player ]; int gettable = actmap->tribute.avail[ b->color / 8 ][ player ].resource(resourcetype) - tributegot[ resourcetype ][ b->color / 8]; if ( gettable > 0 ) { int toget = need-got; if ( toget > gettable ) toget = gettable; // int found = b->getResource( toget, resourcetype, queryonly ); int found = b->actstorage.resource(resourcetype); if ( toget < found ) found = toget; if ( !queryonly ) b->actstorage.resource(resourcetype) -= found; tributegot[ resourcetype ][ b->color / 8] += found; if ( !queryonly ) { actmap->tribute.avail[ b->color / 8 ][ player ].resource( resourcetype ) -= found; actmap->tribute.paid [ player ][ b->color / 8 ].resource( resourcetype ) += found; if ( found ) tributeTransferred(); } got += found; } } } void GetResource :: start ( int x, int y ) { if ( scope == 3 ) { got = need; if ( got > actmap->bi_resource[player].resource( resourcetype ) ) got = actmap->bi_resource[player].resource( resourcetype ); if ( !queryonly ) actmap->bi_resource[player].resource( resourcetype ) -= got; if ( resourcetype == 0 ) searchAllVehiclesNextToBuildings ( player ); } else MapNetwork :: start ( x, y ); } void PutResource :: checkbuilding ( pbuilding b ) { if ( b->color/8 == player ) { if ((b->netcontrol & (cnet_stopenergyinput << resourcetype)) == 0) { int tostore = need-got; if ( b->actstorage.resource( resourcetype ) < 0 ) { displaymessage("map corruption detected; building %s storage for %d/%d is negative!",1,resourceNames[resourcetype],b->getEntry().x, b->getEntry().y ); b->actstorage.resource( resourcetype ) = 0; } if ( b->gettank ( resourcetype ) - b->actstorage.resource( resourcetype ) < tostore ) tostore = b->gettank ( resourcetype ) - b->actstorage.resource( resourcetype ); if ( !queryonly ) b->actstorage.resource( resourcetype ) += tostore; got += tostore; } } } void PutResource :: start ( int x, int y ) { if ( scope == 3 ) { got = need; if ( got > maxint - actmap->bi_resource[player].resource( resourcetype ) ) got = maxint - actmap->bi_resource[player].resource( resourcetype ); if ( !queryonly ) actmap->bi_resource[player].resource( resourcetype ) += got; } else MapNetwork :: start ( x, y ); } void PutTribute :: checkbuilding ( pbuilding b ) { if ( b->color/8 == targplayer ) { if ((b->netcontrol & (cnet_stopenergyinput << resourcetype)) == 0) { int tostore = need-got; if ( b->gettank ( resourcetype ) - b->actstorage.resource( resourcetype ) < tostore ) tostore = b->gettank ( resourcetype ) - b->actstorage.resource( resourcetype ); if ( !queryonly ) { b->actstorage.resource( resourcetype ) += tostore; actmap->tribute.avail[ player ][ targplayer ].resource( resourcetype ) -= tostore; actmap->tribute.paid [ targplayer ][ player ].resource( resourcetype ) += tostore; } got += tostore; } } } void PutTribute :: start ( int x, int y ) { int pl = targplayer; if ( pl == -1 ) targplayer = 0; do { if ( targplayer != player ) if ( actmap->player[targplayer].exist() ) { need = actmap->tribute.avail[ player ][ targplayer ].resource( resourcetype ); if ( need > 0 ) { if ( scope == 3 ) { got = need; if ( got > maxint - actmap->bi_resource[targplayer].resource( resourcetype ) ) got = maxint - actmap->bi_resource[targplayer].resource( resourcetype ); if ( got > actmap->bi_resource[player].resource( resourcetype ) ) got = actmap->bi_resource[player].resource( resourcetype ); if ( !queryonly ) { actmap->bi_resource[targplayer].resource( resourcetype ) += got; actmap->bi_resource[player].resource( resourcetype ) -= got; actmap->tribute.avail[ player ][ targplayer ].resource( resourcetype ) -= got; actmap->tribute.paid [ targplayer ][ player ].resource( resourcetype ) += got; } } else { int avail = startbuilding->getResource ( need, resourcetype, 1, 0 ); if ( need > avail ) need = avail; MapNetwork :: start ( x, y ); if ( !queryonly ) startbuilding->getResource ( got, resourcetype, queryonly, 0 ); } } } targplayer++; } while ( targplayer < 8 && pl == -1 ); } int PutTribute :: puttribute ( pbuilding start, int resource, int _queryonly, int _forplayer, int _fromplayer, int _scope ) { startbuilding = start; targplayer = _forplayer; return getresource ( startbuilding->getEntry().x, startbuilding->getEntry().y, resource, 0, _queryonly, _fromplayer, _scope ); } void transfer_all_outstanding_tribute ( void ) { int targplayer = actmap->actplayer; // for ( int player = 0; player < 8; player++ ) if ( actmap->player[targplayer].exist() ) { ASCString text; for ( int player = 0; player < 8; player++ ) { if ( targplayer != player ) if ( actmap->player[player].exist() ) { int topay[3]; int got[3]; for ( int resourcetype = 0; resourcetype < 3; resourcetype++ ) { got[ resourcetype ] = actmap->tribute.paid[ targplayer ][ player ].resource( resourcetype ) - actmap->tribute.payStatusLastTurn[ targplayer ][ player ].resource( resourcetype ); topay[ resourcetype ] = actmap->tribute.avail[ player ][ targplayer ].resource( resourcetype ) + got[ resourcetype ]; if ( !actmap->isResourceGlobal (resourcetype) ) { for ( tmap::Player::BuildingList::iterator j = actmap->player[player].buildingList.begin(); j != actmap->player[player].buildingList.end() && topay[resourcetype] > got[resourcetype] ; j++ ) { PutTribute pt ( actmap ); got[resourcetype] += pt.puttribute ( *j, resourcetype, 0, targplayer, player, 1 ); } } else { int i; if ( actmap->bi_resource[ player ].resource(resourcetype) < topay[resourcetype] ) i = actmap->bi_resource[ player ].resource(resourcetype); else i = topay[resourcetype]; got [resourcetype ] += i; actmap->bi_resource[ player ].resource(resourcetype) -= i; actmap->bi_resource[ targplayer ].resource(resourcetype) += i; actmap->tribute.avail[ player ][ targplayer ].resource( resourcetype ) -= got[resourcetype]; actmap->tribute.paid[ targplayer ][ player ].resource( resourcetype ) += got[resourcetype]; } } actmap->tribute.payStatusLastTurn[ targplayer ][ player ] = actmap->tribute.paid[ targplayer ][ player ]; if ( topay[0] || topay[1] || topay[2] || got[0] || got[1] || got[2]) { Resources tp ( topay[0], topay[1], topay[2] ); Resources gt ( got[0], got[1], got[2] ); ASCString topayStr = tp.toString(); ASCString gotStr; if ( gt == tp ) gotStr = "all"; else { gotStr = gt.toString(); if ( gotStr.empty() ) gotStr = "nothing"; } ASCString msg; msg.format ( getmessage( 10020 ) , actmap->player[player].getName().c_str(), topayStr.c_str(), gotStr.c_str() ); text += msg; // next message, this time for the providing player if ( got[0] || got[1] || got[2] ) { msg = ""; gotStr = gt.toString(); msg.format ( getmessage( 10021 ) , gotStr.c_str(), actmap->player[targplayer].getName().c_str()); new Message ( msg, actmap, 1 << player ); } } if ( got[0] || got[1] || got[2] ) tributeTransferred(); } } if ( !text.empty() ) new Message ( text, actmap, 1 << targplayer ); } } void GetResourceCapacity :: checkbuilding ( pbuilding b ) { if ( b->color/8 == player ) { if ((b->netcontrol & (cnet_stopenergyinput << resourcetype)) == 0) { int t = b->gettank ( resourcetype ); if ( t > maxint - got ) got = maxint; else got += t; } } } void GetResourceCapacity :: start ( int x, int y ) { if ( scope == 3 ) { got = maxint; } else MapNetwork :: start ( x, y ); } int ResourceChangeNet :: getresource ( int x, int y, int resource, int _player, int _scope ) { if ( (_scope > 0) && (actmap->isResourceGlobal ( resource )) ) scope = 2; else scope = _scope; player = _player; resourcetype = resource; got = 0; start ( x , y ); return got; } void GetResourcePlus :: checkvehicle ( pvehicle v ) {/* if ( resourcetype == 0 ) if ( v->getGeneratorStatus() ) got += v->typ->tank.energy; */ } void GetResourcePlus :: checkbuilding ( pbuilding bld ) { if ( bld->color/8 == player ) got += bld->getResourcePlus().resource( resourcetype ); } void GetResourceUsage :: checkbuilding ( pbuilding b ) { if ( b->color/8 == player ) got += b->getResourceUsage().resource( resourcetype ); }