/* weapons.cpp - weapons and other equipment Copyright (C) 2006 Mark boyd 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 fun to play, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "weapons.h" #include "explosion.h" #include "game.h" #include "enemies.h" #include "etc.h" void shot_det(mover *m, mover *victim); void shover_det(mover *m, mover *victim); void rocket_det(mover *m, mover *victim); void flakker_det(mover *m, mover *victim); void plasmoid_det(mover *m, mover *victim); void scatter_det(mover *m, mover *victim); void sniper_det(mover *m, mover *victim); void rbg_det(mover *m, mover *victim); void scatter_exp(mover *m); void rbg_exp(mover *m); namespace{ using namespace sound; struct weapon_type wt_table[]= {// sp dam game rec del detonation expiration shop ene sound shop // Name Cost eed ttl age graphic oil ay function function graphic mass rgy description {"Nothing", 0, 0, 0.0, 0, 0, 0, 0, NULL, NULL, NULL, 0, 0, SILENCE, "Two cubic metres of empty space"}, {"Peashooter", 300, 300, 0.8, 1, "shot.png", 0, 5, &shot_det, NULL, "peashooter.png", 1, 1, PFFT, "Basic weapon system"}, {"Rapishooter",800, 300, 0.8, 1, "shot.png", 0, 2, &shot_det, NULL, "s_rapishooter.png", 2, 1, PFFT, "Rapid-fire peashooter"}, {"Shover", 500, 400, 0.8, 2, "shover.png", 5, 5, &shover_det, NULL, "s_shover.png", 3, 2, DOOF, "Very massive projectile"}, {"Rocket", 1500, 800, 0.8, 5, "rocket.png", 20, 15, &rocket_det, NULL, "s_rocket.png", 2, 10, SILENCE, "Explosive warhead"}, {"Implosion", 3000, 250, 1.2, 6, "shot.png", 2, 7, &flakker_det, NULL, "s_implosion.png", 10, 6, SILENCE, "Good anti-mob weapon"}, {"Plasmoid", 3000, 500, 1.5, 8, "plasmoid.png", 4, 4, &plasmoid_det, NULL, "s_plasmoid.png", 7, 15, SILENCE, "Ultimate weapon?"}, {"Scatter", 2000, 600, 0.3, 16, "shover.png", 3, 3, &scatter_det, scatter_exp, "s_scatter.png", 5, 20, SILENCE, "Fragmentation weapon"}, {"Sniper", 2000, 1000, 0.4, 10, "wshot.png", 100, 6, &sniper_det, NULL, "s_sniper.png", 3, 15, SILENCE, "?"}, {"R.B.G", 3000, 350, 0.5, 0, "wshot.png", 0, 10, &rbg_det, rbg_exp, "s_rbg.png", 20, 30, SILENCE, "Recking Ball generator"}, //todo: need more sound FX to use here }; } struct engine_type et_table[]= { // name cost thrust mass shop description {"Piffler", 100, 1875.0, 1, "Basic Engine"}, {"Thruster", 500, 3125.0, 3, "Better Engine"}, {"Streaker", 2500, 7500.0, 6, "Powerful Engine"}, }; //Systems have various effects, and most of them aren't in this file - //it's all done with special hacks in random places :( struct system_type st_table[]= {// Name cost mass shop bmp shop description {"Empty", 0, 0, NULL, "A large chunk of empty space"}, {"Generator", 500, 1, "s_generator.png", "Increases energy recharge rate"}, {"Battery", 500, 1, "s_battery.png", "Increases maximum energy"}, {"Lead", 1, 20, "s_lead.png", "Increases ship mass. A lot."}, {"Generator++", 2500, 2, "s_generator2.png", "3 times the standard generator output."}, }; const std::vector &weapon_types() { static std::vector types; if (types.size()==0) { for(int i=0; i &engine_types() { static std::vector types; if (types.size()==0) { for(int i=0; i &system_types() { static std::vector types; if (types.size()==0) { for(int i=0; im_exp_pool.get_explosion(dynamic_cast(m)->pic_name(), m->pic()); e->teleport_centre(m->x_centre(), m->y_centre()); game::the_game->m_arena->add_mover(e); enemy *en = dynamic_cast(victim); if (en) { en->take_hit(1); } m->die(); } void shover_det(mover *m, mover *victim) { //Apply shoving! if (victim && victim->m_mass && !victim->is_stuck()) { victim->m_dx += m->m_dx*0.9/victim->m_mass; victim->m_dy += m->m_dy*0.9/victim->m_mass; } enemy *en = dynamic_cast(victim); if (en) { en->take_hit(2); } m->die(); } void flakker_det(mover *m, mover *victim) { const int dam_radius=100; const int dam_centre=7; const int dam_edge=1; const int blast_radius=150; const float blast_edge=20; arena &the_arena=*(game::the_game->m_arena); the_arena.AOE_damage(m->x_centre(), m->y_centre(), dam_radius, dam_centre, dam_edge, HURT_ENEMIES); //Since the force "damage" is negative, this sucks objects towards the centre of the blast the_arena.AOE_force(m->x_centre(), m->y_centre(), blast_radius, 0, -blast_edge); m->die(); } void rocket_det(mover *m, mover *victim) { const int dam_radius=50; const int dam_centre=5; const int dam_edge=1; const int blast_radius=150; const float blast_centre=40; const float blast_edge=0; arena &the_arena=*(game::the_game->m_arena); the_arena.AOE_damage(m->x_centre(), m->y_centre(), dam_radius, dam_centre, dam_edge, HURT_ENEMIES); the_arena.AOE_force(m->x_centre(), m->y_centre(), blast_radius, blast_centre, blast_edge); sound::play(sound::BOOM); m->die(); } //Notice that we can "detonate" multiple times! //Plasmoids don't die on contact with enemies, making it possible to //blow rows of enemies away with a single shot. //Also, large enemies can be hit multiple times by the same plasmoid //(Annoyingly, this is framerate-dependant) void plasmoid_det(mover *m, mover *victim) { enemy *en = dynamic_cast(victim); if (en) { en->take_hit(8); } } void scatter_exp(mover *m) { const int n=16; const weapon_type &wt=weapon_types()[WT_PEASHOOTER]; for(int i=0; iteleport_centre(m->m_x,m->m_y); s->m_dx=/*m->m_dx+*/wt.exit_speed*sin(2.0*pi*i/n); s->m_dy=/*m->m_dy+*/wt.exit_speed*cos(2.0*pi*i/n); game::the_game->m_arena->add_mover(s); } } void scatter_det(mover *m, mover *victim) { enemy *en = dynamic_cast(victim); if (en) { //explodes on impact! scatter_exp(m); } m->die(); } void sniper_det(mover *m, mover *victim) { enemy *en = dynamic_cast(victim); if (en) { //Don't stop for enemies that can't absorb all the damage //This means the shot can blow up rows of weak enemies if (en->take_hit(10) >= 10) { m->die(); } } } void rbg_det(mover *m, mover *) { recking_ball *rb=new recking_ball; rb->teleport_centre(m->x_centre(), m->y_centre()); game::the_game->m_arena->add_mover(rb); m->die(); } void rbg_exp(mover *m) { recking_ball *rb=new recking_ball; rb->teleport_centre(m->x_centre(), m->y_centre()); game::the_game->m_arena->add_mover(rb); m->die(); }