PageRenderTime 44ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/source/spfst.cpp

https://bitbucket.org/val_haris/asc-ai
C++ | 590 lines | 398 code | 111 blank | 81 comment | 164 complexity | d6c00561f98ec22c19dc18b4192c6a7c MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0
  1. /*! \file spfst.cpp
  2. \brief map accessing and usage routines used by ASC and the mapeditor
  3. */
  4. /*
  5. This file is part of Advanced Strategic Command; http://www.asc-hq.de
  6. Copyright (C) 1994-2010 Martin Bickel and Marc Schellenberger
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  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. You should have received a copy of the GNU General Public License
  16. along with this program; see the file COPYING. If not, write to the
  17. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  18. Boston, MA 02111-1307 USA
  19. */
  20. #include <stdio.h>
  21. #include <cstring>
  22. #include <utility>
  23. #include <map>
  24. #include "vehicletype.h"
  25. #include "buildingtype.h"
  26. #include "typen.h"
  27. #include "spfst.h"
  28. #include "attack.h"
  29. #include "mapalgorithms.h"
  30. #include "vehicle.h"
  31. #include "buildings.h"
  32. #include "mapfield.h"
  33. #include "spfst-legacy.h"
  34. SigC::Signal0<void> repaintMap;
  35. SigC::Signal0<void> repaintDisplay;
  36. SigC::Signal0<void> updateFieldInfo;
  37. SigC::Signal0<void> cursorMoved;
  38. SigC::Signal1<void,ContainerBase*> showContainerInfo;
  39. SigC::Signal1<void,VehicleType*> showVehicleTypeInfo;
  40. SigC::Signal0<void> viewChanged;
  41. SigC::Signal1<void,GameMap*> mapChanged;
  42. SigC::Signal0<bool> idleEvent;
  43. SigC::Signal1<void, const Context&> fieldCrossed;
  44. void displaymap()
  45. {
  46. repaintMap();
  47. }
  48. GameMap* actmap = NULL;
  49. Schriften schriften;
  50. int terrainaccessible ( const MapField* field, const Vehicle* vehicle, int uheight )
  51. {
  52. int res = terrainaccessible2 ( field, vehicle, uheight );
  53. if ( res < 0 )
  54. return 0;
  55. else
  56. return res;
  57. }
  58. int terrainaccessible2 ( const MapField* field, const Vehicle* vehicle, int uheight )
  59. {
  60. if ( uheight == -1 )
  61. uheight = vehicle->height;
  62. if ( !(uheight & vehicle->typ->height))
  63. return 0;
  64. return terrainaccessible2( field, vehicle->typ->terrainaccess, uheight );
  65. }
  66. int terrainaccessible2 ( const MapField* field, const TerrainAccess& terrainAccess, int uheight )
  67. {
  68. if ( uheight >= chtieffliegend)
  69. return 2;
  70. else {
  71. if ( uheight == chtiefgetaucht )
  72. if ( (field->bdt & getTerrainBitType(cbwater3) ).any() )
  73. return 2;
  74. else
  75. return -1;
  76. else
  77. if ( uheight == chgetaucht )
  78. if ( (field->bdt & ( getTerrainBitType(cbwater3) | getTerrainBitType(cbwater2 )) ).any() )
  79. return 2;
  80. else
  81. return -2;
  82. else {
  83. if ( terrainAccess.accessible ( field->bdt ) > 0 ) {
  84. if ( uheight == chschwimmend ) {
  85. if ( (field->bdt & getTerrainBitType(cbwater)).any() )
  86. return 2;
  87. else
  88. return -3;
  89. } else
  90. return 2;
  91. } else
  92. return -3;
  93. }
  94. }
  95. }
  96. int fieldAccessible( const MapField* field,
  97. const Vehicle* vehicle,
  98. int uheight,
  99. const bool* attacked,
  100. bool ignoreVisibility )
  101. {
  102. if ( !field || !vehicle )
  103. return 0;
  104. if ( uheight == -2 )
  105. uheight = vehicle->height;
  106. if ( !ignoreVisibility ) {
  107. int c = fieldVisibility ( field, vehicle->getOwner() );
  108. if (field == NULL)
  109. return 0;
  110. if (c == visible_not)
  111. return 0;
  112. }
  113. /*
  114. if ( c == visible_all)
  115. if ( field->mines.size() )
  116. for ( int i = 0; i < field->mines.size(); i++ )
  117. if ( field->getMine(i).attacksunit( vehicle ))
  118. return 0;
  119. */
  120. if ( (!field->vehicle || field->vehicle == vehicle) && !field->building ) {
  121. if ( vehicle->typ->height & uheight )
  122. return terrainaccessible ( field, vehicle, uheight );
  123. else
  124. return 0;
  125. } else {
  126. if (field->vehicle) {
  127. if ( vehicle->getMap()->getPlayer(vehicle).diplomacy.isAllied( field->vehicle->getOwner()) ) {
  128. if ( field->vehicle->vehicleLoadable ( vehicle, uheight ) )
  129. return 2;
  130. else
  131. if ( terrainaccessible ( field, vehicle, uheight ))
  132. return 1;
  133. else
  134. return 0;
  135. }
  136. else /////// keine eigene vehicle
  137. if ( terrainaccessible ( field, vehicle, uheight ) ) {
  138. if (vehicleplattfahrbar(vehicle,field))
  139. return 2;
  140. else {
  141. if ( getheightdelta(getFirstBit(field->vehicle->height), getFirstBit(uheight)) || (attackpossible28(field->vehicle,vehicle) == false) || ( vehicle->getMap()->getPlayer(vehicle).diplomacy.getState( field->vehicle->getOwner()) >= PEACE ))
  142. return 1;
  143. }
  144. }
  145. }
  146. else { // building
  147. if ((field->bdt & getTerrainBitType(cbbuildingentry) ).any() && field->building->vehicleLoadable ( vehicle, uheight, attacked ))
  148. return 2;
  149. else
  150. if (uheight >= chtieffliegend || (field->building->typ->height <= chgetaucht && uheight >= chschwimmend ))
  151. return 1;
  152. else
  153. return 0;
  154. }
  155. }
  156. return 0;
  157. }
  158. MapField* getfield(int x,
  159. int y)
  160. {
  161. if ((x < 0) || (y < 0) || (x >= actmap->xsize) || (y >= actmap->ysize))
  162. return NULL;
  163. else
  164. return ( &actmap->field[y * actmap->xsize + x] );
  165. }
  166. void putbuilding( GameMap* actmap,
  167. const MapCoordinate& entryPosition,
  168. int color,
  169. const BuildingType* buildingtyp,
  170. int completion,
  171. int ignoreunits )
  172. {
  173. if ( color & 7 )
  174. fatalError("putbuilding muss eine farbe aus 0,8,16,24,.. uebergeben werden !",2);
  175. for ( int a = 0; a < 4; a++)
  176. for ( int b = 0; b < 6; b++ )
  177. if ( buildingtyp->fieldExists ( BuildingType::LocalCoordinate( a, b ) ) ) {
  178. MapField* field = actmap->getField( buildingtyp->getFieldCoordinate( entryPosition, BuildingType::LocalCoordinate(a,b) ));
  179. if (field == NULL)
  180. return ;
  181. else {
  182. if ( field->vehicle && (!ignoreunits ) )
  183. return;
  184. if (field->building != NULL)
  185. return;
  186. }
  187. }
  188. Building* gbde = new Building ( actmap , entryPosition, buildingtyp, color/8 );
  189. if (completion >= buildingtyp->construction_steps)
  190. completion = buildingtyp->construction_steps - 1;
  191. gbde->setCompletion ( completion );
  192. }
  193. void checkobjectsforremoval ( GameMap* gamemap )
  194. {
  195. for ( int y = 0; y < gamemap->ysize; y++ )
  196. for ( int x = 0; x < gamemap->xsize; x++ ) {
  197. MapField* fld = getfield ( x, y );
  198. for ( MapField::ObjectContainer::iterator i = fld->objects.begin(); i != fld->objects.end(); )
  199. if ( i->typ->getFieldModification(fld->getWeather()).terrainaccess.accessible ( fld->bdt ) < 0 ) {
  200. fld->removeObject ( i->typ, true );
  201. i = fld->objects.begin();
  202. } else
  203. i++;
  204. }
  205. }
  206. void checkunitsforremoval ( GameMap* gamemap )
  207. {
  208. ASCString messages[playerNum];
  209. for ( int y = 0; y < gamemap->ysize; y++ )
  210. for ( int x = 0; x < gamemap->xsize; x++ ) {
  211. MapField* fld = gamemap->getField ( x, y );
  212. if ( (fld->building && fld->building->typ->terrainaccess.accessible( fld->bdt ) < 0) && (fld->building->typ->height <= chfahrend) ) {
  213. messages[fld->building->getOwner()] += getBuildingReference( fld->building ) + " was destroyed \n\n";
  214. delete fld->building;
  215. }
  216. }
  217. for ( int c=0; c<=8 ;c++ ) {
  218. ASCString msg = messages[c];
  219. for ( Player::VehicleList::iterator i = gamemap->player[c].vehicleList.begin(); i != gamemap->player[c].vehicleList.end(); ) {
  220. Vehicle* eht = *i;
  221. MapField* field = gamemap->getField(eht->xpos,eht->ypos);
  222. bool erase = false;
  223. ASCString reason;
  224. if (field->vehicle == eht) {
  225. if ( eht->height <= chfahrend )
  226. if ( eht->typ->terrainaccess.accessible ( field->bdt ) < 0 ) {
  227. erase = true;
  228. reason = "was swallowed by the ground";
  229. }
  230. if ( eht )
  231. if ( getmaxwindspeedforunit( eht ) < gamemap->weather.windSpeed*maxwindspeed ) {
  232. reason = "was blown away by the wind";
  233. erase = true;
  234. }
  235. }
  236. if ( erase ) {
  237. msg += getUnitReference( eht ) + reason;
  238. msg += "\n\n";
  239. Vehicle* pv = *i;
  240. gamemap->player[c].vehicleList.erase ( i );
  241. delete pv;
  242. /* if the unit was a transport and had other units loaded, these units have been deleted as well.
  243. We don't know which elements of the container are still valid, so we start from the beginning again. */
  244. i = gamemap->player[c].vehicleList.begin();
  245. } else
  246. i++;
  247. }
  248. if ( !msg.empty() )
  249. new Message ( msg, gamemap, 1<<c);
  250. }
  251. }
  252. int getwindheightforunit ( const Vehicle* eht, int uheight )
  253. {
  254. if ( uheight == -1 )
  255. uheight = eht->height;
  256. if ( uheight == chfliegend )
  257. return 1;
  258. else
  259. if ( uheight == chhochfliegend )
  260. return 2;
  261. else
  262. return 0;
  263. }
  264. int getmaxwindspeedforunit ( const Vehicle* eht )
  265. {
  266. MapField* field = eht->getMap()->getField(eht->xpos,eht->ypos);
  267. if ( field->vehicle == eht) {
  268. if (eht->height >= chtieffliegend && eht->height <= chhochfliegend ) // || ((eht->height == chfahrend) && ( field->typ->art & cbwater ))) )
  269. return eht->typ->movement[getFirstBit(eht->height)] * 256 ;
  270. if ( (field->bdt & getTerrainBitType(cbfestland)).none() && eht->height <= chfahrend && eht->height >= chschwimmend && (field->bdt & getTerrainBitType(cbharbour)).none() && (field->bdt & getTerrainBitType(cbwater0)).none())
  271. return eht->typ->maxwindspeedonwater * maxwindspeed;
  272. }
  273. return maxint;
  274. }
  275. /*
  276. void tdrawline8 :: start ( int x1, int y1, int x2, int y2 )
  277. {
  278. x1 += x1 + (y1 & 1);
  279. x2 += x2 + (y2 & 1);
  280. tdrawline::start ( x1, y1, x2, y2 );
  281. }
  282. void tdrawline8 :: putpix ( int x, int y )
  283. {
  284. if ( (x & 1) == (y & 1) )
  285. putpix8( x/2, y );
  286. }
  287. */
  288. /*
  289. void EllipseOnScreen :: paint ( void )
  290. {
  291. if ( active )
  292. ellipse ( x1, y1, x2, y2, color, precision );
  293. }
  294. void EllipseOnScreen :: read( tnstream& stream )
  295. {
  296. x1 = stream.readInt();
  297. y1 = stream.readInt();
  298. x2 = stream.readInt();
  299. y2 = stream.readInt();
  300. color = stream.readInt();
  301. precision = stream.readFloat();
  302. active = stream.readInt();
  303. }
  304. void EllipseOnScreen :: write ( tnstream& stream )
  305. {
  306. stream.writeInt( x1 );
  307. stream.writeInt( y1 );
  308. stream.writeInt( x2 );
  309. stream.writeInt( y2 );
  310. stream.writeInt( color );
  311. stream.writeFloat( precision );
  312. stream.writeInt( active );
  313. }
  314. */
  315. int getheightdelta ( const ContainerBase* c1, const ContainerBase* c2 )
  316. {
  317. return getheightdelta( getFirstBit(c1->getHeight()), getFirstBit(c2->getHeight() ));
  318. }
  319. bool fieldvisiblenow( const MapField* pe, Vehicle* veh, int player )
  320. {
  321. GameMap* gamemap = pe->getMap();
  322. if ( player == -1 )
  323. return true;
  324. if ( player < -1 )
  325. return false;
  326. if ( !gamemap )
  327. return false;
  328. if ( pe ) {
  329. int c = (pe->visible >> ( player * 2)) & 3;
  330. if ( c < gamemap->getInitialMapVisibility( player ) )
  331. c = gamemap->getInitialMapVisibility( player );
  332. if (c > visible_ago) {
  333. if ( !veh )
  334. veh = pe->vehicle;
  335. if ( veh ) {
  336. if ((c == visible_all) || (veh->color / 8 == player ) || ((veh->height >= chschwimmend) && (veh->height <= chhochfliegend)))
  337. return true;
  338. }
  339. else
  340. if (pe->building != NULL) {
  341. if ((c == visible_all) || (pe->building->typ->height >= chschwimmend) || (pe->building->color == player*8))
  342. return true;
  343. }
  344. else
  345. return true;
  346. }
  347. }
  348. return false;
  349. }
  350. VisibilityStates fieldVisibility( const MapField* pe )
  351. {
  352. return fieldVisibility( pe, pe->getMap()->actplayer );
  353. }
  354. VisibilityStates fieldVisibility( const MapField* pe, int player )
  355. {
  356. GameMap* gamemap = pe->getMap();
  357. if ( player < 0 )
  358. return visible_all;
  359. if ( pe ) {
  360. VisibilityStates c = VisibilityStates((pe->visible >> ( player * 2)) & 3);
  361. if ( c < gamemap->getInitialMapVisibility( player ) )
  362. c = gamemap->getInitialMapVisibility( player );
  363. return c;
  364. } else
  365. return visible_not;
  366. }
  367. void calculateobject( const MapCoordinate& pos,
  368. bool mof,
  369. const ObjectType* obj,
  370. GameMap* gamemap )
  371. {
  372. calculateobject( pos.x, pos.y, mof, obj, gamemap );
  373. }
  374. void calculateobject( int x,
  375. int y,
  376. bool mof,
  377. const ObjectType* obj,
  378. GameMap* actmap )
  379. {
  380. if ( obj->netBehaviour & ObjectType::KeepOrientation )
  381. return;
  382. if ( obj->netBehaviour & ObjectType::SpecialForest ) {
  383. // ForestCalculation::calculateforest( actmap, obj );
  384. return;
  385. }
  386. MapField* fld = actmap->getField(x,y) ;
  387. Object* oi2 = fld-> checkForObject ( obj );
  388. int c = 0;
  389. for ( int dir = 0; dir < sidenum; dir++) {
  390. int a = x;
  391. int b = y;
  392. getnextfield( a, b, dir );
  393. MapField* fld2 = actmap->getField(a,b);
  394. if ( fld2 ) {
  395. if ( obj->netBehaviour & ObjectType::NetToSelf )
  396. if ( fld2->checkForObject ( obj )) {
  397. c |= 1 << dir ;
  398. if ( mof )
  399. calculateobject ( a, b, false, obj, actmap );
  400. }
  401. for ( int oj = 0; oj < int(obj->linkableObjects.size()); oj++ ) {
  402. for ( int id = obj->linkableObjects[oj].from; id <= obj->linkableObjects[oj].to; ++id ) {
  403. Object* oi = fld2->checkForObject ( actmap->getobjecttype_byid ( id ) );
  404. if ( oi ) {
  405. c |= 1 << dir ;
  406. if ( mof )
  407. calculateobject ( a, b, false, oi->typ, actmap );
  408. }
  409. }
  410. }
  411. for ( unsigned int t = 0; t < obj->linkableTerrain.size(); t++ )
  412. for ( int id = obj->linkableTerrain[t].from; id <= obj->linkableTerrain[t].to; ++id )
  413. if ( fld2->typ->terraintype->id == id )
  414. c |= 1 << dir ;
  415. if ( fld2->building && !fld2->building->typ->hasFunction( ContainerBaseType::NoObjectChaining ) ) {
  416. if ( (obj->netBehaviour & ObjectType::NetToBuildingEntry) && (fld2->bdt & getTerrainBitType(cbbuildingentry) ).any() )
  417. c |= 1 << dir;
  418. if ( obj->netBehaviour & ObjectType::NetToBuildings )
  419. c |= 1 << dir;
  420. }
  421. }
  422. else {
  423. if ( obj->netBehaviour & ObjectType::NetToBorder )
  424. c |= 1 << dir;
  425. }
  426. }
  427. if ( obj->netBehaviour & ObjectType::AutoBorder ) {
  428. int autoborder = 0;
  429. int count = 0;
  430. for ( int dir = 0; dir < sidenum; dir++) {
  431. int a = x;
  432. int b = y;
  433. getnextfield( a, b, dir );
  434. MapField* fld2 = actmap->getField(a,b);
  435. if ( !fld2 ) {
  436. // if the field opposite of the border field is connected to, make a straight line out of the map.
  437. if ( c & (1 << ((dir+sidenum/2) % sidenum ))) {
  438. autoborder |= 1 << dir;
  439. count++;
  440. }
  441. }
  442. }
  443. if ( count == 1 )
  444. c |= autoborder;
  445. }
  446. if ( oi2 ) {
  447. oi2->setDir ( c );
  448. }
  449. }
  450. void calculateallobjects( GameMap* actmap )
  451. {
  452. // vector<ObjectType*> forestObjects;
  453. for ( int y = 0; y < actmap->ysize ; y++)
  454. for ( int x = 0; x < actmap->xsize ; x++) {
  455. MapField* fld = actmap->getField(x,y);
  456. for ( MapField::ObjectContainer::iterator i = fld->objects.begin(); i != fld->objects.end(); i++ )
  457. // if ( !(i->typ->netBehaviour & ObjectType::SpecialForest) )
  458. calculateobject( x, y, false, i->typ, actmap );
  459. #if 0
  460. else
  461. if ( find ( forestObjects.begin(), forestObjects.end(), i->typ ) == forestObjects.end())
  462. forestObjects.push_back ( i->typ );
  463. #endif
  464. fld->setparams();
  465. }
  466. #if 0
  467. for ( vector<ObjectType*>::iterator i = forestObjects.begin(); i != forestObjects.end(); i++ )
  468. ForestCalculation::calculateforest( actmap, *i );
  469. #endif
  470. }