1 /* Battle Tanks Game 2 * Copyright (C) 2006-2009 Battle Tanks team 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 */ 18 19 /* 20 * Additional rights can be granted beyond the GNU General Public License 21 * on the terms provided in the Exception. If you modify this file, 22 * you may extend this exception to your version of the file, 23 * but you are not obligated to do so. If you do not wish to provide this 24 * exception without modification, you must delete this exception statement 25 * from your version and license this file solely under the GPL without exception. 26 */ 27 28 #include "object.h" 29 #include "registrar.h" 30 #include "alarm.h" 31 #include "config.h" 32 #include "ai/targets.h" 33 #include "zbox.h" 34 #include "player_manager.h" 35 #include "mrt/random.h" 36 37 #define PIERCEABLE_PAIR(o1, o2) ((o1->piercing && o2->pierceable) || (o2->piercing && o1->pierceable)) 38 39 class ShilkaTurret : public Object { 40 public: tick(const float dt)41 void tick(const float dt) { 42 Object::tick(dt); 43 if (_parent == NULL) 44 throw_ex(("turret is only operable attached to shilka ")); 45 46 bool play_fire = false; 47 const bool fire_possible = _fire.tick(dt); 48 const bool alt_fire_possible = _special_fire.tick(dt); 49 50 51 if (_state.alt_fire && alt_fire_possible) { 52 _special_fire.reset(); 53 if (_parent->has_effect("dirt")) { 54 if (get_state().substr(0,4) == "fire") 55 cancel(); 56 57 static const std::string left_fire = "shilka-bullet-left"; 58 static const std::string right_fire = "shilka-bullet-right"; 59 std::string animation = "shilka-dirt-bullet-"; 60 animation += (_left_fire)?"left":"right"; 61 62 _parent->spawn("dirt-bullet", animation, v2<float>(), _direction); 63 64 play_fire = true; 65 } 66 } 67 68 if (_state.fire && fire_possible) { 69 _fire.reset(); 70 71 if (_parent->has_effect("ricochet")) { 72 _parent->spawn("ricochet-bullet(auto-aim)", "ricochet-bullet", v2<float>(), _direction); 73 play_fire = true; 74 _left_fire = ! _left_fire; 75 } else if (_parent->has_effect("dispersion")) { 76 77 if (alt_fire_possible) { 78 _special_fire.reset(); 79 _parent->spawn("dispersion-bullet", "dispersion-bullet", v2<float>(), _direction); 80 play_fire = true; 81 _left_fire = ! _left_fire; 82 }; 83 84 } else { 85 static const std::string left_fire = "shilka-bullet-left"; 86 static const std::string right_fire = "shilka-bullet-right"; 87 std::string animation = "shilka-bullet-"; 88 animation += (_left_fire)?"left":"right"; 89 90 _parent->spawn("shilka-bullet", animation, v2<float>(), _direction); 91 play_fire = true; 92 _left_fire = ! _left_fire; 93 } 94 } 95 96 if (play_fire) { 97 if (get_state().substr(0,4) == "fire") 98 cancel(); 99 100 play_now(_left_fire?"fire-left":"fire-right"); 101 } 102 103 104 } //end of tick() 105 calculate(const float dt)106 void calculate(const float dt) { 107 if (!_reaction.tick(dt)) 108 return; 109 110 if (_parent == NULL) 111 throw_ex(("turret is only operable attached to shilka ")); 112 113 if (_parent->disable_ai && PlayerManager->get_slot_by_id(_parent->get_id()) == NULL) { 114 Object::calculate(dt); 115 return; 116 } 117 118 v2<float> pos, vel; 119 std::set<const Object *> objects; 120 _parent->enumerate_objects(objects, getWeaponRange("shilka-bullet"), &ai::Targets->troops); 121 122 int dirs = get_directions_number(); 123 //int parent_dir = _parent->get_direction(); 124 //(_parent->get_direction() - _parent->get_directions_number() / 2) * get_directions_number() / _parent->get_directions_number(); 125 126 const Object *target = NULL; 127 v2<float> target_pos; 128 for(std::set<const Object *>::iterator i = objects.begin(); i != objects.end(); ++i) { 129 const Object *o = *i; 130 if (o->get_id() == _parent->get_id() || o->impassability == 0 || o->hp <= 0 || 131 PIERCEABLE_PAIR(_parent, o) || !ZBox::sameBox(_parent->get_z(), o->get_z()) || _parent->has_same_owner(o) || 132 o->has_effect("invulnerability") 133 ) 134 continue; 135 136 pos = get_relative_position(o); 137 if (target == NULL || pos.quick_length() < target_pos.quick_length()) { 138 target = o; 139 target_pos = pos; 140 } 141 //LOG_DEBUG(("%s <- dir: %d, parent_dir: %d (%g, %g)", o->animation.c_str(), dir, parent_dir, pos.x, pos.y)); 142 } 143 144 target_pos.normalize(); 145 int dir = target_pos.get_direction(dirs) - 1; 146 147 if (target == NULL || dir < 0) { 148 Object::calculate(dt); 149 return; 150 } 151 152 _direction = target_pos; 153 set_direction(dir); 154 } 155 on_spawn()156 void on_spawn() { 157 play("hold", true); 158 GET_CONFIG_VALUE("objects.shilka.fire-rate", float, fr, 0.2f); 159 _fire.set(fr); 160 GET_CONFIG_VALUE("objects.shilka.special-fire-rate", float, sfr, 0.4f); 161 _special_fire.set(sfr); 162 } 163 ShilkaTurret()164 ShilkaTurret() : Object("turrel"), _reaction(true), _fire(false), _special_fire(false), _left_fire(false) { 165 impassability = 0; 166 hp = -1; 167 set_directions_number(16); 168 pierceable = true; 169 float rt = 0.1f; 170 mrt::randomize(rt, rt/10); 171 _reaction.set(rt); 172 } 173 serialize(mrt::Serializator & s) const174 virtual void serialize(mrt::Serializator &s) const { 175 Object::serialize(s); 176 s.add(_reaction); 177 s.add(_fire); 178 s.add(_special_fire); 179 s.add(_left_fire); 180 } 181 deserialize(const mrt::Serializator & s)182 virtual void deserialize(const mrt::Serializator &s) { 183 Object::deserialize(s); 184 s.get(_reaction); 185 s.get(_fire); 186 s.get(_special_fire); 187 s.get(_left_fire); 188 } 189 clone() const190 virtual Object * clone() const { return new ShilkaTurret(*this); } 191 192 193 private: 194 Alarm _reaction, _fire, _special_fire; 195 bool _left_fire; 196 }; 197 198 REGISTER_OBJECT("shilka-turret", ShilkaTurret, ()); 199