⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 enemy.cpp

📁 蕃茄炸弹超人[ACT]I ve no Tomatoes 开放原始码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*************************************************************************

                         "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 + -