source: golgotha/src/golg/objs/stank.cc @ 80

Last change on this file since 80 was 80, checked in by Sam Hocevar, 12 years ago
  • Adding the Golgotha source code. Not sure what's going to be interesting in there, but since it's all public domain, there's certainly stuff to pick up.
File size: 43.9 KB
Line 
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
9#include "sound_man.hh"
10#include "input.hh"
11#include "math/pi.hh"
12#include "math/angle.hh"
13#include "math/random.hh"
14#include "resources.hh"
15#include "saver.hh"
16#include "map.hh"
17#include "map_cell.hh"
18#include "map_man.hh"
19#include "sound/sfx_id.hh"
20#include "g1_speed.hh"
21#include "math/trig.hh"
22#include "g1_render.hh"
23#include "r1_api.hh"
24#include "tile.hh"
25#include "object_definer.hh"
26#include "player.hh"
27#include "human.hh"
28#include "controller.hh"
29#include "g1_render.hh"
30#include "statistics.hh"
31#include "human.hh"
32
33#include "objs/model_id.hh"
34#include "objs/stank.hh"
35
36#include "objs/explosion1.hh"
37#include "objs/shrapnel.hh"
38#include "objs/fire.hh"
39#include "lisp/lisp.hh"
40#include "lisp/li_load.hh"
41#include "tick_count.hh"
42
43#include "time/profile.hh"
44#include "map_cell.hh"
45#include "r1_clip.hh"
46#include "lisp/li_error.hh"
47#include "objs/vehic_sounds.hh"
48#include "map_view.hh"
49
50#include "image_man.hh"
51
52#include "g1_tint.hh"
53#include "objs/carcass.hh"
54
55static i4_float droll = 0.0, ddroll = 0.0, hurt=0.0;
56
57static g1_model_ref model_ref("supertankbase"),
58  turret_ref("supertanktop"),
59  stank_carcass("chunk_supertankbase");
60
61static i4_3d_vector turret_attach, muzzle_exit;
62
63static g1_team_icon_ref radar_im0("bitmaps/radar/supertank_0.tga");
64static g1_team_icon_ref radar_im2("bitmaps/radar/supertank_2.tga");
65static g1_team_icon_ref radar_im4("bitmaps/radar/supertank_4.tga");
66static g1_team_icon_ref radar_im6("bitmaps/radar/supertank_6.tga");
67static g1_team_icon_ref radar_im8("bitmaps/radar/supertank_8.tga");
68static g1_team_icon_ref radar_im10("bitmaps/radar/supertank_10.tga");
69static g1_team_icon_ref radar_im12("bitmaps/radar/supertank_12.tga");
70static g1_team_icon_ref radar_im14("bitmaps/radar/supertank_14.tga");
71
72S1_SFX(supertank_lost, "narrative/supertank_lost_22khz.wav", S1_STREAMED, 200);
73S1_SFX(return_to_repair, "computer_voice/return_to_base_for_repairs_22khz.wav", S1_STREAMED, 200);
74
75i4_profile_class pf_stank_think("stank::think");
76
77g1_object_type g1_supertank_type;
78
79static g1_object_type main_base_type;
80
81void g1_supertank_init();
82
83g1_object_definer<g1_player_piece_class>
84g1_supertank_def("stank",
85                 g1_object_definition_class::MOVABLE |
86                 g1_object_definition_class::TO_MAP_PIECE |
87                 g1_object_definition_class::TO_PLAYER_PIECE,
88                 g1_supertank_init);
89
90void g1_supertank_init()
91{
92  g1_supertank_type  = g1_supertank_def.type;
93  main_base_type     = g1_get_object_type("mainbasepad");
94
95  turret_attach = g1_resources.player_top_attach;
96  model_ref()->get_mount_point("Turret", turret_attach);
97  muzzle_exit.set(0.4, 0, 0.11);
98  turret_ref()->get_mount_point("Muzzle", muzzle_exit);
99}
100
101
102void g1_player_piece_class::save_base_info(g1_saver_class *fp)
103{
104  fp->start_version(BASE_DATA_VERSION); 
105  fp->write_format("ffff44",
106                   &base_angle, &lbase_angle, &strafe_speed, &cur_top_attach,
107                   &move_tick,
108                   &upgrade_level_when_built);
109  fp->end_version();
110}
111
112void g1_player_piece_class::load_base_info(g1_loader_class *fp)
113{
114  if (fp && fp->check_version(BASE_DATA_VERSION))
115  {
116    fp->read_format("ffff44",
117                    &base_angle, &lbase_angle, &strafe_speed, &cur_top_attach,
118                    &move_tick,
119                    &upgrade_level_when_built);
120    fp->end_version(I4_LF);
121
122  }
123  else
124  {
125    base_angle=lbase_angle=0;
126    strafe_speed=0;
127    cur_top_attach=g1_resources.player_top_attach.z;
128    move_tick=0;
129  }
130}
131
132
133void g1_player_piece_class::save_mouse_look_info(g1_saver_class *fp)
134{
135  fp->start_version(MOUSE_LOOK_DATA_VERSION);
136
137  fp->write_float(mouse_look_increment_x);
138  fp->write_float(mouse_look_increment_y);
139  fp->write_float(mouse_look_x);
140  fp->write_float(mouse_look_y);
141
142  fp->write_float(turret->rotation.z);
143
144  fp->end_version();
145}
146
147void g1_player_piece_class::load_mouse_look_info(g1_loader_class *fp)
148{
149  if (fp && fp->check_version(MOUSE_LOOK_DATA_VERSION))
150  {
151    mouse_look_increment_x=fp->read_float();
152    mouse_look_increment_y=fp->read_float();
153    mouse_look_x=fp->read_float();
154    mouse_look_y=fp->read_float();
155
156    turret->rotation.z=fp->read_float();
157    fp->end_version(I4_LF);
158  }
159  else
160  {
161    mouse_look_increment_x=mouse_look_increment_y=0;
162    mouse_look_x=mouse_look_y=0;
163    turret->rotation.z=0;
164  }
165}
166
167
168void g1_player_piece_class::save_ammo_info(g1_saver_class *fp)
169{
170  fp->start_version(AMMO_DATA_VERSION);
171  for (int i=0; i<MAX_WEAPONS; i++)
172    ammo[i].save(fp);
173  fp->end_version();
174}
175
176void g1_player_piece_class::load_ammo_info(g1_loader_class *fp)
177{
178  if (fp && fp->check_version(AMMO_DATA_VERSION))
179  {
180    for (int i=0; i<MAX_WEAPONS; i++)
181      ammo[i].load(fp);
182    fp->end_version(I4_LF);
183  }
184}
185
186void g1_player_piece_class::save(g1_saver_class *fp)
187{
188  g1_map_piece_class::save(fp);
189
190  int han=fp->mark_size();
191
192  fp->start_version(DATA_VERSION);
193  fp->write_32(stank_flags);
194  fp->write_float(vspeed);
195  fp->end_version();
196
197  save_base_info(fp);
198  save_mouse_look_info(fp);
199  save_ammo_info(fp);
200
201  fp->end_mark_size(han);
202}
203
204
205void g1_stank_ammo_info_struct::setup(li_symbol *sym)
206{
207  ammo_type=g1_find_stank_ammo_type(sym);
208  if (ammo_type)
209    amount=ammo_type->max_amount;
210  else
211    li_error(0,"s_tank : no weapon called %O", sym);
212 
213  delay_remaining=0;   
214  need_refresh=i4_T;   
215  last_fired_object=0; 
216}
217
218void g1_player_piece_class::find_weapons()
219{
220  int level=g1_player_man.get_local()->supertank_upgrade_level;
221  if (level<0) level=0;
222  upgrade_level_when_built=level;
223
224 
225  li_object *o;
226  for (o=li_get_value("upgrade_levels"); o && li_cdr(o,0) && level; level--)
227    o=li_cdr(o,0);
228 
229  if (o)
230  {
231    o=li_cdr(li_car(o,0),0);
232
233    for (int i=0; i<MAX_WEAPONS; i++)
234    {
235      ammo[i].setup(li_symbol::get(li_car(o,0),0));
236      o=li_cdr(o,0);
237    }   
238  }     
239}
240
241
242
243void g1_stank_ammo_info_struct::save(g1_saver_class *fp)
244{
245  if (ammo_type)
246    li_save_object(fp, ammo_type->weapon_type,0);
247  else
248    li_save_object(fp, li_nil,0);
249 
250                   
251  fp->write_16(amount);
252  fp->write_16(delay_remaining);
253  fp->write_8(need_refresh);
254 
255  fp->write_reference(last_fired_object);
256}
257
258void g1_stank_ammo_info_struct::load(g1_loader_class *fp)
259{
260  li_symbol *wtype=li_symbol::get(li_load_object(fp, fp->li_remap, 0),0);
261 
262  ammo_type=g1_find_stank_ammo_type(wtype);
263  amount=fp->read_16();
264  delay_remaining=fp->read_16();
265  need_refresh=fp->read_8();
266  fp->read_reference(last_fired_object);     
267}
268 
269
270g1_player_piece_class::g1_player_piece_class(g1_object_type id,
271                                             g1_loader_class *fp)
272  : g1_map_piece_class(id, fp), path(0)
273{   
274  w16 ver,data_size;
275  i4_bool defaults=i4_T;
276
277  draw_params.setup(model_ref.id());
278
279  allocate_mini_objects(1,"Super Tank Mini Objects");
280  turret = &mini_objects[0];
281  turret->defmodeltype = turret_ref.id();
282  turret->position(turret_attach);
283
284  if (fp)
285  {
286    int total_size=fp->read_32();
287
288    if (fp->check_version(DATA_VERSION))
289    {
290      stank_flags = fp->read_32();
291      vspeed = fp->read_float();     
292      fp->end_version(I4_LF);
293
294      find_weapons();
295     
296      load_base_info(fp);
297      load_mouse_look_info(fp);
298      load_ammo_info(fp);
299      defaults=i4_F;
300    }
301    else
302      fp->seek(fp->tell() + total_size);   
303  }
304 
305  if (defaults)
306  {
307    find_weapons();
308    stank_flags=0;
309    vspeed=0;
310
311    load_base_info(0);
312    load_mouse_look_info(0);
313    load_ammo_info(0);
314
315    health=ammo[3].amount;
316  }
317   
318  turret_kick = lturret_kick = 0;
319
320  // clear user data
321  accel_ratio = strafe_accel_ratio = dtheta = 0;
322  memset(fire,0,sizeof(fire));
323
324  init_rumble_sound(G1_RUMBLE_STANK);
325
326  radar_image=&radar_im0;
327  radar_type=G1_RADAR_STANK;
328  //initialize these guys. somewhat important
329  set_flag(GROUND        |
330           BLOCKING      |
331           SELECTABLE    |
332           TARGETABLE    |
333           GROUND        |
334           HIT_AERIAL    |
335           HIT_GROUND    |
336           DANGEROUS, 1);
337
338}
339
340i4_bool g1_player_piece_class::suggest_move(i4_float &dist,
341                                            i4_float &dtheta,
342                                            i4_float &dx, i4_float &dy,
343                                            i4_float braking_friction)
344{
345  i4_float angle,t ,diffangle;
346 
347  i4_bool go_reverse    = i4_F;
348  i4_bool can_get_there = i4_T;
349
350  dx = (dest_x - x);
351  dy = (dest_y - y);
352
353  //aim the vehicle   
354  angle = i4_atan2(dy,dx);
355  i4_normalize_angle(angle);   
356 
357  diffangle = angle - theta;
358  if (diffangle<-i4_pi()) diffangle += 2*i4_pi();
359  else if (diffangle>i4_pi()) diffangle -= 2*i4_pi();
360
361  go_reverse = (diffangle>i4_pi()/2) || (diffangle<-i4_pi()/2);
362
363  //dont worry about turn radii unless he's actually ready for forward movement
364  if (go_reverse)
365    dtheta = diffangle;
366  else
367  {
368    can_get_there = check_turn_radius();
369    dtheta = diffangle;
370  }
371
372  //distance to move squared
373  t = dx*dx + dy*dy;
374 
375  //how far will the vehicle go if he slows down from his maximum speed?
376  if (t>speed*speed+0.0025 || braking_friction==0.0)
377  {
378    if (dtheta<-defaults->turn_speed) dtheta = -defaults->turn_speed;
379    else if (dtheta>defaults->turn_speed) dtheta = defaults->turn_speed;
380    theta += dtheta;
381    i4_normalize_angle(theta);
382
383    i4_float stop_dist;
384    if (braking_friction>0.0)
385      stop_dist = fabs(speed)/braking_friction; // geometric series of braking motion
386
387    if (!go_reverse && braking_friction>0.0 && t<=(stop_dist*stop_dist))
388    {           
389      //just in case our calculations were off, dont let him slow to less than 0.01
390      if (speed <= 0.01)
391        speed = 0.01;
392      else
393        speed *= (1.0-braking_friction);
394    }
395    else
396    {
397      // calculate speed changes
398
399      // uA = coefficient of sliding friction (removed for now)
400      // th = rising pitch
401      // uB = damping friction (damping_fraction = 1/uB)
402      // C = exp( -uB * t) (damping_e)
403
404      // K = (accel - (uA*cos(th) + sin(th))*g
405      // finalvel = K / uB
406
407      // vel = finalvel - (speed - finalvel)*exp(-uB * step_time)
408
409      i4_float target_speed, accel;
410
411      if (!can_get_there && !go_reverse)
412        speed *= (1.0-braking_friction);
413      else
414      {
415        if (go_reverse)
416          accel = -defaults->accel*0.30;
417        else
418          accel = defaults->accel;
419
420        accel += sin(pitch)*g1_resources.gravity;
421        speed += accel;
422        speed -= speed*damping_fraction;
423      }
424    }
425    dist = speed*cos(pitch);
426    dx = cos(theta) * dist;
427    dy = sin(theta) * dist;
428    dist = t;
429  }
430  else
431  {
432    dtheta = 0;
433    dist = 0;
434    speed = 0;
435    dx = 0;
436    dy = 0;
437  }   
438
439  // Oli's debug statement
440//   if (g1_object_class::selected())
441//     g1_debugxy(0,1,"(%5.2f,%5.2f)-(%5.2f,%6f)",
442//                x, y,
443//                pitch*180/i4_pi(), speed);
444
445  return (dist==0);
446}
447
448i4_bool g1_player_piece_class::move(i4_float x_amount, i4_float y_amount)
449{
450  int x1,y1, x2,y2, ix,iy;
451  i4_bool ret = i4_F;
452
453  if (x_amount==0.0 && y_amount==0.0)
454    return i4_T;
455
456  i4_3d_vector start, ray(x_amount,y_amount,0), normal, offset, oray;
457  i4_float dist;
458
459  /*
460  offset = ray;
461  dist = offset.length();
462  offset *= 0.1/dist;
463
464  ray += offset;
465  */
466
467  const int nc=8;
468  const i4_float rad = 0.25;
469
470  for (int i=0; i<nc; i++)
471  {
472    start.set(x+rad*cos(2.0*i4_pi()*(0.5+i)/nc),y+rad*sin(2.0*i4_pi()*(0.5+i)/nc),h+0.07);
473
474    if (ray.x<0) { x2 = i4_f_to_i(start.x); x1 = i4_f_to_i(start.x+ray.x); }
475    else         { x1 = i4_f_to_i(start.x); x2 = i4_f_to_i(start.x+ray.x); }
476    if (ray.y<0) { y2 = i4_f_to_i(start.y); y1 = i4_f_to_i(start.y+ray.y); }
477    else         { y1 = i4_f_to_i(start.y); y2 = i4_f_to_i(start.y+ray.y); }
478   
479    for (iy=y1; iy<=y2; iy++)
480      for (ix=x1; ix<=x2; ix++)
481      {
482        g1_object_chain_class *objlist = g1_get_map()->cell(ix,iy)->get_obj_list();
483       
484        while (objlist)
485        {
486          g1_object_class *obj=objlist->object;
487          i4_float dist, dx,dy;
488       
489          if (obj->get_flag(BLOCKING) && obj!=this)
490          {
491            oray = ray;
492            if (g1_model_collide_polygonal(obj, obj->draw_params, start, ray, normal))
493            {
494              if (normal.z>0.8)
495              {
496                // incline more than 45 degrees.  let it go
497                ray = oray;
498              }
499              else
500              {
501                // slide perp. to the normal
502                // NOTE: we really should resubmit the new movement vector to objects
503                //       in the list we already tried to collide against for more robust
504                //       sliding.  just hope we catch most of the errors on the next frame
505                i4_3d_vector diff(ray);
506                diff -= oray;
507                normal.z = 0;
508                normal.normalize();
509                normal *= diff.dot(normal) + 0.05;
510                ray = oray;
511                ray += normal;
512                ret = i4_F;
513              }
514            }
515          }
516       
517          objlist = objlist->next_solid();
518        }
519      }
520  }
521
522  unoccupy_location();
523  /*
524  ray -= offset;
525  */
526  x += ray.x;
527  y += ray.y;
528  if (x<1) x=1; else if (x>g1_get_map()->width()-2) x=g1_get_map()->width()-2;
529  if (y<1) y=1; else if (y>g1_get_map()->height()-2) y=g1_get_map()->height()-2;
530  occupy_location();
531
532  return ret;
533}
534
535void g1_player_piece_class::lead_target(i4_3d_point_class &lead, int slot_number)
536{
537  g1_stank_ammo_info_struct *a=ammo+slot_number;
538
539  int wtype=g1_get_object_type(a->ammo_type->weapon_type);
540  if (wtype)
541  {
542    i4_float shot_speed = g1_object_type_array[wtype]->get_damage_map()->speed;
543    g1_map_piece_class::lead_target(lead,shot_speed);
544  }
545}
546
547void g1_player_piece_class::check_if_turret_in_ground()
548{
549  if (player_num != g1_player_man.local_player)
550    return;
551
552  i4_3d_vector pos, dir;
553  float h;
554 
555  do
556  {
557    get_bullet_exit(pos, dir);
558    h=pos.z-g1_get_map()->map_height(pos.x, pos.y, pos.z);
559
560    if (h<0)
561      turret->rotation.y-=0.01;
562  } while (h<0);
563}
564 
565 
566void g1_player_piece_class::check_for_refuel()
567{
568  g1_object_chain_class *objlist = g1_get_map()->cell(i4_f_to_i(x), i4_f_to_i(y))->get_solid_list();
569  i4_bool on_base=i4_F;
570
571  while (objlist && !on_base)
572  {
573    g1_object_class *obj=objlist->object;
574    i4_float dist, dx,dy;
575
576    if (obj->id == main_base_type && obj->player_num==player_num)
577      on_base = i4_T;
578
579    objlist=objlist->next;
580  }
581
582  if (on_base)
583  {
584    if (get_stank_flag(g1_player_piece_class::ST_REFUELING)==0)
585    {     
586      for (int i=0; i<MAX_WEAPONS; i++)
587      {
588        int mx=ammo[i].ammo_type->max_amount;
589        if (mx==0) mx=1;
590        ammo[i].refuel_delay_remaining=ammo[i].ammo_type->refuel_delay/mx;
591      }
592     
593      set_stank_flag(g1_player_piece_class::ST_REFUELING,1);
594    }
595
596    health++;
597    if (health>ammo[3].ammo_type->max_amount)
598    {
599      health=ammo[3].ammo_type->max_amount;
600
601//       if (refuel_sound)   sfxfix
602//         if (refuel_sound->is_playing()) refuel_sound->stop();
603    }
604    else
605    {
606//       g1_sound_man.update_dynamic_3d_sound(refuel_sound,   sfxfix
607//                                            i4_3d_vector(x,y,h),
608//                                            i4_3d_vector(0,0,0),1.0);
609    }
610
611    for (int i=0; i<MAX_WEAPONS; i++)
612    {
613      if (ammo[i].refuel_delay_remaining)
614        ammo[i].refuel_delay_remaining--;
615      else
616      {
617        if (ammo[i].amount<ammo[i].ammo_type->max_amount)
618        {
619          ammo[i].amount++;
620          // jc:fixme  add refuel sfx here
621        }
622
623        int mx=ammo[i].ammo_type->max_amount;
624        if (mx==0) mx=1;
625        ammo[i].refuel_delay_remaining=ammo[i].ammo_type->refuel_delay/mx;
626      }
627    }
628
629  }
630  else
631  {   
632    if (get_stank_flag(ST_REFUELING))
633      //stop refueling
634      set_stank_flag(ST_REFUELING,0);
635   
636//     if (refuel_sound && refuel_sound->is_playing())   sfxfix
637//       refuel_sound->stop();
638  }
639
640}
641
642void g1_player_piece_class::set_path(g1_path_handle new_path)
643
644  if (path)
645    g1_path_manager.free_path(path);
646  path=new_path;
647}
648
649i4_bool g1_player_piece_class::deploy_to(float destx, float desty)
650{
651  i4_float points[200];
652  w16 t_points;
653  g1_path_handle ph=0;
654
655  if (g1_get_map()->find_path(x,y, destx,desty, points,t_points) && t_points>1)
656    ph=g1_path_manager.alloc_path(t_points-1, points);
657     
658  set_path(ph);
659
660  return (ph!=0);
661}
662
663w32 g1_player_piece_class::follow_path()
664
665  if (!path) return NO_PATH;
666
667  g1_path_manager.get_position(path, dest_x, dest_y);
668
669  // first check to see if we're already there 
670  i4_float dx = (x-dest_x), dy = (y-dest_y);
671  i4_float dist = dx*dx+dy*dy;
672 
673  //if we're there, advance to the next path position
674  if (dist<=0.01)
675  {
676    path = g1_path_manager.advance_path(path);
677    if (!path) return NO_PATH;
678   
679    g1_path_manager.get_position(path, dest_x, dest_y);
680  }
681  return (g1_path_manager.is_last_path_point(path))? FINAL_POINT : GAME_PATH;
682}
683
684void g1_player_piece_class::check_for_powerups()
685{
686  i4_3d_vector v=i4_3d_vector(x,y,h);
687  float r=2.0;
688
689  int fog_rect_x1=10000, fog_rect_y1=10000,
690      fog_rect_x2=-1, fog_rect_y2=-1, ix,iy;
691 
692  g1_map_class *map=g1_get_map();
693
694  int x_left   = i4_f_to_i(v.x-r); if (x_left<0)                x_left=0;
695  int x_right  = i4_f_to_i(v.x+r); if (x_right>=map->width())   x_right=map->width()-1;
696  int y_top    = i4_f_to_i(v.y-r); if (y_top<0)                 y_top=0;
697  int y_bottom = i4_f_to_i(v.y+r); if (y_bottom>=map->height()) y_bottom=map->height()-1; 
698
699  for (iy=y_top;  iy<=y_bottom; iy++)
700  {
701    g1_map_cell_class *c=map->cell(x_left,iy);
702    for (ix=x_left; ix<=x_right;  ix++, c++)
703    {
704      for (g1_object_chain_class *o=c->get_obj_list(); o; o=o->next)
705      {
706        g1_object_class *obj=o->object;
707        if (!obj->get_flag(g1_object_class::SCRATCH_BIT))
708        {
709          obj->set_flag(g1_object_class::SCRATCH_BIT, 1);
710          obj->note_stank_near(this);
711        }
712      }
713    }
714  }
715
716
717  for (iy=y_top;  iy<=y_bottom; iy++)
718  {
719    g1_map_cell_class *c=map->cell(x_left,iy);
720    for (ix=x_left; ix<=x_right;  ix++, c++)
721      for (g1_object_chain_class *o=c->get_obj_list(); o; o=o->next)
722        o->object->set_flag(g1_object_class::SCRATCH_BIT, 0);
723  }
724}
725
726
727void g1_player_piece_class::think()
728{
729  pf_stank_think.start();
730
731  // Save old values of position & orientation
732  lbase_angle  = base_angle;   
733  lturret_kick  = turret_kick;
734
735  if (!check_life())
736  {
737    //    g1_sound_man.play(STATIC_3D_SOUND,g1_sfx_explosion_ground_vehicle,i4_3d_vector(x,y,h));  sfxfix
738
739//     if (refuel_sound)  sfxfix
740//     {
741//       g1_sound_man.free_dynamic_3d_sound(refuel_sound);
742//       refuel_sound=0;
743//     }
744    supertank_lost.play();
745    pf_stank_think.stop();
746    return;
747  }
748
749  check_for_refuel();
750  check_for_powerups();
751 
752  i4_bool process_input = i4_T;
753
754  w32 pathinfo = follow_path();
755 
756  if (player_num==g1_human->team() &&
757      (!g1_current_controller.get() ||
758       (g1_current_controller->view.get_view_mode()!=G1_ACTION_MODE) &&
759       g1_current_controller->view.get_view_mode()!=G1_FOLLOW_MODE &&
760       g1_current_controller->view.get_view_mode()!=G1_WATCH_MODE
761       ))
762    process_input = i4_F;
763
764  // Process real user movement
765 
766  // User Input
767  if (process_input)
768  {
769    // Process mouse movement for looking around
770    i4_normalize_angle(mouse_look_increment_x);
771
772    mouse_look_x -= mouse_look_increment_x;
773    i4_normalize_angle(mouse_look_x);   
774    base_angle   -= mouse_look_increment_x;
775    i4_normalize_angle(base_angle);
776
777    if (mouse_look_increment_y!=0)
778      mouse_look_y = turret->rotation.y;
779     
780    mouse_look_y += mouse_look_increment_y;
781    i4_normalize_angle(mouse_look_y);
782
783    if (mouse_look_y < 3*i4_pi()/2 && mouse_look_y > i4_pi()/2)
784    {
785      if (mouse_look_increment_y>0)
786        mouse_look_y = i4_pi()/2;
787      else
788        mouse_look_y = 3*i4_pi()/2;
789    }
790  }
791
792  mouse_look_increment_x = 0;
793  mouse_look_increment_y = 0;
794
795  // Movement
796  if (pathinfo)
797  {
798    // Move along the set path
799    i4_float dist, dtheta, dx, dy, brakes=0.0;
800
801    if (pathinfo==FINAL_POINT)
802      brakes=0.1;
803   
804    suggest_move(dist, dtheta, dx, dy, brakes);
805    move(dx,dy);
806
807    if (speed*speed>=dist)
808    {
809      i4_3d_vector a,b,c;
810
811      path = g1_path_manager.advance_path(path);
812
813      a.set(x,y,0);
814      b.z=c.z=0;
815      if (g1_path_manager.get_nth_position(path,0,b.x,b.y) &&
816          g1_path_manager.get_nth_position(path,1,c.x,c.y))
817      {
818        c -= b;
819        b -= a;
820        b.normalize();
821        c.normalize();
822        brakes = (b.dot(c)<0.8) ? 0.1 : 0.0;
823      }
824    }
825
826    if (!process_input)
827      base_angle = theta;
828   
829    g1_add_to_sound_average(G1_RUMBLE_STANK, i4_3d_vector(x,y,h), i4_3d_vector(x-lx, y-ly, h-lh));
830  }
831  else
832  {
833    i4_angle desired_base = base_angle;
834 
835    if (process_input)
836    {
837      // process turning
838      base_angle += dtheta;
839      i4_normalize_angle(base_angle);
840    }
841
842    if (process_input && !get_stank_flag(ST_INFLIGHT))
843    {
844      if (accel_ratio)
845      {
846        // process acceleration
847        if (!get_stank_flag(ST_SLIDING))
848          speed += defaults->accel*accel_ratio;
849        speed += sin(pitch)*g1_resources.gravity;
850        speed -= speed*damping_fraction;
851      }
852
853      if (strafe_accel_ratio)
854      {
855        // do strafing
856        strafe_speed += g1_resources.player_accel * strafe_accel_ratio;
857        strafe_speed -= strafe_speed*damping_fraction;
858      }
859
860      desired_base = base_angle;
861      if (strafe_accel_ratio<0)
862      {
863        if (accel_ratio<0)        desired_base = 3*i4_pi()/4+base_angle;
864        else if (accel_ratio>0)   desired_base=i4_pi()/4+base_angle;
865        else                      desired_base=i4_pi()/2+base_angle;
866   
867        i4_normalize_angle(desired_base);
868      }
869      else if (strafe_accel_ratio>0)
870      {
871        if (accel_ratio<0)        desired_base=5*i4_pi()/4+base_angle;
872        else if (accel_ratio>0)   desired_base=7*i4_pi()/4+base_angle;
873        else                      desired_base=3*i4_pi()/2+base_angle;   
874       
875        i4_normalize_angle(desired_base);
876      }
877    }
878
879    if (!get_stank_flag(ST_INFLIGHT))
880    {
881      // Process braking
882      if (accel_ratio==0)
883      {
884        speed = speed*g1_resources.player_stop_friction;
885        if (speed<0.01 && speed>-0.01)
886          speed=0;       
887      }
888      if (strafe_accel_ratio==0)
889      {
890        strafe_speed = strafe_speed*g1_resources.player_stop_friction;
891        if (strafe_speed<0.01 && strafe_speed>-0.01)
892          strafe_speed=0;
893      }
894    }
895
896    dtheta=0;
897    accel_ratio=0;
898    strafe_accel_ratio=0;
899
900    // Do desired rotation
901    i4_rotate_to(theta,desired_base,g1_resources.player_turn_speed+0.1);
902
903    // Move me
904    i4_float
905      mv_speed = cos(groundpitch)*speed,
906      mv_strafe_speed = cos(groundroll)*strafe_speed;       
907
908    i4_float
909      dx = cos(base_angle)*mv_speed + cos(base_angle-i4_pi()/2)*mv_strafe_speed,
910      dy = sin(base_angle)*mv_speed + sin(base_angle-i4_pi()/2)*mv_strafe_speed;
911
912#if 0
913    if (groundpitch<-0.5 || groundpitch>0.5 || groundroll<-0.5 || groundroll>0.5)
914    {
915      dx += sin(groundpitch)*g1_resources.gravity;
916      dy -= sin(groundroll)*g1_resources.gravity;
917      set_stank_flag(ST_SLIDING,1);
918    }
919    else
920      set_stank_flag(ST_SLIDING,0);
921#endif
922
923    move(dx,dy);
924   
925    if (turret->h != cur_top_attach)
926      turret->h = cur_top_attach;
927
928  }
929
930  switch ((int)(base_angle*8/(2*i4_pi())))
931  {
932    case 0 : radar_image=&radar_im0; break;
933    case 1 : radar_image=&radar_im2; break;
934    case 2 : radar_image=&radar_im4; break;
935    case 3 : radar_image=&radar_im6; break;
936    case 4 : radar_image=&radar_im8; break;
937    case 5 : radar_image=&radar_im10; break;
938    case 6 : radar_image=&radar_im12; break;
939    case 7 : radar_image=&radar_im14; break;
940  }
941         
942
943
944  // Calculate height physics & pitch & roll
945 
946  i4_float newground = g1_get_map()->map_height(x,y,lh);
947
948  if (h-0.00001+vspeed > newground)
949  {   
950    //he's off the ground
951    //dont set these to 0, just leave them the way they were
952    groundpitch = lgroundpitch;
953    groundroll  = lgroundroll;
954
955    h += vspeed;
956    vspeed -= g1_resources.gravity;
957
958    set_stank_flag(ST_INFLIGHT);
959  }
960  else
961  {
962    // steady on the ground
963
964    vspeed = newground - h - g1_resources.gravity;
965
966    h = newground;
967
968    i4_3d_vector z2, z3;
969
970    z2.set(x+0.1, y, 0);
971    z3.set(x-0.1, y, 0);
972    z2.z = g1_get_map()->map_height(z2.x,z2.y,lh);
973    z3.z = g1_get_map()->map_height(z3.x,z3.y,lh);
974    groundpitch = -i4_atan2(z2.z - z3.z,0.5);
975
976    z2.set(x, y+0.1, 0);
977    z3.set(x, y-0.1, 0);
978    z2.z = g1_get_map()->map_height(z2.x,z2.y,lh);
979    z3.z = g1_get_map()->map_height(z3.x,z3.y,lh);
980    groundroll =  i4_atan2(z2.z - z3.z,0.5);
981
982    pitch = 0;
983
984    if (player_num != g1_player_man.local_player)
985      roll  = 0;
986    else
987      roll = 0.8*roll;
988
989    set_stank_flag(ST_INFLIGHT,0);
990  }
991
992  if (hurt>0.0)
993  {
994    g1_hurt_tint = i4_f_to_i((G1_NUM_HURT_TINTS-1)*hurt)+1;
995    hurt-=0.05;
996    if (hurt<0.0)
997      hurt = 0.0;
998  }
999  else
1000    g1_hurt_tint = 0;
1001
1002  if (vspeed>0.3)  // don't jump too high
1003    vspeed=0.3;
1004 
1005  // Orient turrent
1006  if (process_input)
1007  {
1008    turret->rotation.x = 0;
1009    turret->rotation.y = mouse_look_y;
1010    turret->rotation.z = base_angle;
1011   
1012    check_if_turret_in_ground();
1013  }
1014  else
1015  {
1016    turret->rotation.x = 0;
1017    turret->rotation.y = turret->lrotation.y = 0;
1018    turret->rotation.x = turret->lrotation.x = 0;
1019  }
1020 
1021  // Do firing stuff
1022  if (turret_kick < 0.f)
1023    turret_kick += 0.02;
1024 
1025  // Update delays
1026  for (int del=0; del<MAX_WEAPONS; del++)
1027    if (ammo[del].delay_remaining)
1028      ammo[del].delay_remaining--;
1029
1030  look_for_targets();
1031
1032
1033  if (player_num!=g1_player_man.local_player)
1034    find_target();
1035  else
1036    g1_unfog_radius(i4_3d_vector(x,y,h), 10.0);
1037
1038  if (process_input)
1039  {
1040    for (int i=0; i<MAX_WEAPONS-1; i++)
1041      if (fire[i])
1042      {
1043        fire[i]=0;
1044        fire_weapon(i);
1045      }
1046  }
1047  else
1048  {
1049    // Auto-fire
1050    if (attack_target.valid())
1051    {
1052      g1_object_class *mp = attack_target.get();
1053 
1054      i4_float dx,dy,angle, dangle;
1055 
1056      //this will obviously only be true if attack_target.ref != NULL   
1057      dx = (mp->x - (x+turret->x));
1058      dy = (mp->y - (y+turret->y));
1059 
1060      //aim the turret
1061 
1062      angle = i4_atan2(dy,dx);   
1063   
1064      //snap it
1065      i4_normalize_angle(angle);   
1066     
1067      dangle = i4_rotate_to(turret->rotation.z, angle, defaults->turn_speed);
1068      if (dangle<defaults->turn_speed && dangle>-defaults->turn_speed)
1069        fire_weapon(2);
1070    }
1071    else
1072    {
1073      if (!moved())
1074      {
1075        if (g1_tick_counter & 128)
1076          turret->rotation.z +=
1077            defaults->turn_speed * sin(i4_2pi() * (float)(g1_tick_counter & 63) / 64.f);
1078        else
1079          turret->rotation.z -=
1080            defaults->turn_speed * sin(i4_2pi() * (float)(g1_tick_counter & 63) / 64.f);
1081      }
1082    }
1083  }
1084 
1085  request_think();
1086
1087  pf_stank_think.stop();
1088}
1089
1090
1091void g1_player_piece_class::track_base(i4_float desired_angle)
1092{
1093  i4_float d;
1094 
1095  d = i4_angle_diff(desired_angle, theta);
1096 
1097  if (d<g1_resources.strafe_turn_speed)
1098  {
1099    theta=desired_angle;
1100    return ;
1101  }
1102
1103  if (i4_angle_minus(desired_angle, theta) < i4_pi())
1104  {
1105    theta += g1_resources.strafe_turn_speed;
1106    if (theta>=i4_2pi()) theta-=i4_2pi();
1107  }
1108  else
1109  {
1110    theta -= g1_resources.strafe_turn_speed;
1111    if (theta<0)
1112      theta += i4_2pi();
1113  }
1114}
1115
1116
1117extern w32 g1_num_objs_in_view;
1118extern w32 g1_objs_in_view[];
1119
1120g1_object_class *g1_player_piece_class::find_view_target(const i4_3d_vector &view_pos,
1121                                                         const i4_3d_vector &view_dir,
1122                                                         find_view_type type,
1123                                                         float max_dist)
1124{
1125  sw32 i;
1126  i4_float best;
1127  i4_3d_vector vdir=view_dir;
1128  vdir.normalize();
1129
1130 
1131  if (type==USE_SLOP)
1132    best = cos(i4_deg2rad(g1_resources.player_fire_slop_angle));
1133  else
1134    best = 0.0;
1135
1136  g1_object_class *fire_at_this = 0;
1137
1138  if (g1_num_objs_in_view <= 0) return 0;
1139
1140  for (i=0;i<g1_num_objs_in_view;i++)
1141  {
1142    if (g1_global_id.check_id(g1_objs_in_view[i]))
1143    {
1144      g1_object_class *p = g1_global_id.get(g1_objs_in_view[i]);
1145
1146      if (p && can_attack(p) && p->get_flag(DANGEROUS) && p!=(g1_object_class *)this)
1147      {
1148        i4_3d_vector source_to_target = i4_3d_vector(p->x, p->y, p->h);
1149        source_to_target -= view_pos;
1150
1151        float dist=source_to_target.length();
1152        source_to_target/=dist;
1153
1154        i4_float dot = fabs(source_to_target.dot(vdir));
1155        if (dot > best && dist<max_dist)
1156        {         
1157          best = dot;
1158          fire_at_this = p;
1159        }
1160      }
1161    }
1162  }
1163 
1164  return fire_at_this;
1165}
1166
1167
1168i4_bool g1_player_piece_class::in_range(int slot_number, g1_object_class *o) const
1169{
1170  if (!o) return i4_F;
1171
1172  int wtype=g1_get_object_type(ammo[slot_number].ammo_type->weapon_type);
1173  if (wtype==0) return i4_F;
1174
1175  i4_float range=g1_object_type_array[wtype]->get_damage_map()->range;
1176  range *= range;
1177  i4_float dist = (o->x-x)*(o->x-x) + (o->y-y)*(o->y-y);
1178
1179  return dist<range;
1180}
1181
1182i4_bool g1_player_piece_class::fire_weapon(int slot_number)
1183{
1184  g1_stank_ammo_info_struct *a=ammo+slot_number;
1185  if (a->delay_remaining)
1186    a->delay_remaining--;
1187  else
1188  {
1189    if (a->amount)
1190    { 
1191      i4_3d_point_class bpos, bdir; 
1192      get_bullet_exit(bpos, bdir);
1193
1194      float range=0;
1195      int wtype=g1_get_object_type(a->ammo_type->weapon_type);
1196      if (wtype)
1197        range=g1_object_type_array[wtype]->get_damage_map()->range;
1198     
1199      g1_object_class *fire_at=a->current_target.get();
1200
1201#if 0
1202      if (!fire_at)
1203        fire_at = attack_target.get();
1204#endif
1205
1206      // adjust fire direction to point directly at the object
1207      if (fire_at)
1208      {
1209        i4_3d_vector lead;
1210
1211        attack_target = a->current_target.get();
1212        lead_target(bdir, slot_number);
1213        bdir -= bpos;
1214        bdir.z += fire_at->occupancy_radius()/3;
1215      }
1216 
1217      g1_object_class *weapon = g1_fire(a->ammo_type->weapon_type, this,
1218                                        fire_at,
1219                                        bpos,
1220                                        bdir,
1221                                        a->last_fired_object.get());
1222      if (weapon)
1223      {
1224        a->amount--;
1225        a->delay_remaining=a->ammo_type->fire_delay;
1226        a->last_fired_object = weapon;
1227      }
1228
1229      return i4_T;
1230    }
1231  }
1232
1233  return i4_F;
1234}
1235
1236
1237
1238void fast_transform(i4_transform_class *t,const i4_3d_vector &src, r1_3d_point_class &dst);
1239
1240
1241static r1_texture_ref target_cursor_sprite("target_cursor");
1242static r1_texture_ref target_gun_cursor_sprite("gun_target_cursor");
1243static g1_model_ref lock_on("lock_on"), lock_on_guns("lock_on_guns");
1244
1245
1246static void draw_spining_tris(float px, float py, float z,
1247                              float theta,
1248                              g1_quad_object_class *o,                           
1249                              int ticks)
1250{
1251  g1_vert_class *v=o->get_verts(0,0);
1252
1253  i4_transform_class t;
1254  t.identity();
1255  t.mult_translate(px,py,0);
1256 
1257  float s=g1_render.center_x / z;
1258
1259  if (ticks<10)
1260  {
1261    ticks=11-ticks;
1262    while (ticks--)     
1263      s*=1.1;
1264  }
1265   
1266  t.mult_scale(s,s,1);
1267  t.mult_rotate_z(theta);
1268  t.mult_rotate_x(i4_pi()/2.0);
1269
1270 
1271 
1272  r1_render_api_class *api=g1_render.r_api;
1273
1274 
1275  r1_vert tv[4];
1276  for (int k=0; k<4; k++)
1277  {
1278    tv[k].v.z=r1_near_clip_z;
1279    tv[k].a=1;
1280    tv[k].w=r1_ooz(tv[k].v.z);
1281    tv[k].r=1;
1282    tv[k].g=1;
1283    tv[k].b=1;
1284  }
1285 
1286  for (int i=0; i<o->num_quad; i++)
1287  {
1288    i4_bool off=i4_F;
1289   
1290    g1_quad_class *q=o->quad+i;
1291    int t_verts=q->num_verts();
1292    for (int j=0; j<t_verts; j++)
1293    {
1294      t.transform(v[q->vertex_ref[j]].v, tv[j].v);
1295      tv[j].px=tv[j].v.x;
1296      tv[j].py=tv[j].v.y;
1297     
1298      if (tv[j].v.x<0 || tv[j].v.x>g1_render.center_x*2 ||
1299          tv[j].v.y<0 || tv[j].v.y>g1_render.center_y*2)
1300        off=i4_T;       
1301    }
1302 
1303    if (!off)
1304    {
1305      g1_render.r_api->use_texture(q->material_ref, 8, 0);
1306      g1_render.r_api->render_poly(t_verts, tv);
1307    }
1308  }
1309}
1310
1311
1312void g1_player_piece_class::draw_target_cursors(g1_draw_context_class *context)
1313{
1314  float z=r1_near_clip_z;
1315  float w_mult=z/g1_render.center_x;
1316 
1317  g1_render.render_sprite(i4_3d_vector(0,0,z),
1318                          target_cursor_sprite.get(), 33 * w_mult, 33 * w_mult);
1319
1320  r1_vert v;
1321
1322  float theta=(g1_tick_counter + g1_render.frame_ratio)/4.0;
1323 
1324  if (ammo[1].current_target.get())
1325  {
1326    g1_object_class *t=ammo[1].current_target.get();
1327    i4_3d_vector p=i4_3d_vector(t->x, t->y, t->h+ t->occupancy_radius()/3.0);
1328    i4_3d_vector lp=i4_3d_vector(t->lx, t->ly, t->lh+ t->occupancy_radius()/3.0);
1329    i4_3d_vector ip;
1330    ip.interpolate(lp, p, g1_render.frame_ratio);
1331
1332    if (g1_render.project_point(ip, v, context->transform))
1333      draw_spining_tris(v.px, v.py, v.v.z, theta,
1334                        lock_on_guns.get(),
1335                        ammo[1].ticks_this_has_been_my_current_target);
1336  }
1337
1338  theta+=0.4;
1339  if (ammo[2].current_target.get())
1340  {   
1341    g1_object_class *t=ammo[2].current_target.get();
1342
1343    i4_3d_vector p=i4_3d_vector(t->x, t->y, t->h+ t->occupancy_radius()/3.0);
1344    i4_3d_vector lp=i4_3d_vector(t->lx, t->ly, t->lh+ t->occupancy_radius()/3.0);
1345    i4_3d_vector ip;
1346    ip.interpolate(lp, p, g1_render.frame_ratio);
1347
1348    if (g1_render.project_point(ip, v, context->transform))
1349      draw_spining_tris(v.px, v.py, v.v.z, theta,
1350                        lock_on.get(),
1351                        ammo[1].ticks_this_has_been_my_current_target);
1352  }
1353 
1354}
1355
1356void g1_player_piece_class::look_for_targets()
1357{
1358  if (!g1_player_man.get_local() ||
1359      g1_player_man.get_local()->get_player_num()!=player_num)
1360  {
1361    ammo[0].current_target=0;
1362    if (attack_target.valid())
1363      ammo[1].current_target = attack_target.get();
1364    ammo[2].current_target=0;
1365    return;
1366  }
1367
1368  i4_3d_vector bpos, bdir; 
1369  get_bullet_exit(bpos, bdir);
1370
1371  for (int i=0; i<MAX_WEAPONS; i++)
1372  {
1373    if (ammo[i].amount)
1374    {
1375      float range=0;
1376      int wtype=g1_get_object_type(ammo[i].ammo_type->weapon_type);
1377      if (wtype)
1378        range=g1_object_type_array[wtype]->get_damage_map()->range;
1379
1380      g1_object_class *t=find_view_target(bpos, bdir, i ? USE_SCREEN : USE_SLOP, range);
1381   
1382      if (t==ammo[i].current_target.get())     
1383        ammo[i].ticks_this_has_been_my_current_target++;
1384      else
1385      {
1386        ammo[i].ticks_this_has_been_my_current_target=0;
1387        ammo[i].current_target=t;
1388      }
1389    }
1390    else
1391    {
1392      ammo[i].ticks_this_has_been_my_current_target=0;
1393      ammo[i].current_target=0;
1394    }
1395  }
1396}
1397
1398void g1_player_piece_class::draw(g1_draw_context_class *context)
1399{
1400  g1_player_piece_class *local_stank=g1_player_man.get_local()->get_commander();
1401   
1402
1403  if (g1_current_controller.get() &&
1404      this==local_stank && g1_current_controller->view.get_view_mode()==G1_ACTION_MODE)
1405    draw_target_cursors(context);
1406
1407   
1408  sw8 damage_level;
1409
1410  if (health > defaults->health)
1411    damage_level = 7;
1412  else
1413  if (health < 0)
1414    damage_level = 0;
1415  else
1416    damage_level = i4_f_to_i(7.f * health / (float)defaults->health);
1417 
1418  g1_render.set_render_damage_level(damage_level);
1419
1420  g1_screen_box *bbox=0;
1421
1422  if (get_flag(g1_object_class::SELECTABLE | g1_object_class::TARGETABLE))
1423  {
1424    if (g1_render.current_selectable_list)
1425      bbox=g1_render.current_selectable_list->add();
1426    if (bbox)
1427    {
1428      bbox->x1 = 2048;
1429      bbox->y1 = 2048;
1430      bbox->x2 = -1;
1431      bbox->y2 = -1;
1432      bbox->z1 = 999999;
1433      bbox->z2 = -999999;
1434      bbox->w  = 1.0/999999;
1435      bbox->object_id=global_id;
1436    }
1437  }
1438
1439 
1440  //draw with this model
1441  g1_quad_object_class *model = draw_params.model;
1442
1443  //3d vectors
1444  i4_transform_class out;
1445  i4_transform_class *old = context->transform; 
1446  context->transform = &out;
1447
1448  out.multiply(*old, *world_transform);
1449
1450  if (this!=local_stank ||
1451      !g1_current_controller.get() ||
1452      g1_current_controller->view.get_view_mode()!=G1_ACTION_MODE)
1453  {
1454    g1_render.render_object(model,
1455                            &out,
1456                            world_transform,
1457                            1,                     
1458                            player_num,
1459                            draw_params.frame,
1460                            bbox,
1461                            0);
1462  }
1463 
1464  turret->offset.x = i4_interpolate(lturret_kick, turret_kick, g1_render.frame_ratio);
1465
1466
1467  // draw barrel with alpha if in action mode and on the local supertank
1468  if (this==local_stank &&
1469      g1_current_controller.get() &&
1470      g1_current_controller->view.get_view_mode()==G1_ACTION_MODE)
1471  {
1472   
1473//     g1_render.r_api->set_alpha_mode(R1_ALPHA_CONSTANT);
1474//     g1_render.r_api->set_write_mode(R1_COMPARE_W | R1_WRITE_COLOR);
1475//     g1_render.r_api->set_shading_mode(R1_COLORED_SHADING);
1476//     g1_render.r_api->set_constant_color((w32)(0.80 * 255) << 24);
1477
1478    i4_3d_vector r     = turret->rotation;
1479    i4_3d_vector old_r = turret->lrotation;
1480   
1481    turret->rotation.z  = turret->rotation.z  - theta;
1482    turret->lrotation.z = turret->lrotation.z - ltheta;
1483
1484    i4_transform_class turret_local;
1485    turret->calc_transform(g1_render.frame_ratio, &turret_local);
1486
1487    turret->draw(context,
1488                world_transform,
1489                bbox,
1490                player_num,
1491                &turret_local);
1492   
1493    turret->rotation  = r;
1494    turret->lrotation = old_r;
1495
1496//     g1_render.r_api->set_alpha_mode(R1_ALPHA_DISABLED);
1497//     g1_render.r_api->set_write_mode(R1_COMPARE_W | R1_WRITE_W | R1_WRITE_COLOR);
1498  }
1499  else
1500  {
1501    i4_3d_vector r     = turret->rotation;
1502    i4_3d_vector old_r = turret->lrotation;
1503   
1504    turret->rotation.x  = 0;
1505    turret->lrotation.x = 0;
1506   
1507    turret->rotation.y  = 0;
1508    turret->lrotation.y = 0;
1509
1510    turret->rotation.z  = turret->rotation.z  - theta;
1511    turret->lrotation.z = turret->lrotation.z - ltheta;
1512
1513    turret->draw(context,
1514                world_transform,
1515                bbox,
1516                player_num);
1517   
1518    turret->rotation  = r;
1519    turret->lrotation = old_r;
1520  }
1521
1522  //get back the old context transform 
1523  context->transform = old;
1524
1525  g1_render.set_render_damage_level(-1);
1526
1527  if (path)
1528  {
1529    i4_3d_point_class a(x,y,h+0.1),b(dest_x,dest_y,0),c;
1530
1531    b.z = g1_get_map()->terrain_height(b.x,b.y)+0.1;
1532    c = b;
1533    g1_path_manager.get_nth_position(path,1,c.x,c.y);
1534    c.z = g1_get_map()->terrain_height(c.x,c.y)+0.1;
1535    g1_render.render_3d_line(a,b,0x00ff00,0x00ff00,context->transform);
1536    g1_render.render_3d_line(b,c,0x00ff00,0x00ff00,context->transform);
1537  }
1538
1539}
1540
1541
1542void g1_player_piece_class::get_bullet_exit(i4_3d_vector &pos,
1543                                            i4_3d_vector &dir)
1544{
1545#if 1
1546  i4_3d_vector r  = turret->rotation;
1547  i4_3d_vector lr = turret->lrotation;
1548 
1549  turret->rotation.z  = turret->rotation.z  - theta;
1550  turret->lrotation.z = turret->lrotation.z - ltheta;
1551
1552  i4_transform_class t, main, l2w;
1553  turret->calc_transform(1.0, &t);   
1554  calc_world_transform(1.0, &main);
1555  l2w.multiply(main, t);
1556   
1557  l2w.transform(muzzle_exit, pos);
1558  dir=l2w.x;
1559
1560  turret->rotation = r;
1561  turret->lrotation = lr;
1562#else
1563  i4_transform_class spare_transform;
1564
1565  i4_transform_class temp_transform;
1566
1567  spare_transform.identity();
1568
1569  temp_transform.rotate_x(groundroll);
1570  spare_transform.multiply(temp_transform);
1571
1572  temp_transform.rotate_y(groundpitch);
1573  spare_transform.multiply(temp_transform);
1574                 
1575  temp_transform.rotate_z(turret->rotation.z);
1576  spare_transform.multiply(temp_transform);
1577
1578  temp_transform.rotate_y(turret->rotation.y);
1579  spare_transform.multiply(temp_transform);
1580
1581  i4_3d_vector bullet_pos;
1582  i4_3d_vector bullet_dir;
1583  i4_3d_vector tmp;
1584 
1585  bullet_pos.x = g1_resources.player_turret_radius;
1586  bullet_pos.y = 0.023;
1587  bullet_pos.z = 0.17;
1588
1589  bullet_dir.x = g1_resources.bullet_speed;
1590  bullet_dir.y = 0;
1591  bullet_dir.z = 0;
1592 
1593  spare_transform.transform(bullet_pos, pos);
1594
1595  pos.x += x;
1596  pos.y += y;
1597  pos.z += h;
1598 
1599  spare_transform.transform(bullet_dir, dir);
1600#endif
1601}
1602
1603g1_player_piece_class::~g1_player_piece_class()
1604{
1605  if (player_num==g1_player_man.local_player)
1606    g1_hurt_tint=0;
1607}
1608
1609
1610static int first_hurt=1;
1611
1612void g1_player_piece_class::damage(g1_object_class *obj, int hp, i4_3d_vector _damage_dir)
1613{
1614  if (player_num == g1_player_man.local_player)
1615  {
1616    if (hp>10)
1617    {
1618      i4_angle dir = i4_atan2(_damage_dir.y, _damage_dir.x);
1619     
1620      dir -= theta;
1621      i4_normalize_angle(dir);
1622     
1623      if (dir>i4_pi())
1624        roll = 0.08;
1625      else
1626        roll = -0.08;
1627    }
1628
1629    hurt += i4_f_to_i(hp)/100.0;
1630    hurt = (hurt>0.99999)?0.99999 : hurt;
1631
1632    if (first_hurt)
1633    {
1634      first_hurt=0;
1635      return_to_repair.play();
1636    }
1637
1638    if (health!=0 && health-hp<=0)
1639    {
1640      if (g1_current_controller.get())
1641      {
1642        g1_current_controller->view.suggest_camera_mode(G1_CIRCLE_WAIT,
1643                                                         global_id);
1644        g1_current_controller->scroll_message("Death cometh.  Press any Key..");       
1645      }
1646    }
1647
1648  }
1649
1650  if (health!=0 && health-hp<=0)
1651  {
1652    g1_player_man.get(player_num)->continue_wait=1;
1653    theta = base_angle;
1654    g1_create_carcass(this, stank_carcass.get());
1655  }
1656
1657  if ((stank_flags & ST_GODMODE)==0)   
1658    g1_map_piece_class::damage(obj, hp, _damage_dir);
1659 
1660}
1661
1662void g1_player_piece_class::notify_damage(g1_object_class *obj, sw32 hp)
1663{
1664  // did we kill this guy?
1665  if (obj->health-hp<=0 && obj->get_flag(DANGEROUS))
1666    g1_player_man.get(player_num)->add_points(obj->get_type()->defaults->cost);
1667}
1668
1669void g1_player_piece_class::calc_action_cam(g1_camera_info_struct &cam,
1670                                            float fr)
1671
1672  i4_transform_class cam_transform;
1673 
1674  i4_3d_vector interp_pos,tmp;
1675  interp_pos.interpolate(i4_3d_vector(lx,ly,lh), i4_3d_vector(x,y,h), fr);
1676
1677  cam.ground_rotate = i4_interpolate_angle(turret->lrotation.z, turret->rotation.z, fr);
1678  cam.horizon_rotate = i4_interpolate_angle(turret->lrotation.y, turret->rotation.y, fr);
1679  cam.roll  = i4_interpolate_angle(lroll, roll, fr);
1680  cam.ground_x_rotate = i4_interpolate_angle(lgroundroll,  groundroll, fr);
1681  cam.ground_y_rotate = i4_interpolate_angle(lgroundpitch, groundpitch, fr);
1682   
1683  cam_transform.translate(interp_pos.x, interp_pos.y, interp_pos.z);
1684
1685  cam_transform.mult_rotate_x(cam.ground_x_rotate);
1686  cam_transform.mult_rotate_y(cam.ground_y_rotate);
1687  cam_transform.mult_rotate_z(cam.ground_rotate);
1688  cam_transform.mult_rotate_y(cam.horizon_rotate);
1689 
1690  //hardcoded position of the camera, relative to (0,0,0) of the turret model
1691  cam_transform.transform(i4_3d_vector(0.15, 0.023, 0.12), tmp);
1692
1693  cam.gx = tmp.x;
1694  cam.gy = tmp.y;
1695  cam.gz = tmp.z;
1696}
Note: See TracBrowser for help on using the repository browser.