/* * 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: actors.cc,v 1.1 2003/01/05 19:56:39 dheck Exp $ */ #include "enigma.hh" #include "actors.hh" #include "player.hh" #include "sound.hh" #include "objects.hh" #include "object_mixins.hh" #include "world.hh" using px::V3; using namespace world; //====================================================================== // ACTORS //====================================================================== Actor::Actor(const char *kind, const px::V3 &p) : Object(kind), actorinfo(p, V3()), startingpos(p), respawnpos(), use_respawnpos(false) { set_attrib("mouseforce", 0.0); sprite_id = 0; } void Actor::respawn() { V3 p =(use_respawnpos) ? respawnpos : startingpos; warp (p); // move(); on_respawn(p); } void Actor::init() { sprite_id = AddSprite(display::SPRITE_ACTOR, actorinfo.pos); } void Actor::set_attrib(const string &key, const Value &val) { Object::set_attrib(key, val); } void Actor::on_creation(const px::V3 &p) { startingpos = p; set_model(get_kind(), p); move(); } void Actor::on_respawn (const px::V3 &pos) { } enigma::GridPos get_field(px::V3 p) { return enigma::GridPos(static_cast(p[0]), static_cast(p[1])); } void Actor::warp(const px::V3 &newpos) { actorinfo.pos = newpos; actorinfo.vel = V3(); display::MoveSprite(sprite_id, actorinfo.pos); move(); //on_motion(actorinfo.pos); } void Actor::move() { using namespace world; GridPos field = get_field(actorinfo.pos); GridPos ofield = get_field(actorinfo.oldpos); if (field != ofield) { if (Floor *fl = GetFloor(field)) fl->actor_enter(this); if (Floor *ofl = GetFloor(ofield)) ofl->actor_leave(this); if (Item *it = GetItem(field)) it->actor_enter(this); if (Item *oit = GetItem(ofield)) oit->actor_leave(this); } if (Floor *fl = GetFloor(field)) fl->actor_hit(this); if (Item *it = GetItem(field)) if (it->actor_hit(this)) player::PickupItem(this, field); if (Stone *st = GetStone(field)) st->actor_inside(this); display::MoveSprite(sprite_id, actorinfo.pos); on_motion(actorinfo.pos); } void Actor::set_model(const string &mname, const px::V3 &pos) { // sprite_id = AddSprite(display::SPRITE_ACTOR, pos, mname.c_str()); display::MoveSprite(sprite_id, pos); display::ReplaceSprite(sprite_id, mname.c_str()); } void Actor::set_model(const string &name) { display::ReplaceSprite(sprite_id, name.c_str()); } //---------------------------------------- // Rotor //---------------------------------------- namespace { class Rotor : public Actor { public: Rotor(); private: // Actor interface. bool is_dead() { return false; } // Object interface. Object* clone() { return new Rotor; } void dispose() { delete this; } }; } Rotor::Rotor() : Actor("ac-rotor", V3()) { world::ActorInfo *ai = get_actorinfo(); ai->radius = 20/64.0; ai->mass = 0.8; } //---------------------------------------- // BasicBall //---------------------------------------- namespace { class BasicBall : public Actor, public display::ModelCallback { protected: BasicBall(const char *kind, double radius, double mass); enum State { NO_STATE, NORMAL, SHATTERING, DROWNING, FALLING, JUMPING, DEAD, APPEARING, DISAPPEARING, }; State state; void set_model_cb(const string &m) { set_model(m.c_str()); display::SetCallback(get_spriteid(), this); } void change_state(State newstate); // ModelCallback interface. void animcb(); // Actor interface. void on_creation(const px::V3 &p) { Actor::on_creation(p); change_state(APPEARING); } void on_respawn (const px::V3 &pos) { change_state(APPEARING); } bool is_dead() { return state == DEAD; } bool is_flying() { return state == JUMPING; } bool is_on_floor() { return state == NORMAL; } bool can_drop_items() { return state==NORMAL || state==JUMPING; } bool can_pickup_items() { return state==NORMAL; } // Object interface. void message(const string &m, const Value &); }; } BasicBall::BasicBall(const char *kind, double radius, double mass) : Actor(kind, V3()) , state(NO_STATE) { world::ActorInfo *ai = get_actorinfo(); ai->radius = radius; ai->mass = mass; } void BasicBall::message(const string &m, const Value &) { if (state == NORMAL) { if (m == "shatter") change_state(SHATTERING); else if (m == "fall") change_state(FALLING); else if (m == "drown") change_state(DROWNING); else if (m == "jump") change_state(JUMPING); else if (m == "appear") change_state(APPEARING); else if (m == "disappear") change_state(DISAPPEARING); } } void BasicBall::animcb() { string kind=get_kind(); switch (state) { case SHATTERING: set_model(kind+"-shattered"); change_state(DEAD); break; case FALLING: sound::PlaySound("shatter"); set_model(kind+"-fallen"); change_state(DEAD); break; case DROWNING: set_model("invisible"); change_state(DEAD); break; case JUMPING: set_model(kind); change_state(NORMAL); break; case APPEARING: set_model(kind); change_state(NORMAL); break; case DISAPPEARING: set_model("ringanim"); break; default: break; } } void BasicBall::change_state(State newstate) { if (newstate == state) return; string kind=get_kind(); switch (newstate) { case NORMAL: world::ReleaseActor(this); break; case SHATTERING: sound::PlaySound("shatter"); world::GrabActor(this); set_model_cb(kind+"-shatter"); break; case DROWNING: world::GrabActor(this); sound::PlaySound("drown"); set_model_cb("ring-anim"); break; case FALLING: world::GrabActor(this); set_model_cb(kind+"-fall"); break; case DEAD: break; case JUMPING: sound::PlaySound("boink"); set_model_cb(kind+"-jump"); break; case APPEARING: set_model_cb(kind+"-appear"); world::GrabActor(this); break; case DISAPPEARING: world::GrabActor(this); set_model_cb(kind+"-drown"); break; default: break; } state = newstate; } //---------------------------------------- // Balls of different sorts //---------------------------------------- namespace { class BlackBall : public BasicBall { CLONEOBJ(BlackBall); public: BlackBall() : BasicBall("ac-blackball", 19.0/64.0, 1.0) { set_attrib("mouseforce", Value(true)); set_attrib("color", Value(0.0)); set_attrib("blackball", Value(true)); } }; class WhiteBall : public BasicBall { CLONEOBJ(WhiteBall); public: WhiteBall() : BasicBall("ac-whiteball", 19.0/64.0, 1.0) { set_attrib("mouseforce", Value(true)); set_attrib("color", Value(0.0)); set_attrib("whiteball", Value(double(true))); } }; class WhiteBall_Small : public BasicBall { CLONEOBJ(WhiteBall_Small); public: WhiteBall_Small() : BasicBall("ac-whiteball-small", 13/64.0, 0.7) {} }; } void actors::Init() { using world::Register; Register(new Rotor); Register(new BlackBall); Register(new WhiteBall); Register(new WhiteBall_Small); }