guided_missile.cc 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. /********************************************************************** <BR>
  2. This file is part of Crack dot Com's free source code release of
  3. Golgotha. <a href="http://www.crack.com/golgotha_release"> <BR> for
  4. information about compiling & licensing issues visit this URL</a>
  5. <PRE> If that doesn't help, contact Jonathan Clark at
  6. golgotha_source@usa.net (Subject should have "GOLG" in it)
  7. ***********************************************************************/
  8. #include "g1_object.hh"
  9. #include "tile.hh"
  10. #include "math/num_type.hh"
  11. #include "math/pi.hh"
  12. #include "math/trig.hh"
  13. #include "math/angle.hh"
  14. #include "g1_rand.hh"
  15. #include "objs/model_draw.hh"
  16. #include "objs/explosion1.hh"
  17. #include "objs/map_piece.hh"
  18. #include "saver.hh"
  19. #include "map.hh"
  20. #include "map_man.hh"
  21. #include "object_definer.hh"
  22. #include "resources.hh"
  23. #include "player.hh"
  24. #include "objs/particle_emitter.hh"
  25. #include "g1_render.hh"
  26. #include "flare.hh"
  27. #include "objs/guided_missile.hh"
  28. #include "sound/sfx_id.hh"
  29. #include "lisp/lisp.hh"
  30. #include "li_objref.hh"
  31. #include "lisp/li_vect.hh"
  32. #include "objs/smoke_trail.hh"
  33. #include "objs/vehic_sounds.hh"
  34. #include "camera.hh"
  35. #include "time/profile.hh"
  36. static i4_profile_class pf_missile("missile_think");
  37. g1_object_definer<g1_guided_missile_class>
  38. g1_guided_missile_def("guided_missile");
  39. static li_symbol_ref li_smoke_trail("smoke_trail");
  40. static li_symbol_ref li_explosion1("explosion1");
  41. static li_g1_ref_class_member track_object("track_object");
  42. static li_g1_ref_class_member smoke_trail("smoke_trail");
  43. static li_g1_ref_class_member who_fired_me("who_fired_me");
  44. static li_vect_class_member velocity("velocity");
  45. static li_float_class_member fuel("fuel");
  46. static li_symbol_ref light_type("lightbulb");
  47. g1_guided_missile_class::g1_guided_missile_class(g1_object_type id,
  48. g1_loader_class *fp)
  49. : g1_object_class(id,fp)
  50. {
  51. radar_type=G1_RADAR_WEAPON;
  52. char lod_name[256];
  53. draw_params.setup(name());
  54. set_flag(AERIAL |
  55. HIT_AERIAL |
  56. HIT_GROUND |
  57. SHADOWED,
  58. 1);
  59. damping_fraction = 1.0 - get_type()->defaults->accel/get_type()->defaults->speed;
  60. }
  61. void g1_guided_missile_class::request_remove()
  62. {
  63. li_class_context context(vars);
  64. delete_smoke();
  65. if (light.get())
  66. {
  67. light->unoccupy_location();
  68. light->request_remove();
  69. }
  70. g1_object_class::request_remove();
  71. }
  72. void g1_guided_missile_class::think()
  73. {
  74. pf_missile.start();
  75. i4_3d_vector accel;
  76. i4_3d_vector vel=velocity();
  77. if (fuel() > 0)
  78. {
  79. g1_object_class *track = track_object()->value();
  80. if (track)
  81. {
  82. i4_3d_vector pos(x,y,h);
  83. i4_3d_vector lead(track->x, track->y, track->h + 0.05);
  84. i4_3d_vector mp_diff(track->x - track->lx, track->y - track->ly, track->h - track->lh);
  85. i4_3d_vector tvel(vel);
  86. // leading code
  87. i4_3d_vector diff(lead);
  88. diff -= pos;
  89. i4_float t = diff.length()/get_type()->defaults->speed;
  90. mp_diff*=t;
  91. lead += mp_diff;
  92. // base acceleration vector
  93. accel = lead;
  94. accel -= pos;
  95. // accel.z *= 1.5; // correct height faster
  96. // determine look ahead for ground avoidance
  97. int look_ahead = i4_f_to_i(accel.length());
  98. if (look_ahead>3) look_ahead=3;
  99. accel.normalize();
  100. #if 0
  101. // attempt to cancel old velocity
  102. tvel.normalize();
  103. tvel *= 0.4;
  104. accel -= tvel;
  105. accel.normalize();
  106. #endif
  107. #if 1
  108. // attempt to cancel perp component of old velocity
  109. if (vel.dot(accel)>0)
  110. {
  111. i4_3d_vector perp(-accel.y, accel.x, 0);
  112. i4_float perp_vel = vel.dot(perp);
  113. perp_vel /= get_type()->defaults->accel;
  114. if (perp_vel<-1.0)
  115. accel = perp;
  116. else if (perp_vel>1.0)
  117. {
  118. accel = perp;
  119. accel.reverse();
  120. }
  121. else
  122. {
  123. accel *= sqrt(1.0 - perp_vel*perp_vel);
  124. perp *= -perp_vel;
  125. accel += perp;
  126. }
  127. }
  128. #endif
  129. if (accel.z>-0.5)
  130. {
  131. // ground tracking
  132. i4_3d_vector p(pos);
  133. i4_float height;
  134. for (int i=0; i<look_ahead; i++)
  135. {
  136. p += accel;
  137. height = g1_get_map()->terrain_height(p.x,p.y) + 0.02;
  138. if (height>p.z)
  139. {
  140. accel.set(p.x, p.y, height + (height - p.z));
  141. accel -= pos;
  142. accel.normalize();
  143. p.z = height;
  144. }
  145. }
  146. }
  147. theta = i4_atan2(vel.y,vel.x);
  148. pitch = i4_atan2(-vel.z, sqrt(vel.y*vel.y+vel.x*vel.x));
  149. }
  150. else
  151. {
  152. accel.set(cos(theta),
  153. sin(theta),
  154. 0);
  155. pitch *= 0.8;
  156. }
  157. accel *= get_type()->defaults->accel;
  158. vel += accel;
  159. vel *= damping_fraction;
  160. }
  161. else
  162. vel += i4_3d_vector(0,0,-g1_resources.gravity);
  163. velocity() = vel;
  164. if (move(vel.x,vel.y,vel.z))
  165. {
  166. if (light.get())
  167. light->move(x,y,h);
  168. request_think();
  169. }
  170. pf_missile.stop();
  171. }
  172. void g1_guided_missile_class::setup(const i4_3d_vector &pos,
  173. const i4_3d_vector &dir,
  174. g1_object_class *this_guy_fired_me,
  175. g1_object_class *track_me)
  176. {
  177. li_class_context context(vars);
  178. w32 i;
  179. x=lx=pos.x; y=ly=pos.y; h=lh=pos.z;
  180. i4_float start_speed=get_type()->defaults->speed*0.3;
  181. i4_3d_vector vel(dir);
  182. vel.normalize();
  183. vel *= start_speed;
  184. vars->set(velocity,new li_vect(vel));
  185. vars->set(track_object, new li_g1_ref(track_me));
  186. vars->set(who_fired_me, new li_g1_ref(this_guy_fired_me));
  187. player_num = this_guy_fired_me->player_num;
  188. g1_damage_map_struct *dmap=get_type()->get_damage_map();
  189. fuel() = dmap->range;
  190. ltheta=theta = i4_atan2(dir.y, dir.x);
  191. pitch=lpitch = i4_atan2(-dir.z, sqrt(dir.x * dir.x + dir.y * dir.y));
  192. lroll=roll = 0;
  193. request_think();
  194. g1_player_info_class *player=g1_player_man.get(player_num);
  195. if (occupy_location())
  196. {
  197. start_sounds();
  198. float r=g1_resources.visual_radius();
  199. if (g1_current_view_state()->dist_sqrd(i4_3d_vector(x,y,h))<r*r)
  200. {
  201. add_smoke();
  202. light = (g1_light_object_class *)g1_create_object(g1_get_object_type(light_type.get()));
  203. light->setup(x,y,h, 1, 0, 0, 1);
  204. light->occupy_location();
  205. }
  206. }
  207. }
  208. void g1_guided_missile_class::start_sounds()
  209. {
  210. }
  211. void g1_guided_missile_class::add_smoke()
  212. {
  213. int smoke_type=g1_get_object_type(li_smoke_trail.get());
  214. g1_smoke_trail_class *st=(g1_smoke_trail_class *)g1_create_object(smoke_type);
  215. vars->set(smoke_trail, new li_g1_ref(st));
  216. if (st)
  217. {
  218. st->setup(x, y, h, 0.02, 0.02, 0xff0000, 0xffffff); // red to white
  219. st->occupy_location();
  220. }
  221. }
  222. void g1_guided_missile_class::update_smoke()
  223. {
  224. li_class_context c(vars);
  225. if (!smoke_trail())
  226. return;
  227. g1_smoke_trail_class *st=(g1_smoke_trail_class *) smoke_trail()->value();
  228. if (st)
  229. st->update_head(x,y,h);
  230. }
  231. void g1_guided_missile_class::delete_smoke()
  232. {
  233. li_class_context c(vars);
  234. if (!smoke_trail())
  235. return;
  236. g1_smoke_trail_class *st=(g1_smoke_trail_class *) smoke_trail()->value();
  237. if (st)
  238. {
  239. st->unoccupy_location();
  240. st->request_remove();
  241. vars->set(smoke_trail, li_g1_null_ref());
  242. }
  243. }
  244. void g1_guided_missile_class::add_explode()
  245. {
  246. g1_explosion1_class *explosion;
  247. int explosion_type=g1_get_object_type(li_explosion1.get());
  248. explosion = (g1_explosion1_class *)g1_create_object(explosion_type);
  249. if (explosion)
  250. {
  251. i4_float rx,ry,rh;
  252. rx = g1_float_rand(3) * 0.2;
  253. ry = g1_float_rand(4) * 0.2;
  254. rh = g1_float_rand(9) * 0.2;
  255. explosion->setup(x+rx,y+ry,h+rh, g1_explosion1_class::HIT_OBJECT);
  256. }
  257. }
  258. i4_bool g1_guided_missile_class::move(i4_float x_amount,
  259. i4_float y_amount,
  260. i4_float z_amount)
  261. {
  262. sw32 res;
  263. g1_object_class *hit = NULL;
  264. i4_3d_vector pos(x,y,h),ray(x_amount, y_amount, z_amount);
  265. res = g1_get_map()->check_non_player_collision(player_num,pos, ray, hit);
  266. if (res)
  267. {
  268. g1_apply_damage(this, who_fired_me()->value(), hit, ray);
  269. if (res != -1)
  270. add_explode();
  271. unoccupy_location();
  272. request_remove();
  273. return i4_F;
  274. }
  275. fuel() -= ray.length();
  276. pos += ray;
  277. unoccupy_location();
  278. x = pos.x;
  279. y = pos.y;
  280. h = pos.z;
  281. if (!occupy_location())
  282. return i4_F;
  283. else
  284. {
  285. update_smoke();
  286. g1_add_to_sound_average(G1_RUMBLE_MISSILE, pos, ray);
  287. }
  288. return i4_T;
  289. }