From bbc091a52439e4942cfa614a6c16b3f530dfab8a Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Sun, 27 May 2007 10:01:09 +0000 Subject: [PATCH] remove dead_script_hint, add scripting capabilities to willowisp, willowisps can have paths now SVN-Revision: 5057 --- src/badguy/badguy.cpp | 17 ++--- src/badguy/badguy.hpp | 1 - src/badguy/willowisp.cpp | 148 +++++++++++++++++++++++++++++------- src/badguy/willowisp.hpp | 25 +++++- src/badguy/yeti.cpp | 1 - src/lisp/lexer.cpp | 2 +- src/scripting/willowisp.hpp | 48 ++++++++++++ src/scripting/wrapper.cpp | 114 +++++++++++++++++++++++++++ src/scripting/wrapper.hpp | 1 + src/scripting/wrapper.interface.hpp | 1 + src/sector.cpp | 6 +- 11 files changed, 317 insertions(+), 47 deletions(-) create mode 100644 src/scripting/willowisp.hpp diff --git a/src/badguy/badguy.cpp b/src/badguy/badguy.cpp index 2d1b68ef0..19e8d8b49 100644 --- a/src/badguy/badguy.cpp +++ b/src/badguy/badguy.cpp @@ -36,7 +36,9 @@ static const float X_OFFSCREEN_DISTANCE = 1600; static const float Y_OFFSCREEN_DISTANCE = 1200; BadGuy::BadGuy(const Vector& pos, const std::string& sprite_name, int layer) - : MovingSprite(pos, sprite_name, layer, COLGROUP_DISABLED), countMe(true), dir(LEFT), start_dir(AUTO), frozen(false), ignited(false), draw_dead_script_hint(false), state(STATE_INIT), on_ground_flag(false) + : MovingSprite(pos, sprite_name, layer, COLGROUP_DISABLED), countMe(true), + dir(LEFT), start_dir(AUTO), frozen(false), ignited(false), + state(STATE_INIT), on_ground_flag(false) { start_position = bbox.p1; @@ -45,7 +47,9 @@ BadGuy::BadGuy(const Vector& pos, const std::string& sprite_name, int layer) } BadGuy::BadGuy(const Vector& pos, Direction direction, const std::string& sprite_name, int layer) - : MovingSprite(pos, sprite_name, layer, COLGROUP_DISABLED), countMe(true), dir(direction), start_dir(direction), frozen(false), ignited(false), draw_dead_script_hint(false), state(STATE_INIT), on_ground_flag(false) + : MovingSprite(pos, sprite_name, layer, COLGROUP_DISABLED), countMe(true), + dir(direction), start_dir(direction), frozen(false), ignited(false), + state(STATE_INIT), on_ground_flag(false) { start_position = bbox.p1; @@ -64,7 +68,6 @@ BadGuy::BadGuy(const lisp::Lisp& reader, const std::string& sprite_name, int lay dir = start_dir; reader.get("dead-script", dead_script); - draw_dead_script_hint = (dead_script != ""); sound_manager->preload("sounds/squish.wav"); sound_manager->preload("sounds/fall.wav"); @@ -84,11 +87,6 @@ BadGuy::draw(DrawingContext& context) context.set_drawing_effect(old_effect); } else { sprite->draw(context, get_pos(), layer); - if (draw_dead_script_hint) { - Vector ppos = Vector(systemRandom.randf(bbox.p1.x+8, bbox.p2.x-8), bbox.p2.y); - Vector pspeed = Vector(0, -100); - Sector::current()->add_object(new Particles(ppos, 44, 46, pspeed, Vector(0,0), 1, Color(.6f, .2f, .2f), 3, .1f, LAYER_OBJECTS+1)); - } } } @@ -356,7 +354,8 @@ BadGuy::kill_fall() void BadGuy::run_dead_script() { - if (countMe) Sector::current()->get_level()->stats.badguys++; + if (countMe) + Sector::current()->get_level()->stats.badguys++; // start dead-script if(dead_script != "") { diff --git a/src/badguy/badguy.hpp b/src/badguy/badguy.hpp index f9592868d..6c1816612 100644 --- a/src/badguy/badguy.hpp +++ b/src/badguy/badguy.hpp @@ -229,7 +229,6 @@ protected: bool ignited; /**< true if this badguy is currently on fire */ std::string dead_script; /**< script to execute when badguy is killed */ - bool draw_dead_script_hint; /**< whether to draw a visual indication that this Badguy triggers a script */ private: void try_activate(); diff --git a/src/badguy/willowisp.cpp b/src/badguy/willowisp.cpp index a4fecd897..22ec6171b 100644 --- a/src/badguy/willowisp.cpp +++ b/src/badguy/willowisp.cpp @@ -24,6 +24,7 @@ #include "game_session.hpp" #include "object/lantern.hpp" #include "object/player.hpp" +#include "scripting/squirrel_util.hpp" static const float FLYSPEED = 64; /**< speed in px per second */ static const float TRACK_RANGE = 384; /**< at what distance to start tracking the player */ @@ -33,27 +34,30 @@ static const std::string SOUNDFILE = "sounds/willowisp.wav"; WillOWisp::WillOWisp(const lisp::Lisp& reader) : BadGuy(reader, "images/creatures/willowisp/willowisp.sprite", LAYER_FLOATINGOBJECTS), mystate(STATE_IDLE), target_sector("main"), target_spawnpoint("main") { + flyspeed = FLYSPEED; + track_range = TRACK_RANGE; + vanish_range = VANISH_RANGE; + reader.get("sector", target_sector); reader.get("spawnpoint", target_spawnpoint); + reader.get("name", name); + reader.get("flyspeed", flyspeed); + reader.get("track-range", track_range); + reader.get("vanish-range", vanish_range); + reader.get("hit-script", hit_script); + + const lisp::Lisp* pathLisp = reader.get_lisp("path"); + if(pathLisp != NULL) { + path.reset(new Path()); + path->read(*pathLisp); + walker.reset(new PathWalker(path.get(), false)); + } countMe = false; sound_manager->preload(SOUNDFILE); } void -WillOWisp::write(lisp::Writer& writer) -{ - writer.start_list("willowisp"); - - writer.write_float("x", start_position.x); - writer.write_float("y", start_position.y); - writer.write_string("sector", target_sector); - writer.write_string("spawnpoint", target_spawnpoint); - - writer.end_list("willowisp"); -} - -void WillOWisp::draw(DrawingContext& context) { sprite->draw(context, get_pos(), layer); @@ -75,36 +79,53 @@ WillOWisp::active_update(float elapsed_time) Vector p2 = player->get_pos() + (player->get_bbox().p2 - player->get_bbox().p1) / 2; Vector dist = (p2 - p1); - if (mystate == STATE_IDLE) { - if (dist.norm() <= TRACK_RANGE) { + switch(mystate) { + case STATE_STOPPED: + break; + + case STATE_IDLE: + if (dist.norm() <= track_range) { mystate = STATE_TRACKING; } - } + break; - if (mystate == STATE_TRACKING) { - if (dist.norm() <= VANISH_RANGE) { + case STATE_TRACKING: + if (dist.norm() <= vanish_range) { Vector dir = dist.unit(); - movement = dir*elapsed_time*FLYSPEED; + movement = dir * elapsed_time * flyspeed; } else { vanish(); } sound_source->set_position(get_pos()); - } + break; - if (mystate == STATE_WARPING) { + case STATE_WARPING: if(sprite->animation_done()) { remove_me(); } - } - if (mystate == STATE_VANISHING) { + case STATE_VANISHING: { Vector dir = dist.unit(); - movement = dir*elapsed_time*FLYSPEED; + movement = dir * elapsed_time * flyspeed; if(sprite->animation_done()) { remove_me(); } + break; } + case STATE_PATHMOVING: + case STATE_PATHMOVING_TRACK: + if(walker.get() == NULL) + return; + movement = walker->advance(elapsed_time) - get_pos(); + if(mystate == STATE_PATHMOVING_TRACK && dist.norm() <= track_range) { + mystate = STATE_TRACKING; + } + break; + + default: + assert(false); + } } void @@ -126,7 +147,10 @@ WillOWisp::deactivate() sound_source.reset(NULL); switch (mystate) { + case STATE_STOPPED: case STATE_IDLE: + case STATE_PATHMOVING: + case STATE_PATHMOVING_TRACK: break; case STATE_TRACKING: mystate = STATE_IDLE; @@ -149,24 +173,90 @@ WillOWisp::vanish() bool WillOWisp::collides(GameObject& other, const CollisionHit& ) { Lantern* lantern = dynamic_cast(&other); - if (lantern && lantern->is_open()) return true; - if (dynamic_cast(&other)) return true; + + if (lantern && lantern->is_open()) + return true; + + if (dynamic_cast(&other)) + return true; + return false; } HitResponse WillOWisp::collision_player(Player& player, const CollisionHit& ) { - if(player.is_invincible()) return ABORT_MOVE; + if(player.is_invincible()) + return ABORT_MOVE; - if (mystate != STATE_TRACKING) return ABORT_MOVE; + if (mystate != STATE_TRACKING) + return ABORT_MOVE; mystate = STATE_WARPING; sprite->set_action("warping", 1); - GameSession::current()->respawn(target_sector, target_spawnpoint); + if(hit_script != "") { + std::istringstream stream(hit_script); + Sector::current()->run_script(stream, "hit-script"); + } else { + GameSession::current()->respawn(target_sector, target_spawnpoint); + } sound_manager->play("sounds/warp.wav"); return CONTINUE; } +void +WillOWisp::goto_node(int node_no) +{ + walker->goto_node(node_no); + if(mystate != STATE_PATHMOVING && mystate != STATE_PATHMOVING_TRACK) { + mystate = STATE_PATHMOVING; + walker->start_moving(); + } +} + +void +WillOWisp::set_state(const std::string& new_state) +{ + if(new_state == "stopped") { + mystate = STATE_STOPPED; + } else if(new_state == "idle") { + mystate = STATE_IDLE; + } else if(new_state == "move_path") { + mystate = STATE_PATHMOVING; + walker->start_moving(); + } else if(new_state == "move_path_track") { + mystate = STATE_PATHMOVING_TRACK; + walker->start_moving(); + } else if(new_state == "normal") { + mystate = STATE_IDLE; + } else { + std::ostringstream msg; + msg << "Can't set unknown willowisp state '" << new_state << "', should " + "be stopped, move_path, move_path_track or normal"; + throw new std::runtime_error(msg.str()); + } +} + +void +WillOWisp::expose(HSQUIRRELVM vm, SQInteger table_idx) +{ + if (name.empty()) + return; + + std::cout << "Expose me '" << name << "'\n"; + Scripting::WillOWisp* interface = static_cast (this); + expose_object(vm, table_idx, interface, name); +} + +void +WillOWisp::unexpose(HSQUIRRELVM vm, SQInteger table_idx) +{ + if (name.empty()) + return; + + std::cout << "UnExpose me '" << name << "'\n"; + Scripting::unexpose_object(vm, table_idx, name); +} + IMPLEMENT_FACTORY(WillOWisp, "willowisp") diff --git a/src/badguy/willowisp.hpp b/src/badguy/willowisp.hpp index c21933d53..d9401c8a0 100644 --- a/src/badguy/willowisp.hpp +++ b/src/badguy/willowisp.hpp @@ -22,8 +22,13 @@ #define __WILLOWISP_H__ #include "badguy.hpp" +#include "object/path.hpp" +#include "object/path_walker.hpp" +#include "script_interface.hpp" +#include "scripting/willowisp.hpp" -class WillOWisp : public BadGuy +class WillOWisp : public BadGuy, public Scripting::WillOWisp, + public ScriptInterface { public: WillOWisp(const lisp::Lisp& reader); @@ -31,7 +36,6 @@ public: void activate(); void deactivate(); - void write(lisp::Writer& write); void active_update(float elapsed_time); virtual bool is_flammable() const { return false; } virtual bool is_freezable() const { return false; } @@ -44,20 +48,35 @@ public: virtual void draw(DrawingContext& context); + virtual void goto_node(int node_no); + virtual void set_state(const std::string& state); + + virtual void expose(HSQUIRRELVM vm, SQInteger table_idx); + virtual void unexpose(HSQUIRRELVM vm, SQInteger table_idx); + protected: virtual bool collides(GameObject& other, const CollisionHit& hit); HitResponse collision_player(Player& player, const CollisionHit& hit); private: enum MyState { - STATE_IDLE, STATE_TRACKING, STATE_VANISHING, STATE_WARPING + STATE_STOPPED, STATE_IDLE, STATE_TRACKING, STATE_VANISHING, STATE_WARPING, + STATE_PATHMOVING, STATE_PATHMOVING_TRACK }; MyState mystate; std::string target_sector; std::string target_spawnpoint; + std::string hit_script; std::auto_ptr sound_source; + + std::auto_ptr path; + std::auto_ptr walker; + + float flyspeed; + float track_range; + float vanish_range; }; #endif diff --git a/src/badguy/yeti.cpp b/src/badguy/yeti.cpp index 5578d0d71..79959257d 100644 --- a/src/badguy/yeti.cpp +++ b/src/badguy/yeti.cpp @@ -60,7 +60,6 @@ Yeti::Yeti(const lisp::Lisp& reader) sound_manager->preload("sounds/yeti_gna.wav"); sound_manager->preload("sounds/yeti_roar.wav"); hud_head.reset(new Surface("images/creatures/yeti/hudlife.png")); - draw_dead_script_hint = false; } Yeti::~Yeti() diff --git a/src/lisp/lexer.cpp b/src/lisp/lexer.cpp index 4e4f2fb6d..c9daf4b69 100644 --- a/src/lisp/lexer.cpp +++ b/src/lisp/lexer.cpp @@ -130,7 +130,7 @@ Lexer::getNextToken() } catch(EOFException& ) { std::stringstream msg; msg << "Parse error in line " << startline << ": " - << "EOF while parsing string."; + << "EOF while parsing string."; throw std::runtime_error(msg.str()); } nextChar(); diff --git a/src/scripting/willowisp.hpp b/src/scripting/willowisp.hpp new file mode 100644 index 000000000..fb1be1256 --- /dev/null +++ b/src/scripting/willowisp.hpp @@ -0,0 +1,48 @@ +// $Id$ +// +// SuperTux +// Copyright (C) 2007 Matthias Braun +// +// 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. + +#ifndef __SCRIPTING_WILLOWISP_H__ +#define __SCRIPTING_WILLOWISP_H__ + +namespace Scripting +{ + +class WillOWisp +{ +public: +#ifndef SCRIPTING_API + virtual ~WillOWisp() + {} +#endif + + /** Move willowisp to given node */ + virtual void goto_node(int node_no) = 0; + + /** set willowisp state can be: + * -stopped willowisp doesn't move + * -move_path willowisp moves along the path (call goto_node) + * -move_path_track willowisp moves along path but catchs tux when he is near + * -normal "normal" mode starts tracking tux when he is near enough + */ + virtual void set_state(const std::string& state) = 0; +}; + +} + +#endif diff --git a/src/scripting/wrapper.cpp b/src/scripting/wrapper.cpp index 91c0cda0b..a47c84ec2 100644 --- a/src/scripting/wrapper.cpp +++ b/src/scripting/wrapper.cpp @@ -2895,6 +2895,71 @@ static SQInteger LevelTime_set_time_wrapper(HSQUIRRELVM vm) } +static SQInteger WillOWisp_release_hook(SQUserPointer ptr, SQInteger ) +{ + Scripting::WillOWisp* _this = reinterpret_cast (ptr); + delete _this; + return 0; +} + +static SQInteger WillOWisp_goto_node_wrapper(HSQUIRRELVM vm) +{ + SQUserPointer data; + if(SQ_FAILED(sq_getinstanceup(vm, 1, &data, 0))) { + sq_throwerror(vm, _SC("'goto_node' called without instance")); + return SQ_ERROR; + } + Scripting::WillOWisp* _this = reinterpret_cast (data); + SQInteger arg0; + if(SQ_FAILED(sq_getinteger(vm, 2, &arg0))) { + sq_throwerror(vm, _SC("Argument 1 not an integer")); + return SQ_ERROR; + } + + try { + _this->goto_node(static_cast (arg0)); + + return 0; + + } catch(std::exception& e) { + sq_throwerror(vm, e.what()); + return SQ_ERROR; + } catch(...) { + sq_throwerror(vm, _SC("Unexpected exception while executing function 'goto_node'")); + return SQ_ERROR; + } + +} + +static SQInteger WillOWisp_set_state_wrapper(HSQUIRRELVM vm) +{ + SQUserPointer data; + if(SQ_FAILED(sq_getinstanceup(vm, 1, &data, 0))) { + sq_throwerror(vm, _SC("'set_state' called without instance")); + return SQ_ERROR; + } + Scripting::WillOWisp* _this = reinterpret_cast (data); + const SQChar* arg0; + if(SQ_FAILED(sq_getstring(vm, 2, &arg0))) { + sq_throwerror(vm, _SC("Argument 1 not a string")); + return SQ_ERROR; + } + + try { + _this->set_state(arg0); + + return 0; + + } catch(std::exception& e) { + sq_throwerror(vm, e.what()); + return SQ_ERROR; + } catch(...) { + sq_throwerror(vm, _SC("Unexpected exception while executing function 'set_state'")); + return SQ_ERROR; + } + +} + static SQInteger display_wrapper(HSQUIRRELVM vm) { return Scripting::display(vm); @@ -3912,6 +3977,32 @@ void create_squirrel_instance(HSQUIRRELVM v, Scripting::LevelTime* object, bool sq_remove(v, -2); // remove root table } +void create_squirrel_instance(HSQUIRRELVM v, Scripting::WillOWisp* object, bool setup_releasehook) +{ + using namespace Wrapper; + + sq_pushroottable(v); + sq_pushstring(v, "WillOWisp", -1); + if(SQ_FAILED(sq_get(v, -2))) { + std::ostringstream msg; + msg << "Couldn't resolved squirrel type 'WillOWisp'"; + throw SquirrelError(v, msg.str()); + } + + if(SQ_FAILED(sq_createinstance(v, -1)) || SQ_FAILED(sq_setinstanceup(v, -1, object))) { + std::ostringstream msg; + msg << "Couldn't setup squirrel instance for object of type 'WillOWisp'"; + throw SquirrelError(v, msg.str()); + } + sq_remove(v, -2); // remove object name + + if(setup_releasehook) { + sq_setreleasehook(v, -1, WillOWisp_release_hook); + } + + sq_remove(v, -2); // remove root table +} + void register_supertux_wrapper(HSQUIRRELVM v) { using namespace Wrapper; @@ -4927,6 +5018,29 @@ void register_supertux_wrapper(HSQUIRRELVM v) throw SquirrelError(v, "Couldn't register class 'LevelTime'"); } + // Register class WillOWisp + sq_pushstring(v, "WillOWisp", -1); + if(sq_newclass(v, SQFalse) < 0) { + std::ostringstream msg; + msg << "Couldn't create new class 'WillOWisp'"; + throw SquirrelError(v, msg.str()); + } + sq_pushstring(v, "goto_node", -1); + sq_newclosure(v, &WillOWisp_goto_node_wrapper, 0); + if(SQ_FAILED(sq_createslot(v, -3))) { + throw SquirrelError(v, "Couldn't register function 'goto_node'"); + } + + sq_pushstring(v, "set_state", -1); + sq_newclosure(v, &WillOWisp_set_state_wrapper, 0); + if(SQ_FAILED(sq_createslot(v, -3))) { + throw SquirrelError(v, "Couldn't register function 'set_state'"); + } + + if(SQ_FAILED(sq_createslot(v, -3))) { + throw SquirrelError(v, "Couldn't register class 'WillOWisp'"); + } + } } // end of namespace Scripting diff --git a/src/scripting/wrapper.hpp b/src/scripting/wrapper.hpp index cc6e43e3a..9deb6ef13 100644 --- a/src/scripting/wrapper.hpp +++ b/src/scripting/wrapper.hpp @@ -29,6 +29,7 @@ void create_squirrel_instance(HSQUIRRELVM v, Scripting::Thunderstorm* object, bo void create_squirrel_instance(HSQUIRRELVM v, Scripting::TileMap* object, bool setup_releasehook = false); void create_squirrel_instance(HSQUIRRELVM v, Scripting::SSector* object, bool setup_releasehook = false); void create_squirrel_instance(HSQUIRRELVM v, Scripting::LevelTime* object, bool setup_releasehook = false); +void create_squirrel_instance(HSQUIRRELVM v, Scripting::WillOWisp* object, bool setup_releasehook = false); } diff --git a/src/scripting/wrapper.interface.hpp b/src/scripting/wrapper.interface.hpp index c28ce590e..d95dd6770 100644 --- a/src/scripting/wrapper.interface.hpp +++ b/src/scripting/wrapper.interface.hpp @@ -16,3 +16,4 @@ #include "tilemap.hpp" #include "ssector.hpp" #include "level_time.hpp" +#include "willowisp.hpp" diff --git a/src/sector.cpp b/src/sector.cpp index aa95d7c9f..57418fd83 100644 --- a/src/sector.cpp +++ b/src/sector.cpp @@ -897,10 +897,10 @@ void check_collisions(collision::Constraints* constraints, return; // calculate intersection - float itop = r1.get_bottom() - r2.get_top(); + float itop = r1.get_bottom() - r2.get_top(); float ibottom = r2.get_bottom() - r1.get_top(); - float ileft = r1.get_right() - r2.get_left(); - float iright = r2.get_right() - r1.get_left(); + float ileft = r1.get_right() - r2.get_left(); + float iright = r2.get_right() - r1.get_left(); if(fabsf(movement.y) > fabsf(movement.x)) { if(ileft < SHIFT_DELTA) { -- 2.11.0