/* * Copyright (C) 2002,2003 Daniel Heck * * 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; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * * $Id: world_internal.hh,v 1.1.2.1 2003/09/22 02:37:16 dheck Exp $ */ namespace { class Field; typedef px::Array2 FieldArray; typedef std::vector ActorList; typedef vector ForceList; typedef vector StoneContactList; //---------------------------------------- // Signals //---------------------------------------- class Signal { public: virtual ~Signal() {}; virtual void emit_from(Object *source, int value) = 0; virtual Object *get_target() = 0; virtual Object *get_source() = 0; }; class SimpleSignal : public Signal { public: SimpleSignal (Object *src, GridLoc dstloc, const string &msg) : source (src), destloc(dstloc), message(msg) {} Object *get_target(); Object *get_source() { return source; } void emit_from (Object *src, int value); private: Object *source; GridLoc destloc; string message; }; class SignalList { typedef vector ListT; ListT m_signals; public: ~SignalList() { clear(); } void clear() { delete_sequence (m_signals.begin(), m_signals.end()); m_signals.clear(); } void add (Signal *sig) { m_signals.push_back(sig); } void emit_from (Object *source, int value); Object *find_single_destination(Object *src); }; /* ** RubberBand ** ** Stores the physical information about a rubber band (to which ** object it is attached, its length and force, etc.) */ class RubberBand { public: RubberBand (Actor *a1, Actor *a2, double strength=10, double length=2); RubberBand (Actor *a1, Stone *st, double strength=10, double length=2); ~RubberBand(); void tick(double); V2 get_force(Actor *a); Actor *get_actor() const { return actor; } Actor *get_actor2() const { return actor2; } Stone *get_stone() const { return stone; } double get_strength() const { return strength; } double get_length() const { return length; } private: V2 get_p1() const; V2 get_p2() const; // Variables. Actor *actor, *actor2; Stone *stone; display::RubberHandle model; double strength, length; }; //---------------------------------------- // Field //---------------------------------------- class Field { public: Field(); ~Field(); Floor *floor; Item *item; Stone *stone; }; /* ** MouseForce ** ** This class implements the "force field" that accelerates objects ** when the mouse is moved. Only objects that have the "mouseforce" ** attribute set are affected by this force field. */ class MouseForce { public: void set_force(V2 f) { force=f; } void add_force(V2 f) { force+=f; } V2 get_force(Actor *a) { double mouseforce = 0; a->double_attrib("mouseforce", &mouseforce); if (a->is_flying() || a->is_dead()) return V2(); else return force * mouseforce; } void tick(double /*dtime*/) { force=V2(); } private: V2 force; }; /* ** Scramble ** ** Stores all positions plus direction where puzzle scrambling should ** be performed */ struct Scramble { GridPos pos; Direction dir; int intensity; Scramble(GridPos p, Direction d, int i) : pos(p), dir(d), intensity(i) {} bool expired() const { return intensity<1; } }; /* ** World ** ** Will one day become the abstract interface to the game engine... */ class World { public: virtual ~World() {} virtual void name_object (Object *obj, const string &name) = 0; }; /* ** WorldImpl ** ** Contains the level information (in theory everything that is local ** to the current level; in practice a lot of things are still stored ** in global variables). */ class WorldImpl : public World { public: WorldImpl(int ww, int hh); ~WorldImpl(); bool contains (GridPos p) { return (p.x>=0 && p.y>=0 && p.xcontains(p)) return &fields(p.x,p.y); else return 0; } void name_object (Object *obj, const string &name); void unname (Object *); Object *get_named (const string &); void tick (double dtime); void remove (ForceField *ff); void add_scramble(GridPos p, Direction dir); void scramble_puzzles(); public: // Variables. FieldArray fields; // Contains floors, items, etc. int w, h; // Width and height of the level ForceList forces; ActorList actorlist; // List of movable, dynamic objects vector rubbers; SignalList signals; MouseForce mouseforce; int scrambleIntensity; private: /* Objects can be named with NameObject and referenced with GetNamedObject. This dictionary maps the names to the actual objects. */ px::Dict m_objnames; list scrambles; }; /* ** DelayedImpulse ** */ class DelayedImpulse { Impulse impulse; double delay; const Stone *receiver; // to test if stone has changed DelayedImpulse& operator = (const DelayedImpulse& other); // forbidden public: DelayedImpulse(const Impulse& impulse_, double delay_, const Stone *receiver_) : impulse(impulse_), delay(delay_), receiver(receiver_) {} DelayedImpulse(const DelayedImpulse& other) : impulse(other.impulse), delay(other.delay), receiver(other.receiver) {} bool tick(double dtime) { // returns true if Impulse has to be sent NOW delay -= dtime; return delay <= 0; } const GridPos& destination() const { return impulse.dest; } void send_impulse(Stone *target) const { // @@@ FIXME: the test for equality of Stones sometimes fails // (e.g. with turnstiles rotated by rotators) // // I guess this happens, because when the turnstile-pivot removes and add arms // during turn, it may happen, that the Stone receives the same memory address // // Possible fix : add unique ID to all objects if (target == receiver) { // if object did not change since impulse was initiated target->on_impulse(impulse); } } }; typedef list ImpulseList; }