00001 /* 00002 SagaEngine library 00003 Copyright (c) 2002-2006 Skalden Studio AS 00004 00005 This software is provided 'as-is', without any express or implied 00006 warranty. In no event will the authors be held liable for any 00007 damages arising from the use of this software. 00008 00009 Permission is granted to distribute the library under the terms of the 00010 Q Public License version 1.0. Be sure to read and understand the license 00011 before using the library. It should be included here, or you may read it 00012 at http://www.trolltech.com/products/qt/licenses/licensing/qpl 00013 00014 The original version of this library can be located at: 00015 http://www.sagaengine.com/ 00016 00017 Rune Myrland 00018 rune@skalden.com 00019 */ 00020 00021 00022 #include "Area.hpp" 00023 #include "AreaManager.hpp" 00024 #include "util/error/all.hpp" 00025 #include "util/math/all.hpp" 00026 #include "util/system/util_system.hpp" 00027 #include "util/type/all.hpp" 00028 #include "util/vecmath/all.hpp" 00029 #include "sim/all.hpp" 00030 #include "sim/action/all.hpp" 00031 #include "sim/config/all.hpp" 00032 #include "sim/react/ThingCollide.hpp" 00033 #include "sim/schema/all.hpp" 00034 #include "sim/script/all.hpp" 00035 #include "sim/stat/all.hpp" 00036 #include "sim/thing/all.hpp" 00037 #include "sim/pos/PosComponent.hpp" 00038 #include "comp/list/CompositeList.hpp" 00039 #include "comp/list/ComponentList.hpp" 00040 #include "../physics/PhysicsAreaComponent.hpp" 00041 #include "../react/CollisionAreaComponent.hpp" 00042 #include "../signal/SignalAreaComponent.hpp" 00043 #include "../spawn/SpawnAreaComponent.hpp" 00044 #include "../spawn/SpawnManager.hpp" 00045 #include "../zone/ZoneAreaComponent.hpp" 00046 00047 #include <cstdio> 00048 #include <cstring> 00049 00050 #ifndef abs 00051 #define abs(n) (((n) < 0) ? (-(n)) : (n)) 00052 #endif 00053 00054 namespace se_core { 00055 Area 00056 ::Area(Composite* owner, const ComponentFactory* factory, coor_tile_t w, coor_tile_t h) 00057 : Component(sct_BLOB, owner, factory), width_(w), height_(h) { 00058 LogDetail(owner->name() << " area created with size " << w << ", " << h); 00059 00060 posComponent_ = new PosComponent(owner); 00061 00062 // Init to default position 00063 owner_->setParent(RootComponent::inactiveRoot()); 00064 00065 posComponent_->nextPos().reset(); 00066 coor_t ySize = CoorT::fromTile(w); 00067 BoundingBox b; 00068 // Must be below 0, because things that has gravity is constantly falling 00069 // Floor adjustments are often done after wall collision tests 00070 b.setMin(0, -ySize, 0); 00071 b.setMax(CoorT::fromTile(w), ySize, CoorT::fromTile(h)); 00072 posComponent_->nextPos().setBounds(b); 00073 posComponent_->flip(); 00074 00075 spawnAreaComponent_ = new SpawnAreaComponent(owner); 00076 collisionAreaComponent_ = new CollisionAreaComponent(owner); 00077 AreaEdge& areaEdge = collisionAreaComponent_->areaEdge(); 00078 areaEdge.addLink(Point2(0, 0), Point2(CoorT::fromTile(w), 0)); 00079 areaEdge.addLink(Point2(CoorT::fromTile(w), 0), Point2(CoorT::fromTile(w), CoorT::fromTile(h))); 00080 areaEdge.addLink(Point2(CoorT::fromTile(w), CoorT::fromTile(h)), Point2(0, CoorT::fromTile(h))); 00081 areaEdge.addLink(Point2(0, CoorT::fromTile(h)), Point2(0, 0)); 00082 00083 physicsAreaComponent_ = new PhysicsAreaComponent(owner, collisionAreaComponent_); 00084 actionComponent_ = new ActionComponent(owner); 00085 scriptComponent_ = new ScriptComponent(owner, actionComponent_); 00086 signalAreaComponent_ = new SignalAreaComponent(owner); 00087 zoneAreaComponent_ = new ZoneAreaComponent(owner); 00088 // Register with area manager 00089 //SimSchema::areaManager.addArea(this); 00090 } 00091 00092 00093 Area 00094 ::~Area() { 00095 LogDetail(owner()->name() << " area destroyed"); 00096 delete zoneAreaComponent_; 00097 delete signalAreaComponent_; 00098 delete scriptComponent_; 00099 delete actionComponent_; 00100 delete physicsAreaComponent_; 00101 delete collisionAreaComponent_; 00102 delete spawnAreaComponent_; 00103 delete posComponent_; 00104 } 00105 00106 00107 void Area 00108 ::saveThings(/* stream */) { 00109 // Header 00110 Dump("EB01"); 00111 00112 // Name 00113 Dump((sprintf(log_msg(), "N %s", this->name()), log_msg())); 00114 /* 00115 // Entrances 00116 for(int i = 0; i < MAX_ENTRANCES; ++i) { 00117 if(!this->entrances_[i]) 00118 continue; 00119 DebugExec(Point3& e = *this->entrances_[i]); 00120 Dump((sprintf(log_msg(), "E %d %.2f %.2f", i, CoorT::toFloat(e.x_), CoorT::toFloat(e.y_)), log_msg())); 00121 } 00122 */ 00123 00124 // Things 00125 /* 00126 SimObjectList::iterator_type it = this->allThings().iterator(); 00127 Thing* t; 00128 CompositeFactory* td; 00129 while(it != SimObjectList::end()) { 00130 t = SimSchema::simObjectList.nextThing(it); 00131 td = SimSchema::thingManager().factory(t->name()); 00132 DebugExec(const Point3& c = t->pos().localCoor()); 00133 Dump((sprintf(log_msg(), "O %s %.2f %.2f", t->name(), CoorT::toFloat(c.x_), CoorT::toFloat(c.y_)), log_msg())); 00134 00135 // Statistics 00136 for(int i = 0; i < SV_COUNT; ++i) { 00137 if(td->singleValue(i) == t->singleValue(i)) continue; 00138 Dump((sprintf(log_msg(), "S %d %d", i, t->singleValue(i)), log_msg())); 00139 } 00140 00141 // Attributes 00142 for(int i = 0; i < ATT_COUNT; ++i) { 00143 // TODO: Assumes that attributes will never be assigned in definition, only on instantiation... 00144 if(t->attribute(i).get()[0] == '\0') continue; 00145 Dump((sprintf(log_msg(), "A %d %s", i, t->attribute(i).get()), log_msg())); 00146 } 00147 00148 Dump("/"); 00149 } 00150 00151 // End of file 00152 Dump("Q"); 00153 */ 00154 } 00155 00156 00157 Composite* Area 00158 ::findTarget(const char* factoryName, const Point3& worldCoor) const { 00159 // Default to maximum pick range 00160 coor_double_t nearestDist = 0; 00161 Composite* nearest = 0; 00162 00163 CompositeList::Iterator it(owner()->children()); 00164 while(it.hasNext()) { 00165 Composite* t = &it.next(); 00166 if(strcmp(t->name(), factoryName) == 0) { 00167 PosComponent::Ptr pos(*t); 00168 coor_double_t dist = worldCoor.distanceSquared(pos->nextPos().worldCoor()); 00169 if(!nearest || dist < nearestDist) { 00170 nearest = t; 00171 nearestDist = dist; 00172 } 00173 } 00174 } 00175 00176 return nearest; 00177 } 00178 00179 /* 00180 Thing* Area 00181 ::findPickTarget(Player& actor) const { 00182 actor.setPickTarget(0); 00183 const Point3& coor = actor.pos().localCoor(); 00184 00185 // Default to maximum pick range 00186 coor_t nearest = (3 * COOR_RES); 00187 00188 SimObjectList::iterator_type it = multiSimObject(MGOA_PICKABLE_THINGS).iterator(); 00189 while(it != SimObjectList::end()) { 00190 Thing* t = SimSchema::simObjectList.nextThing(it); 00191 if(coor.xzDistanceLinf(t->pos().localCoor()) < nearest) { 00192 nearest = coor.xzDistanceLinf(t->pos().localCoor()); 00193 actor.setPickTarget(t); 00194 } 00195 } 00196 //if(actor.pickTarget()) { 00197 // actor.setDefaultAction(actionPick); 00198 //} 00199 return actor.pickTarget(); 00200 } 00201 00202 00203 Thing* Area 00204 ::findDefaultActionTarget(Player& actor) const { 00205 actor.resetDefaultAction(); 00206 if(findPickTarget(actor)) return actor.pickTarget(); 00207 00208 actor.setTarget(0); 00209 const Pos& pos = actor.pos(); 00210 const Point3& coor = pos.localCoor(); 00211 00212 coor_double_t nearest = -1; 00213 00214 SimObjectList::iterator_type it = multiSimObject(MGOA_ACTORS).iterator(); 00215 while(it != SimObjectList::end()) { 00216 Actor* a = SimSchema::simObjectList.nextActor(it); 00217 if(a == &actor) continue; 00218 if(a->cutscenes().isEmpty()) continue; 00219 if(nearest < 0 || coor.xzDistanceSquared(a->pos().localCoor()) < nearest) { 00220 // TODO: 00221 //if(pos.hasInFront(a->pos().localCoor()) && actor.findRunnableCutscene(*a)) { 00222 // nearest = coor.xzDistanceSquared(a->pos().localCoor()); 00223 // actor.setTarget(a); 00224 // actor.setPickTarget(a); 00225 //} 00226 } 00227 } 00228 //TODO: 00229 //if(actor.hasTarget()) { 00230 // actor.setDefaultAction(actionStartCutscene); 00231 //} 00232 00233 return actor.pickTarget(); 00234 } 00235 */ 00236 00237 00238 void Area 00239 ::reset() { 00240 // Get newly spawned objects into allThings() 00241 flipSpawns(); 00242 //spawnAreaComponent_->flipSpawns(); 00243 //multiSimObjects_[ MGOA_SPAWNS ].clear(); 00244 00245 // Shedule all things for destruction, and flip 00246 // it out of area 00247 { 00248 CompositeList::TreeIterator it(owner()->children()); 00249 while(it.hasNext()) { 00250 Composite* t = &it.next(); 00251 t->scheduleForDestruction(); 00252 } 00253 } 00254 } 00255 00256 00257 bool Area 00258 ::isNeighbour(const Area& area) const { 00259 Page rel; 00260 zoneAreaComponent_->offset(*area.zoneAreaComponent_, rel); 00261 return rel.isNeighbourOffset() && (rel.x_ == 0 || rel.z_ == 0); 00262 } 00263 00264 00265 bool Area 00266 ::addNeighbour(Area* area) { 00267 if(isNeighbour(*area)) { 00268 AssertWarning(area->isNeighbour(*this), name() << " isn't relinked from " << area->name()); 00269 zoneAreaComponent_->addLink(*area->zoneAreaComponent_); 00270 00271 int px = zoneAreaComponent_->page().x_; 00272 int pz = zoneAreaComponent_->page().z_; 00273 00274 int npx = area->zoneAreaComponent_->page().x_; 00275 int npz = area->zoneAreaComponent_->page().z_; 00276 00277 AreaEdge& areaEdge = collisionAreaComponent_->areaEdge(); 00278 00279 coor_t w = CoorT::fromTile(width_); 00280 coor_t h = CoorT::fromTile(height_); 00281 Assert(pz == npz || px == npx); 00282 if(pz > npz) { 00283 areaEdge.removeLink(Point2(0, 0), Point2(w, 0)); 00284 } 00285 else if(px < npx) { 00286 areaEdge.removeLink(Point2(w, 0), Point2(w, h)); 00287 } 00288 else if(pz < npz) { 00289 areaEdge.removeLink(Point2(w, h), Point2(0, h)); 00290 } 00291 else if(px > npx) { 00292 areaEdge.removeLink(Point2(0, h), Point2(0, 0)); 00293 } 00294 00295 } 00296 00297 return zoneAreaComponent_->addNeighbour(*area->zoneAreaComponent_); 00298 } 00299 00300 00301 Area* Area 00302 ::neighbour(short relX, short relY, short relZ) { 00303 ZoneAreaComponent* c = zoneAreaComponent_->neighbour(relX, relY, relZ); 00304 if(!c) return 0; 00305 return Area::Ptr(*c); 00306 } 00307 00308 00309 const Area* Area 00310 ::neighbour(short relX, short relY, short relZ) const { 00311 const ZoneAreaComponent* c = zoneAreaComponent_->neighbour(relX, relY, relZ); 00312 if(!c) return 0; 00313 return Area::Ptr(*c); 00314 } 00315 00316 00317 Area* Area 00318 ::neighbour(const Point3& worldCoor) { 00319 const Point3& wc = posComponent_->nextPos().worldCoor(); 00320 coor_t x = worldCoor.x_ - wc.x_; 00321 //coor_t y = worldCoor.y_ - wc.y_; 00322 coor_t z = worldCoor.z_ - wc.z_; 00323 00324 int relX = 0; 00325 if(x < 0) relX = -1; 00326 if(CoorT::tile(x) >= width()) relX = 1; 00327 00328 int relY = 0; 00329 00330 int relZ = 0; 00331 if(z < 0) relZ = -1; 00332 if(CoorT::tile(z) >= height()) relZ = 1; 00333 00334 return neighbour(relX, relY, relZ); 00335 } 00336 00337 00338 const Area* Area 00339 ::neighbour(const Point3& worldCoor) const { 00340 const Point3& wc = posComponent_->nextPos().worldCoor(); 00341 coor_t x = worldCoor.x_ - wc.x_; 00342 //coor_t y = worldCoor.y_ - wc.y_; 00343 coor_t z = worldCoor.z_ - wc.z_; 00344 00345 int relX = 0; 00346 if(x < 0) relX = -1; 00347 if(CoorT::tile(x) >= width()) relX = 1; 00348 00349 int relY = 0; 00350 00351 int relZ = 0; 00352 if(z < 0) relZ = -1; 00353 if(CoorT::tile(z) >= height()) relZ = 1; 00354 00355 return neighbour(relX, relY, relZ); 00356 } 00357 00358 00359 void Area 00360 ::flipSpawns(void) { 00361 spawnAreaComponent_->flipSpawns(); 00362 } 00363 00364 00365 00366 Composite* Area 00367 ::spawn(const char* thingName, const ViewPoint& vp, long deniedTsMask, PosComponent* parent) { 00368 if(deniedTsMask != 0 && (tsMask(terrainStyle(vp.coor_)) & deniedTsMask) != 0) { 00369 // Tried to spawn on denied terrain type 00370 LogDetail((int)(tsMask(terrainStyle(vp.coor_)))); 00371 return 0; 00372 } 00373 00374 return spawnAreaComponent_->spawn(thingName, vp, parent); 00375 } 00376 00377 00378 long Area 00379 ::touchedTerrain(const Point3& centre, coor_t radius) const { 00380 long touched = 0; 00381 Vector3 v(radius, 0, radius); 00382 for(coor_t dx = radius; dx > 0; dx -= COOR_RES) { 00383 for(coor_t dz = radius; dz > 0; dz -= COOR_RES) { 00384 Point3 c; 00385 c.set(centre); 00386 c.add(dx, 0, dz); 00387 touched |= tsMask(terrainStyle(c)); 00388 00389 c.set(centre); 00390 c.add(-dx, 0, dz); 00391 touched |= tsMask(terrainStyle(c)); 00392 00393 c.set(centre); 00394 c.add(dx, 0, -dz); 00395 touched |= tsMask(terrainStyle(c)); 00396 00397 c.set(centre); 00398 c.add(-dx, 0, -dz); 00399 touched |= tsMask(terrainStyle(c)); 00400 } 00401 } 00402 00403 return touched; 00404 } 00405 00406 00407 long Area 00408 ::touchedTerrain(const Point3& from, const Point3& to) const { 00409 long touched = 0; 00410 00411 // Bresenham 00412 // TODO: Should be modified so that all tiles touching the 00413 // line is taken into account. 00414 00415 // The difference between the x's 00416 int deltax = abs(to.xTile() - from.xTile()); 00417 // The difference between the y's 00418 int deltay = abs(to.zTile() - from.zTile()); 00419 // Start x off at the first pixel 00420 int x = from.xTile(); 00421 // Start y off at the first pixel 00422 int y = from.zTile(); 00423 00424 int xinc1, xinc2; 00425 if (to.xTile() >= from.xTile()) { 00426 // The x-values are increasing 00427 xinc1 = xinc2 = 1; 00428 } 00429 else { 00430 // The x-values are decreasing 00431 xinc1 = xinc2 = -1; 00432 } 00433 00434 int yinc1, yinc2; 00435 if (to.zTile() >= to.xTile()) { 00436 // The y-values are increasing 00437 yinc1 = yinc2 = 1; 00438 } 00439 else { 00440 // The y-values are decreasing 00441 yinc1 = yinc2 = -1; 00442 } 00443 00444 int den, num, numadd, numpixels; 00445 // There is at least one x-value for every y-value 00446 if (deltax >= deltay) { 00447 // Don't change the x when numerator >= denominator 00448 xinc1 = 0; 00449 // Don't change the y for every iteration 00450 yinc2 = 0; 00451 den = deltax; 00452 num = deltax >> 1; 00453 numadd = deltay; 00454 // There are more x-values than y-values 00455 numpixels = deltax; 00456 } 00457 // There is at least one y-value for every x-value 00458 else { 00459 // Don't change the x for every iteration 00460 xinc2 = 0; 00461 // Don't change the y when numerator >= denominator 00462 yinc1 = 0; 00463 den = deltay; 00464 num = deltay >> 1; 00465 numadd = deltax; 00466 // There are more y-values than x-values 00467 numpixels = deltay; 00468 } 00469 00470 for (int curpixel = 0; curpixel <= numpixels; curpixel++) { 00471 // "Draw" the current pixel 00472 touched |= tsMask(terrainStyle(Point3(CoorT::fromInt(x), 0, CoorT::fromInt(y)))); 00473 // Increase the numerator by the top of the fraction 00474 num += numadd; 00475 // Check if numerator >= denominator 00476 if (num >= den) { 00477 // Calculate the new numerator value 00478 num -= den; 00479 // Change the x as appropriate 00480 x += xinc1; 00481 // Change the y as appropriate 00482 y += yinc1; 00483 } 00484 // Change the x as appropriate 00485 x += xinc2; 00486 // Change the y as appropriate 00487 y += yinc2; 00488 } 00489 00490 return touched; 00491 } 00492 00493 }
Home Page | SagaEngine trunk (updated nightly) reference generated Sun Dec 2 20:06:11 2007 by Doxygen version 1.3.9.1.