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 "mrt/random.h"
33 #include "ai/herd.h"
34 #include "ai/targets.h"
35 
36 class BaseZombie : public Object {
37 public:
clone() const38 	virtual Object * clone() const { return new BaseZombie(*this); }
BaseZombie(const std::string & classname)39 	BaseZombie(const std::string &classname): Object(classname), _can_punch(true) {}
40 
get_impassability_penalty(const float impassability,float & base,float & base_value,float & penalty) const41 	void get_impassability_penalty(const float impassability, float &base, float &base_value, float &penalty) const {
42 		if (impassability > 0.2f) {
43 			base_value = 0.2f;
44 			base = 0;
45 			penalty = 0;
46 		}
47 	}
48 
49 	virtual void on_spawn();
50 	virtual void tick(const float dt);
51 	virtual void emit(const std::string &event, Object * emitter = NULL);
take(const BaseObject * obj,const std::string & type)52 	const bool take(const BaseObject *obj, const std::string &type) {
53 		return false;
54 	}
55 
serialize(mrt::Serializator & s) const56 	virtual void serialize(mrt::Serializator &s) const {
57 		Object::serialize(s);
58 		s.add(_can_punch);
59 	}
60 
deserialize(const mrt::Serializator & s)61 	virtual void deserialize(const mrt::Serializator &s) {
62 		Object::deserialize(s);
63 		s.get(_can_punch);
64 	}
65 
66 private:
67 	bool _can_punch;
68 };
69 
on_spawn()70 void BaseZombie::on_spawn() {
71 	play("hold", true);
72 	disown();
73 }
74 
tick(const float dt)75 void BaseZombie::tick(const float dt) {
76 	Object::tick(dt);
77 
78 	if (_state.fire && get_state() != "punch") {
79 		_can_punch = true;
80 		play_now("punch");
81 		return;
82 	}
83 
84 	if (_velocity.is0()) {
85 		if (get_state() != "hold") {
86 			cancel_all();
87 			play("hold", true);
88 		}
89 	} else {
90 		if (get_state() == "hold") {
91 			cancel_all();
92 			play("walk", true);
93 		}
94 	}
95 }
96 
97 
emit(const std::string & event,Object * emitter)98 void BaseZombie::emit(const std::string &event, Object * emitter) {
99 	if (event == "death") {
100 		spawn("corpse(zombie-death)", "dead-zombie", v2<float>(), v2<float>());
101 	} else if (emitter != NULL && event == "collision") {
102 		if (get_state() != "punch" && emitter->registered_name != "zombie") {
103 			_state.fire = true;
104 		}
105 		if (_state.fire && _can_punch && get_state_progress() >= 0.5 && get_state() == "punch" && emitter->registered_name != "zombie") {
106 			_can_punch = false;
107 
108 			GET_CONFIG_VALUE("objects.zombie.damage", int, kd, 15);
109 
110 			if (emitter && emitter->classname != "explosion")
111 				emitter->add_damage(this, kd);
112 
113 			return;
114 		}
115 
116 	}
117 	Object::emit(event, emitter);
118 }
119 
120 
121 
122 
123 /*============================================
124 				ai zombie
125 ============================================*/
126 
127 class Zombie : public BaseZombie, public ai::Herd{
128 public:
Zombie(const std::string & classname)129 	Zombie(const std::string &classname) :
130 	BaseZombie(classname), _reaction(true) {
131 	}
132 
133 	virtual void calculate(const float dt);
134 
135 	virtual Object * clone() const;
136 	virtual void on_spawn();
137 
serialize(mrt::Serializator & s) const138 	virtual void serialize(mrt::Serializator &s) const {
139 		BaseZombie::serialize(s);
140 		s.add(_reaction);
141 	}
deserialize(const mrt::Serializator & s)142 	virtual void deserialize(const mrt::Serializator &s) {
143 		BaseZombie::deserialize(s);
144 		s.get(_reaction);
145 	}
146 
147 	virtual void onIdle(const float dt);
148 
149 	const int getComfortDistance(const Object *other) const;
150 
151 private:
152 	Alarm _reaction;
153 };
154 
getComfortDistance(const Object * other) const155 const int Zombie::getComfortDistance(const Object *other) const {
156 	GET_CONFIG_VALUE("objects.zombie.comfort-distance", int, cd, 120);
157 	return (other == NULL || other->classname == classname)?cd:-1; //fixme names if you want
158 }
159 
160 
onIdle(const float dt)161 void Zombie::onIdle(const float dt) {
162 	_state.fire = false;
163 
164 	GET_CONFIG_VALUE("objects.zombie.targeting-range(stable)", int, trs, 600);
165 	GET_CONFIG_VALUE("objects.zombie.targeting-range(alerted)", int, tra, 900);
166 	int tt = (hp < max_hp)?tra:trs;
167 
168 	ai::Herd::calculateV(_velocity, this, 0, tt);
169 }
170 
171 
calculate(const float dt)172 void Zombie::calculate(const float dt) {
173 	v2<float> vel;
174 	int tt;
175 
176 	if (is_driven())
177 		goto drive;
178 
179 	if (!_reaction.tick(dt))
180 		return;
181 
182 
183 	GET_CONFIG_VALUE("objects.zombie.targeting-range(stable)", int, trs, 600);
184 	GET_CONFIG_VALUE("objects.zombie.targeting-range(alerted)", int, tra, 900);
185 	tt = (hp < max_hp)?tra:trs;
186 
187 	if (get_nearest(ai::Targets->monster, tt, _velocity, vel, false)) {
188 		if (_velocity.quick_length() > size.quick_length())
189 			_state.fire = false;
190 
191 		_velocity.normalize();
192 		quantize_velocity();
193 	} else {
194 		_state.fire = false;
195 		if (!_variants.has("no-herd"))
196 			onIdle(dt);
197 	}
198 
199 drive:
200 	GET_CONFIG_VALUE("objects.zombie.rotation-time", float, rt, 0.1);
201 
202 	calculate_way_velocity();
203 	limit_rotation(dt, rt, true, false);
204 	update_state_from_velocity();
205 }
206 
on_spawn()207 void Zombie::on_spawn() {
208 	BaseZombie::on_spawn();
209 
210 	float rt;
211 
212 	Config->get("objects." + registered_name + ".reaction-time", rt, 0.5f);
213 	mrt::randomize(rt, rt/10);
214 	_reaction.set(rt);
215 }
216 
clone() const217 Object* Zombie::clone() const  {
218 	return new Zombie(*this);
219 }
220 
221 REGISTER_OBJECT("zombie", Zombie, ("monster"));
222