3 Copyright (C) 2003 Nuno Subtil
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 static const char cvsid
[] =
21 "$Id: ghost.c,v 1.21 2003/11/22 17:07:42 nsubtil Exp $";
42 GLfloat ghost_colors
[4][4] = {
43 {GHOST_GREEN
}, {GHOST_RED
}, {GHOST_MAGENTA
}, {GHOST_ORANGE
}
45 int num_ghost_colors
= 4;
47 void ghost_taint_all(struct game
*game
)
51 for(c
= 0; c
< game
->n_ghosts
; c
++)
52 if(!game
->ghosts
[c
].tainted
&& game
->ghosts
[c
].state
== GHOST_STATE_ACTIVE
)
54 game
->ghosts
[c
].tainted
= 1;
55 game
->ghosts
[c
].speed
/= 2.0;
59 void ghost_untaint_all(struct game
*game
)
63 for(c
= 0; c
< game
->n_ghosts
; c
++)
64 if(game
->ghosts
[c
].tainted
)
66 game
->ghosts
[c
].tainted
= 0;
67 game
->ghosts
[c
].speed
*= 2.0;
71 void ghost_reset_all(struct game
*game
)
84 for(cx
= 0; cx
< map
->width
; cx
++)
85 for(cy
= 0; cy
< map
->height
; cy
++)
86 if(MAP(map
, cx
, cy
).flags
& MAP_FLAG_GHOST_START_POSITION
)
91 game
->ghosts
= realloc(game
->ghosts
,
92 sizeof(struct ghost
) * game
->n_ghosts
);
94 new = &game
->ghosts
[game
->n_ghosts
- 1];
95 new->state
= GHOST_STATE_ACTIVE
;
97 new->position
[X
] = (float)cx
+ 0.5;
98 new->position
[Y
] = -0.5;
99 new->position
[Z
] = (float)cy
+ 0.5;
101 new->direction
= DIRECTION_UP
;
102 new->speed
= GHOST_SPEED
;
105 object_read_file("gfx/ghost-green-moving.3d",
106 &new->frames_active
);
109 object_read_file("gfx/ghost-green-dying.3d",
112 new->model_dead
= &new->model_dying
[new->frames_dying
- 1];
113 new->frames_dead
= 1;
115 new->model_returning
=
116 object_read_file("gfx/ghost-green-returning.3d",
117 &new->frames_returning
);
119 new->current_frame
= (float)(rand() % new->frames_active
);
121 new->view_distance
= 10;
123 new->color
= ghost_colors
[(game
->n_ghosts
- 1) % num_ghost_colors
];
128 void ghost_kill(struct game
*game
, struct ghost
*g
)
130 g
->state
= GHOST_STATE_DYING
;
131 g
->current_frame
= 0.0;
132 audio_play_sample("sfx/eat-ghost.wav");
135 void ghost_update(struct game
*game
, int ghost_no
, float delta
)
137 float new_position
[3], vec
[2];
138 float frac_x
, frac_z
, dest_x
, dest_z
;
141 int keep_moving
= 1, verify
= 0;
143 g
= &game
->ghosts
[ghost_no
];
148 case GHOST_STATE_DYING
:
149 g
->current_frame
+= delta
* ANIM_FPS
;
151 if(g
->current_frame
>= (float)g
->frames_dying
)
153 g
->state
= GHOST_STATE_DEAD
;
154 g
->current_frame
= 0.0;
165 case GHOST_STATE_RETURNING
:
166 g
->current_frame
+= delta
* ANIM_FPS
;
168 if(g
->current_frame
>= (float)g
->frames_returning
)
170 g
->state
= GHOST_STATE_ACTIVE
;
171 g
->current_frame
= 0.0;
181 new_position
[X
] = g
->position
[X
];
182 new_position
[Y
] = g
->position
[Y
];
183 new_position
[Z
] = g
->position
[Z
];
185 frac_x
= g
->position
[X
] - (float)((int)g
->position
[X
]);
186 frac_z
= g
->position
[Z
] - (float)((int)g
->position
[Z
]);
188 dest_x
= (int)g
->position
[X
] + 0.5;
189 dest_z
= (int)g
->position
[Z
] + 0.5;
194 new_position
[Z
] += MIN(delta
* g
->speed
, 0.5);
199 if(new_position
[Z
] > dest_z
)
205 g
->position
[X
] = new_position
[X
];
206 g
->position
[Z
] = new_position
[Z
];
208 g
->position
[X
] = dest_x
;
209 g
->position
[Z
] = dest_z
;
210 ghost_new_direction(game
, g
);
213 if(MAP_CAN_ENTER_GHOST(map
, (int)dest_x
, (int)dest_z
))
215 g
->position
[X
] = new_position
[X
];
216 g
->position
[Z
] = new_position
[Z
];
219 g
->position
[X
] = dest_x
;
220 g
->position
[Z
] = dest_z
- 1.0;
222 ghost_new_direction(game
, g
);
223 } while(g
->direction
== DIRECTION_UP
&&
224 g
->state
!= GHOST_STATE_DEAD
);
231 new_position
[Z
] -= MIN(delta
* g
->speed
, 0.5);
236 if(new_position
[Z
] < dest_z
)
242 g
->position
[X
] = new_position
[X
];
243 g
->position
[Z
] = new_position
[Z
];
245 g
->position
[X
] = dest_x
;
246 g
->position
[Z
] = dest_z
;
247 ghost_new_direction(game
, g
);
250 if(MAP_CAN_ENTER_GHOST(map
, (int)dest_x
, (int)dest_z
))
252 g
->position
[X
] = new_position
[X
];
253 g
->position
[Z
] = new_position
[Z
];
256 g
->position
[X
] = dest_x
;
257 g
->position
[Z
] = dest_z
+ 1.0;
259 ghost_new_direction(game
, g
);
260 } while(g
->direction
== DIRECTION_DOWN
&&
261 g
->state
!= GHOST_STATE_DEAD
);
268 new_position
[X
] -= MIN(delta
* g
->speed
, 0.5);
273 if(new_position
[X
] < dest_x
)
279 g
->position
[X
] = new_position
[X
];
280 g
->position
[Z
] = new_position
[Z
];
282 g
->position
[X
] = dest_x
;
283 g
->position
[Z
] = dest_z
;
284 ghost_new_direction(game
, g
);
287 if(MAP_CAN_ENTER_GHOST(map
, (int)dest_x
, (int)dest_z
))
289 g
->position
[X
] = new_position
[X
];
290 g
->position
[Z
] = new_position
[Z
];
293 g
->position
[X
] = dest_x
+ 1.0;
294 g
->position
[Z
] = dest_z
;
296 ghost_new_direction(game
, g
);
297 } while(g
->direction
== DIRECTION_LEFT
&&
298 g
->state
!= GHOST_STATE_DEAD
);
304 case DIRECTION_RIGHT
:
305 new_position
[X
] += MIN(delta
* g
->speed
, 0.5);
310 if(new_position
[X
] > dest_x
)
316 g
->position
[X
] = new_position
[X
];
317 g
->position
[Z
] = new_position
[Z
];
319 g
->position
[X
] = dest_x
;
320 g
->position
[Z
] = dest_z
;
321 ghost_new_direction(game
, g
);
324 if(MAP_CAN_ENTER_GHOST(map
, (int)dest_x
, (int)dest_z
))
326 g
->position
[X
] = new_position
[X
];
327 g
->position
[Z
] = new_position
[Z
];
330 g
->position
[X
] = dest_x
- 1.0;
331 g
->position
[Z
] = dest_z
;
333 ghost_new_direction(game
, g
);
334 } while(g
->direction
== DIRECTION_RIGHT
&&
335 g
->state
!= GHOST_STATE_DEAD
);
343 ghost_new_direction(game
, g
);
345 vec
[X
] = g
->position
[X
] - (float)((int)g
->position
[X
]);
346 vec
[Y
] = g
->position
[Z
] - (float)((int)g
->position
[Z
]);
347 if(verify
|| math_norm_vec2(vec
) <= 0.1)
349 if(MAP(map
, (int)g
->position
[X
], (int)g
->position
[Z
]).flags
& MAP_FLAG_GHOST_START_POSITION
)
350 if(g
->state
== GHOST_STATE_DEAD
)
352 g
->state
= GHOST_STATE_RETURNING
;
353 g
->current_frame
= 0.0;
354 audio_play_sample("sfx/ghost-return.wav");
358 switch(MAP(map
, (int)g
->position
[X
], (int)g
->position
[Z
]).ghost_dir_alive
)
361 if(g
->state
== GHOST_STATE_ACTIVE
)
363 g
->direction
= DIRECTION_UP
;
364 g
->time
= 1.0 / g
->speed
;
373 dir
= ghost_check_visibility(game
, g
, &dist
);
376 /* jogador por perto */
378 g
->time
= dist
/ g
->speed
;
385 g
->current_frame
= g
->current_frame
+ delta
* ANIM_FPS
;
387 ghost_detect_player_collisions(game
, g
);
388 ghost_detect_ghost_collisions(game
, g
);
391 void ghost_detect_ghost_collisions(struct game
*game
, struct ghost
*g
)
399 for(c
= 0; c
< game
->n_ghosts
; c
++)
401 math_sub_vec3(vec
, g
->position
, game
->ghosts
[c
].position
);
403 if(math_norm_vec3(vec
) < 0.7)
407 if(math_norm_vec3(vec
) == 0.0)
411 if(g
->direction
== DIRECTION_STOPPED
)
415 gx
= (int)g
->position
[X
];
416 gy
= (int)g
->position
[Z
];
418 ox
= (int)game
->ghosts
[c
].position
[X
];
419 oy
= (int)game
->ghosts
[c
].position
[Z
];
423 /* escapatória para g */
424 if(MAP_CAN_ENTER_GHOST(map
, gx
, gy
+ 1) &&
425 !ghost_in_position(game
, gx
, gy
+ 1))
427 g
->direction
= DIRECTION_UP
;
430 // ghosts[c].direction = DIRECTION_STOPPED;
431 // ghosts[c].time = 0.25;
435 if(MAP_CAN_ENTER_GHOST(map
, gx
, gy
- 1) &&
436 !ghost_in_position(game
, gx
, gy
- 1))
438 g
->direction
= DIRECTION_DOWN
;
441 // ghosts[c].direction = DIRECTION_STOPPED;
442 // ghosts[c].time = 0.25;
446 if(MAP_CAN_ENTER_GHOST(map
, gx
- 1, gy
) &&
447 !ghost_in_position(game
, gx
- 1, gy
))
449 g
->direction
= DIRECTION_LEFT
;
452 // ghosts[c].direction = DIRECTION_STOPPED;
453 // ghosts[c].time = 0.25;
457 if(MAP_CAN_ENTER_GHOST(map
, gx
+ 1, gy
) &&
458 !ghost_in_position(game
, gx
+ 1, gy
))
460 g
->direction
= DIRECTION_RIGHT
;
463 // ghosts[c].direction = DIRECTION_STOPPED;
464 // ghosts[c].time = 0.25;
468 /* escapatória para ghosts[c] */
469 g
->direction
= DIRECTION_STOPPED
;
472 if(MAP_CAN_ENTER_GHOST(map
, ox
, oy
+ 1) &&
473 !ghost_in_position(game
, ox
, oy
+ 1))
475 game
->ghosts
[c
].direction
= DIRECTION_UP
;
476 game
->ghosts
[c
].time
= 1.0;
480 if(MAP_CAN_ENTER_GHOST(map
, ox
, oy
- 1) &&
481 !ghost_in_position(game
, ox
, oy
- 1))
483 game
->ghosts
[c
].direction
= DIRECTION_DOWN
;
484 game
->ghosts
[c
].time
= 1.0;
488 if(MAP_CAN_ENTER_GHOST(map
, ox
- 1, oy
) &&
489 !ghost_in_position(game
, ox
- 1, oy
))
491 game
->ghosts
[c
].direction
= DIRECTION_LEFT
;
492 game
->ghosts
[c
].time
= 1.0;
496 if(MAP_CAN_ENTER_GHOST(map
, ox
+ 1, oy
) &&
497 !ghost_in_position(game
, ox
+ 1, oy
))
499 game
->ghosts
[c
].direction
= DIRECTION_RIGHT
;
500 game
->ghosts
[c
].time
= 1.0;
504 game
->ghosts
[c
].direction
= DIRECTION_STOPPED
;
505 game
->ghosts
[c
].time
= 0.25;
507 /* escapatória para ghosts[c] */
508 if(MAP_CAN_ENTER_GHOST(map
, ox
, oy
+ 1) &&
509 !ghost_in_position(game
, ox
, oy
+ 1))
511 game
->ghosts
[c
].direction
= DIRECTION_UP
;
512 game
->ghosts
[c
].time
= 1.0;
514 // g->direction = DIRECTION_STOPPED;
519 if(MAP_CAN_ENTER_GHOST(map
, ox
, oy
- 1) &&
520 !ghost_in_position(game
, ox
, oy
- 1))
522 game
->ghosts
[c
].direction
= DIRECTION_DOWN
;
523 game
->ghosts
[c
].time
= 1.0;
525 // g->direction = DIRECTION_STOPPED;
530 if(MAP_CAN_ENTER_GHOST(map
, ox
- 1, oy
) &&
531 !ghost_in_position(game
, ox
- 1, oy
))
533 game
->ghosts
[c
].direction
= DIRECTION_LEFT
;
534 game
->ghosts
[c
].time
= 1.0;
536 // g->direction = DIRECTION_STOPPED;
541 if(MAP_CAN_ENTER_GHOST(map
, ox
+ 1, oy
) &&
542 !ghost_in_position(game
, ox
+ 1, oy
))
544 game
->ghosts
[c
].direction
= DIRECTION_RIGHT
;
545 game
->ghosts
[c
].time
= 1.0;
547 // g->direction = DIRECTION_STOPPED;
552 game
->ghosts
[c
].direction
= DIRECTION_STOPPED
;
553 game
->ghosts
[c
].time
= 0.0;
555 /* escapatória para g */
556 if(MAP_CAN_ENTER_GHOST(map
, gx
, gy
+ 1) &&
557 !ghost_in_position(game
, gx
, gy
+ 1))
559 g
->direction
= DIRECTION_UP
;
564 if(MAP_CAN_ENTER_GHOST(map
, gx
, gy
- 1) &&
565 !ghost_in_position(game
, gx
, gy
- 1))
567 g
->direction
= DIRECTION_DOWN
;
572 if(MAP_CAN_ENTER_GHOST(map
, gx
- 1, gy
) &&
573 !ghost_in_position(game
, gx
- 1, gy
))
575 g
->direction
= DIRECTION_LEFT
;
580 if(MAP_CAN_ENTER_GHOST(map
, gx
+ 1, gy
) &&
581 !ghost_in_position(game
, gx
+ 1, gy
))
583 g
->direction
= DIRECTION_RIGHT
;
588 g
->direction
= DIRECTION_STOPPED
;
595 int ghost_in_position(struct game
*game
, int x
, int y
)
599 for(c
= 0; c
< game
->n_ghosts
; c
++)
600 if((int)game
->ghosts
[c
].position
[X
] == x
&&
601 (int)game
->ghosts
[c
].position
[Z
] == y
)
607 void ghost_detect_player_collisions(struct game
*game
, struct ghost
*g
)
612 if(g
->state
!= GHOST_STATE_ACTIVE
)
615 for(c
= 0; c
< game
->n_players
; c
++)
617 if(game
->players
[c
].state
== PLAYER_STATE_DEAD
)
620 math_sub_vec3(vec
, g
->position
, game
->players
[c
].position
);
621 if(math_norm_vec3(vec
) < 0.7)
623 /* fantasma bateu num jogador */
624 if(game
->players
[c
].pill_time
> 0.0)
626 /* uh oh, fantasma comido */
627 game
->players
[c
].score
+= (100 * game
->players
[c
].multiplier
);
628 game
->players
[c
].multiplier
<<= 1;
636 g
->direction
= DIRECTION_DOWN
;
640 g
->direction
= DIRECTION_UP
;
644 g
->direction
= DIRECTION_RIGHT
;
647 case DIRECTION_RIGHT
:
648 g
->direction
= DIRECTION_LEFT
;
652 g
->time
= 1.0 / g
->speed
;
654 player_kill(game
, c
);
661 devolve a direcção de um jogador próximo (distância em dist)
664 int ghost_check_visibility(struct game
*game
, struct ghost
*g
, int *r_dist
)
666 int c
, px
, py
, gx
, gy
, dist
, player_no
;
670 gx
= (int)g
->position
[X
];
671 gy
= (int)g
->position
[Z
];
673 if(g
->state
== GHOST_STATE_DEAD
)
676 /* determinar visibilidade de jogadores próximos */
677 for(player_no
= 0; player_no
< game
->n_players
; player_no
++)
679 if(game
->players
[player_no
].state
== PLAYER_STATE_DEAD
)
682 px
= (int)game
->players
[player_no
].position
[X
];
683 py
= (int)game
->players
[player_no
].position
[Z
];
691 if(dist
> g
->view_distance
)
697 for(c
= gx
- 1; c
> px
; c
--)
698 if(!MAP_CAN_ENTER_GHOST(map
, c
, py
))
704 /* jogador à esquerda */
707 if(game
->players
[player_no
].pill_time
> 0.0)
712 if(MAP_CAN_ENTER_GHOST(map
,
713 (int)g
->position
[X
] + 1,
714 (int)g
->position
[Z
]))
715 return DIRECTION_RIGHT
;
717 if(MAP_CAN_ENTER_GHOST(map
,
719 (int)g
->position
[Z
] + 1))
722 if(MAP_CAN_ENTER_GHOST(map
,
724 (int)g
->position
[Z
] - 1))
725 return DIRECTION_DOWN
;
727 /* sem hipótese de fugir */
730 return DIRECTION_LEFT
;
733 for(c
= gx
+ 1; c
< px
; c
++)
734 if(!MAP_CAN_ENTER_GHOST(map
, c
, py
))
739 /* jogador à direita */
742 if(game
->players
[player_no
].pill_time
> 0.0)
747 if(MAP_CAN_ENTER_GHOST(map
,
748 (int)g
->position
[X
] - 1,
749 (int)g
->position
[Z
]))
750 return DIRECTION_LEFT
;
752 if(MAP_CAN_ENTER_GHOST(map
,
754 (int)g
->position
[Z
] + 1))
757 if(MAP_CAN_ENTER_GHOST(map
,
759 (int)g
->position
[Z
] - 1))
760 return DIRECTION_DOWN
;
763 return DIRECTION_RIGHT
;
774 if(dist
> g
->view_distance
)
779 for(c
= gy
- 1; c
> py
; c
--)
780 if(!MAP_CAN_ENTER_GHOST(map
, px
, c
))
788 if(game
->players
[player_no
].pill_time
> 0.0)
792 if(MAP_CAN_ENTER_GHOST(map
,
794 (int)g
->position
[Z
] + 1))
797 if(MAP_CAN_ENTER_GHOST(map
,
798 (int)g
->position
[X
] - 1,
799 (int)g
->position
[Z
]))
800 return DIRECTION_LEFT
;
802 if(MAP_CAN_ENTER_GHOST(map
,
803 (int)g
->position
[X
] + 1,
804 (int)g
->position
[Z
]))
805 return DIRECTION_RIGHT
;
808 return DIRECTION_DOWN
;
811 for(c
= gy
+ 1; c
< py
; c
++)
812 if(!MAP_CAN_ENTER_GHOST(map
, px
, c
))
820 if(game
->players
[player_no
].pill_time
> 0.0)
824 if(MAP_CAN_ENTER_GHOST(map
,
826 (int)g
->position
[Z
] - 1))
827 return DIRECTION_DOWN
;
829 if(MAP_CAN_ENTER_GHOST(map
,
830 (int)g
->position
[X
] - 1,
831 (int)g
->position
[Z
]))
832 return DIRECTION_LEFT
;
834 if(MAP_CAN_ENTER_GHOST(map
,
835 (int)g
->position
[X
] + 1,
836 (int)g
->position
[Z
]))
837 return DIRECTION_RIGHT
;
849 void ghost_new_direction(struct game
*game
, struct ghost
*g
)
857 g
->position
[X
] = (float)((int)g
->position
[X
]) + 0.5;
858 g
->position
[Z
] = (float)((int)g
->position
[Z
]) + 0.5;
860 if(g
->state
== GHOST_STATE_DEAD
)
862 g
->time
= 1.0 / g
->speed
;
864 switch(MAP(map
, (int)g
->position
[X
], (int)g
->position
[Z
]).ghost_dir
)
867 g
->direction
= DIRECTION_UP
;
871 g
->direction
= DIRECTION_DOWN
;
875 g
->direction
= DIRECTION_LEFT
;
878 case DIRECTION_RIGHT
:
879 g
->direction
= DIRECTION_RIGHT
;
883 if(MAP(map
, (int)g
->position
[X
], (int)g
->position
[Z
]).flags
& MAP_FLAG_GHOST_START_POSITION
)
889 printf("ghost_new_direction: que raio está um (hmm...) a fazer no mapa ? (%d %d)\n", (int)g
->position
[X
], (int)g
->position
[Z
]);
900 dir
= ghost_check_visibility(game
, g
, &dist
);
903 /* não há jogadores visíveis, direcção aleatória */
904 g
->direction
= rand() % DIRECTION_COUNT
;
905 g
->time
= (float)(rand() % 5) + 1.0;
908 g
->time
= dist
/ g
->speed
;