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