📄 enemy.cpp
字号:
/*************************************************************************
"I Have No Tomatoes"
Copyright (c) 2004, Mika Halttunen
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must
not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
Mika Halttunen <lsoft@mbnet.fi>
*************************************************************************/
#include <stdio.h>
#include "SDL.h"
#include "SDL_opengl.h"
#include "SDL_image.h"
#include "texture.h"
#include "game.h"
#include "init.h"
#include "player.h"
#include "mymath.h"
#include "tilemap.h"
#include "enemy.h"
#include "particle.h"
#include "bonus.h"
#include "helpers.h"
#include "effects.h"
#include "special_power.h"
#include "trap.h"
#include "soundmusic.h"
#include "levels.h"
// Enemy list
list<ENEMY> enemylist;
// Enemy animations
GLuint enemy_anim[3];
static int anim_frames[4] = { 0, 1, 0, 2 };
// Texture from player.cpp
extern GLuint sprite_shadow;
// From bonus.cpp
extern int killed_5_diamonds;
// The counter for the continuous enemy creation
int enemy_creation_counter;
// Amount of time between two enemy creation periods
const int enemy_creation_interval = 90;
// Enemy burning time
int enemy_burn_time = 420;
// Load the enemies
void load_enemies() {
// Load the red enemy animations
enemy_anim[0] = load_png("enemy1.png", true, false, false);
enemy_anim[1] = load_png("enemy2.png", true, false, false);
enemy_anim[2] = load_png("enemy3.png", true, false, false);
}
// Helper function which checks if the players are right next to
// a location or in the same region
bool is_player_close(int x, int y) {
// Check distance to the players
int dx = x - (int)p1.get_real_x();
int dy = y - (int)p1.get_real_y();
if(dx*dx + dy*dy <= 49) // 49 == 7*7
return true;
if(two_players) {
dx = x - (int)p2.get_real_x();
dy = y - (int)p2.get_real_y();
if(dx*dx + dy*dy <= 49) // 49 == 7*7
return true;
}
// Determine the regions (4x4)
int p1reg = 0, p2reg = 0;
if(p1.x < 7 && p1.y <= 7)
p1reg = 1;
else if(p1.x < 7 && p1.y > 7)
p1reg = 3;
else if(p1.x >= 7 && p1.y <= 7)
p1reg = 2;
else
p1reg = 4;
if(two_players) {
if(p2.x < 7 && p2.y <= 7)
p2reg = 1;
else if(p2.x < 7 && p2.y > 7)
p2reg = 3;
else if(p2.x >= 7 && p2.y <= 7)
p2reg = 2;
else
p2reg = 4;
}
int ereg;
if(x < 7 && y <= 7)
ereg = 1;
else if(x < 7 && y > 7)
ereg = 3;
else if(x >= 7 && y <= 7)
ereg = 2;
else
ereg = 4;
// Check the region
if(p1reg == ereg)
return true;
if(two_players && p2reg == ereg)
return true;
return false;
}
// Helper function which adds an new enemy while checking
// for bad places
bool new_enemy(int &ex, int &ey) {
// Add a new enemy
ENEMY e;
e.clear();
// Check for bad places
int x = RAND(0, MAP_W-1);
int y = RAND(0, MAP_H-1);
int counter = 0;
while((!can_teleport(x, y) || is_player_close(x,y)) && counter < 10000) {
x = RAND(0, MAP_W-1);
y = RAND(0, MAP_H-1);
counter++;
}
if(counter >= 10000)
return false;
e.x = x;
e.y = y;
ex = x;
ey = y;
e.tx = e.x;
e.ty = e.y;
e.type = RAND(0,2);
e.alive = true;
enemylist.push_back(e);
return true;
}
// Move the enemies
void move_enemies() {
// Create new enemies if there's less than enemy_amount of them
// (but don't create enemies until all the diamonds from Killed-5 have
// been collected)
int num_enemies = enemylist.size();
if(num_enemies < ENEMY_AMOUNT && !killed_5_diamonds && !level_pause) {
enemy_creation_counter--;
if(enemy_creation_counter < 0) {
bool created = false;
// Add enemies to maintain the certain enemy amount
for(int i=0; i < (ENEMY_AMOUNT - num_enemies); i++) {
// Add a new enemy
int ex, ey;
if(new_enemy(ex, ey)) {
// Create the teleport effect
create_teleport_effect(ex, ey);
created = true;
}
}
// Play the appear sound
if(created) {
play_sound(SND_APPEAR, false);
enemy_creation_counter = enemy_creation_interval;
}
}
}
// Move the active enemies
if(enemylist.size() == 0)
return;
list<ENEMY>::iterator i;
for(i = enemylist.begin(); i != enemylist.end(); ++i) {
(*i).move();
// Remove the dead enemies
if((*i).alive == false) {
i = enemylist.erase(i);
}
}
}
// Draw the enemies
void draw_enemies() {
if(enemylist.size() == 0)
return;
list<ENEMY>::iterator i;
for(i = enemylist.begin(); i != enemylist.end(); ++i) {
(*i).draw();
}
}
// Clear the enemy list
void clear_enemies() {
enemylist.clear();
enemy_creation_counter = 30;
}
// Helper function which computes the right direction
int get_dir(int dx, int dy) {
if(dx == 0 && dy == -1)
return DIR_N;
else if(dx == 1 && dy == 0)
return DIR_E;
else if(dx == 0 && dy == 1)
return DIR_S;
else
return DIR_W;
}
// Look for a player and chase him
void ENEMY::look_player() {
// Movement deltas for each direction
const int dx[4] = { 0, 1, 0, -1 };
const int dy[4] = { -1, 0, 1, 0 };
// Sweep in a straigth line and check for the player presence
for(int pos=1; pos < MAP_W; pos++) {
int xx, yy;
xx = x + dx[dir] * pos;
yy = y + dy[dir] * pos;
// Check for solid tile
if(map_solid(xx, yy))
break;
// Check for the players
if((int)p1.get_real_x() == xx && (int)p1.get_real_y() == yy && p1.alive && !p1.jumping && !(using_special_power == 1 && which_special_power == BLUE_POWER_TELEPORT)) {
// Begin the chase
chase = 1; // 1 for player one
speed += 0.03f;
break;
}
else if(two_players && (int)p2.get_real_x() == xx && (int)p2.get_real_y() == yy && p2.alive && !p2.jumping && !(using_special_power == 2 && which_special_power == BLUE_POWER_TELEPORT)) {
// Begin the chase
chase = 2; // 2 for player two
speed += 0.03f;
break;
}
}
}
// Lightning special power instance from special_power.cpp
extern SP_LIGHTNING sp_lightning;
// Move the enemy
void ENEMY::move() {
// Advance the animation
if(!chase && !burning)
anim += 0.10f;
else
anim += 0.20f;
if((int)anim > 3 || kicked)
anim = 0.0f;
// Advance the dying animation if we're actually dying
if(dying) {
die_anim -= 0.03f;
// Create the blue "burning down" effect
float px = get_real_x();
float py = get_real_y();
for(int f=0; f < RAND(2,10); f++) {
float rnd = RANDF(-0.3f, 0.3f);
VECT pos(px, 2*size - 0.05f - (2.5f*size*(1-die_anim)), py);
pos.x += rnd;
pos.z -= rnd;
if(pos.y < 0.0f)
pos.y = 0.0f;
if(turning)
pos.y += (turning_raise * 0.85f);
VECT dir = 0.0f;
float c1[4] = { 0.1f, 0.7f, 1, 1 };
float c2[4] = { 0.1f, 0.7f, 1, 0 };
add_particle(pos, dir, RAND(20,35), 0.1f, 0.4f, c1, c2, part_star);
}
if(die_anim < 0.0f) {
die_anim = 0.0f;
alive = false;
}
return;
}
// Create some particle fire from the burning enemies
if(burning) {
VECT ppos(get_real_x(), 0.5f, get_real_y());
create_fire(ppos);
}
// Advance the turning animation
if(turning) {
// Raise up
if(turning == 1) {
turning_raise += 0.035f;
if(turning_raise >= 1.0f) {
turning_raise = 1.0f;
turning++;
}
}
// Turn
else if(turning == 2) {
turning_counter++;
if(turning_counter == 5) {
dir = nextdir;
nextdir = dir + 1;
if(nextdir > DIR_W)
nextdir = DIR_N;
}
else if(turning_counter == 10) {
dir = nextdir;
turning++;
}
}
// Go down
else if(turning == 3) {
turning_raise -= 0.035f;
if(turning_raise <= 0.0f) {
turning_raise = 0.0f;
turning = 0;
}
}
// Check the collision between the player #1
if(p1.alive && !p1.jumping) {
float dx = get_real_x() - p1.get_real_x();
float dy = get_real_y() - p1.get_real_y();
if(dx*dx + dy*dy <= 0.9f) {
// Collision happened!
// Kill the player and die
p1.die();
die();
}
}
// Check the collision between the player #2
if(alive && two_players && p2.alive && !p2.jumping) {
float dx = get_real_x() - p2.get_real_x();
float dy = get_real_y() - p2.get_real_y();
if(dx*dx + dy*dy <= 0.9f) {
// Collision happened!
// Kill the player and die
p2.die();
die();
}
}
return;
}
// If there is the lightning special power in progress, don't move the enemies which are
// suffering from the lightning strikes
if(special_power_pause && which_special_power == BLUE_POWER_LIGHTNING) {
// Check if we're a target
for(int f=0; f<ENEMY_AMOUNT; f++) {
if(sp_lightning.targets[f] == this) {
anim += 0.30f;
if((int)anim > 3)
anim = 0.0f;
return;
}
}
}
// Don't move if the level is finished
if(level_pause)
return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -