Area.cpp

Go to the documentation of this file.
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.

SourceForge.net Logo