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