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

📄 player.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 "enemy.h"
#include "tilemap.h"
#include "bomb.h"
#include "particle.h"
#include "effects.h"
#include "font.h"
#include "teleport.h"
#include "special_power.h"
#include "soundmusic.h"
#include "comments.h"
#include "select_special.h"
#include "levels.h"
#include "helpers.h"


// This a dirty hack. I use this to modify the tilemap rendering to disable
// the depth writing for the particular block where the player is standing.
// Otherwise the player's feet would be cut off annoyingly. Since I'm modifying
// the tilemap, I can't use the display list when the player is over a block.
// This includes a speed penalty but it can't be helped. Of course I'm using
// the tilemap's display list when the player is not on a block.
int players_on_block_x[2] = { -1, -1 };
int players_on_block_y[2] = { -1, -1 };


// Players
PLAYER p1;
PLAYER p2;

// Player animations
GLuint player1_anim;
static int anim_frames[4] = { 0, 1, 0, 2 };

// Player sprite shadow
GLuint sprite_shadow;

// Player icons for two player mode
GLuint p_icons;
float p_icon_alpha[2] = { 0, 0 };


// Teleport particle from teleport.cpp
extern GLuint part_teleport;


// Moving style defines
#define MOV_RELATIVE		1
#define MOV_ABSOLUTE		2


#ifdef EDITOR
#define using_special_power			100
#define which_special_power			100
#endif



// Load player textures
void load_players() {
	// Load the animation
	player1_anim = load_png("player1.png", true, false, false);

	// Load the shadow
	sprite_shadow = load_png("shadow.png", true, false, true);

	// Load the icons
	p_icons = load_png("picons.png", true, false, false);
}


// Draw the player icons
void draw_player_icons() {
	if(!two_players)
		return;

	float offx = 0, offz = 0;
	float size = 0.5f;

	glDisable(GL_DEPTH_TEST);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	BIND_TEXTURE(p_icons);

	// For player #1
	if(p1.alive && p_icon_alpha[0]) {
		// Calculate the offset
		switch(p1.dir) {
			default:
			case DIR_N: offz = -p1.offset; break;
			case DIR_E: offx = p1.offset; break;
			case DIR_S: offz = p1.offset; break;
			case DIR_W: offx = -p1.offset; break;
		}

		// Translate to the position
		glPushMatrix();
		glTranslatef(p1.x + offx + 0.5f, p1.size - 0.20f, p1.y + offz + 0.5f);
		glTranslatef(0, 1.0f, 0);

		// Take the jumping position in to account
		#ifndef EDITOR
		if(p1.jumping) {
			VECT jpos = 0.0f;
			jpos = p1.jump_dir * p1.jump_pos * p1.jump_dist;
			glTranslatef(jpos.x, jpos.y, jpos.z);
		}
		#endif

		// If we're jumped over a block, raise the icon up
		if(map[p1.x][p1.y][1])
			glTranslatef(0, TILE_H, 0);

		// If we're jumping, translate up to the position
		#ifndef EDITOR
		if(p1.jumping) {
			float jy = p1.jump_height * SIN(180.0f * p1.jump_pos);

			// If we're jumping to a block, make sure we don't "sink" in it
			if(map[p1.jump_tx][p1.jump_ty][1] && jy < TILE_H && p1.jump_pos > 0.5f)
				jy = TILE_H;

			glTranslatef(0, jy, 0);
		}

		// If we're teleporting using the teleport special, raise ourselves up!
		if(using_special_power == 1 && which_special_power == BLUE_POWER_TELEPORT)
			glTranslatef(0, TELEPORT_POWER_HEIGHT * sp_teleport.teleport_pos, 0);
		#endif

		// Negate the camera rotation
		glMultMatrixf(cam_neg_matrix);

		// Draw the sprite
		glColor4f(1,1,1, p_icon_alpha[0]);
		glBegin(GL_TRIANGLE_STRIP);
			glTexCoord2f(0.5f, 1); glVertex3f( size,  size,  size);
			glTexCoord2f(0, 1); glVertex3f(-size,  size,  size);
			glTexCoord2f(0.5f, 0); glVertex3f( size, -size, -size);
			glTexCoord2f(0, 0); glVertex3f(-size, -size, -size);
		glEnd();

		glPopMatrix();
	}


	// For player #2
	if(p2.alive && p_icon_alpha[1]) {
		offz = offx = 0;
		// Calculate the offset
		switch(p2.dir) {
			default:
			case DIR_N: offz = -p2.offset; break;
			case DIR_E: offx = p2.offset; break;
			case DIR_S: offz = p2.offset; break;
			case DIR_W: offx = -p2.offset; break;
		}

		// Translate to the position
		glPushMatrix();
		glTranslatef(p2.x + offx + 0.5f, p2.size - 0.20f, p2.y + offz + 0.5f);
		glTranslatef(0, 1.0f, 0);

		// If the players are sharing a block, make the P2 icon go a bit higher
		if(p1.x == p2.x && p1.y == p2.y)
			glTranslatef(0, 1.0f, 0);

		// Take the jumping position in to account
		#ifndef EDITOR
		if(p2.jumping) {
			VECT jpos = 0.0f;
			jpos = p2.jump_dir * p2.jump_pos * p2.jump_dist;
			glTranslatef(jpos.x, jpos.y, jpos.z);
		}
		#endif

		// If we're jumped over a block, raise the icon up
		if(map[p2.x][p2.y][1])
			glTranslatef(0, TILE_H, 0);

		// If we're jumping, translate up to the position
		#ifndef EDITOR
		if(p2.jumping) {
			float jy = p2.jump_height * SIN(180.0f * p2.jump_pos);

			// If we're jumping to a block, make sure we don't "sink" in it
			if(map[p2.jump_tx][p2.jump_ty][1] && jy < TILE_H && p2.jump_pos > 0.5f)
				jy = TILE_H;

			glTranslatef(0, jy, 0);
		}

		// If we're teleporting using the teleport special, raise ourselves up!
		if(using_special_power == 2 && which_special_power == BLUE_POWER_TELEPORT)
			glTranslatef(0, TELEPORT_POWER_HEIGHT * sp_teleport.teleport_pos, 0);
		#endif

		// Negate the camera rotation
		glMultMatrixf(cam_neg_matrix);

		// Draw the sprite
		glColor4f(1,1,1, p_icon_alpha[1]);
		glBegin(GL_TRIANGLE_STRIP);
			glTexCoord2f(1, 1); glVertex3f( size,  size,  size);
			glTexCoord2f(0.5f, 1); glVertex3f(-size,  size,  size);
			glTexCoord2f(1, 0); glVertex3f( size, -size, -size);
			glTexCoord2f(0.5f, 0); glVertex3f(-size, -size, -size);
		glEnd();

		glPopMatrix();
	}


	glEnable(GL_DEPTH_TEST);
}


// Show the player icon for 'who'
void show_icon(int who) {
	p_icon_alpha[who] = 1.0f;
}


// Helper function which returns a random block around a
// non-block position
void get_random_block_at(int x, int y, int &bx, int &by) {
	int dx = RAND(-1,1);
	int dy = RAND(-1,1);
	int counter = 0;
	while((!map_solid(x+dx, y+dy) || (x+dx < 0 || y+dy < 0 || x+dx > MAP_W-1 || y+dy > MAP_H-1)
			|| (x+dx == x && y+dy == y)) && counter < 10000) {
		dx = RAND(-1,1);
		dy = RAND(-1,1);
	}

	bx = x + dx;
	by = y + dy;
}


// Helper function which returns a respawn position
void get_respawn_position(int x, int y, int &rx, int &ry) {

	int ox, oy;
	bool ok = false;
	while(!ok) {
		get_random_block_at(x, y, ox, oy);
		int count = 0;
		if(!map_solid(ox+1, oy))
			count++;
		if(!map_solid(ox-1, oy))
			count++;
		if(!map_solid(ox, oy+1))
			count++;
		if(!map_solid(ox, oy-1))
			count++;

		if(count)
			ok = true;
	}

	rx = ox;
	ry = oy;
}




// Move the player
void PLAYER::move() {
#ifndef EDITOR
	int who = (this == &p1) ? 1 : 2;
	int who2 = who-1; 	// Used for array indices

	// Reduce the icon alpha
	if(p_icon_alpha[who2]) {
		p_icon_alpha[who2] -= 0.005f;
		if(p_icon_alpha[who2] < 0.0f)
			p_icon_alpha[who2] = 0.0f;
	}

	// If we're dead, reduce the death counter and respawn
	if(!alive) {
		death_counter--;
		if(death_counter == 0) {
			// Respawn to a block
			int ox, oy;
			get_respawn_position((int)get_real_x(), (int)get_real_y(), ox, oy);

			int odir = dir;
			//clear();
			alive = true;
			x = ox;
			y = oy;
			dir = odir;
			nextdir = dir;
			tx = x;
			ty = y;
			walking = false;
			jumping = false;
			dying = false;
			offset = 0.0f;
			create_teleport_effect(x, y);
			show_icon(who2);

			// Play the appear sound
			play_sound(SND_APPEAR, false);

		}
		return;
	}

	// 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;
			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;

			// Explode the player bombs
			if(num_bombs > 0) {
				list<BOMB>::iterator b;
				for(b = bomblist.begin(); b != bomblist.end(); ++b)
					if((*b).owner == who && (*b).time > 1)
						(*b).time = 1;		// Makes the bomb explode on the next cycle
			}
		}

		return;
	}


	// Jumping stuff
	if(jumping) {
		jump_pos += jump_speed;
		if(jump_pos >= 1.0f) {
			jump_pos = 1.0f;

			// We're now on the target tile
			x = jump_tx;
			y = jump_ty;
			tx = x;
			ty = y;
			offset = 0.0f;
			jumping = false;
		}

		// Create some particles if we're teleporting
		if(in_teleport && jumping) {
			VECT pos(get_real_x(), 0.25f, get_real_y());
			pos += jump_dir * jump_pos * jump_dist;
			pos.y += jump_height * SIN(180.0f * jump_pos);

			VECT dir;
			for(int f=0; f<5; f++) {
				VECT ppos = pos + VECT(RANDF(-0.5f,0.5f),RANDF(-0.5f,0.5f),RANDF(-0.5f,0.5f));
				dir.x = dir.y = dir.z = 0.0f;
				float c1[4] = { 0.3, 0.7f, 1, 1 };
				float c2[4] = { 0, 0, 1, 0 };

				add_particle(ppos, dir, RAND(10,30), 0.1f, 0.3f, c1, c2, part_teleport);
			}
		}


		// This is a dirty hack. Read the comments from the beginning of this file.
		if(map[jump_tx][jump_ty][1] && jump_pos > 0.9f) {
			players_on_block_x[who2] = jump_tx;
			players_on_block_y[who2] = jump_ty;
		}

		return;
	}

	// This is a dirty hack. Read the comments from the beginning of this file.
	if(map[x][y][1]) {
		players_on_block_x[who2] = x;
		players_on_block_y[who2] = y;
		//return;
	}
	else {
		players_on_block_x[who2] = -1;
	}

	// Don't move if we're using the napalm or the teleport power
	if(using_special_power && (which_special_power == RED_POWER_NAPALM))
		return;
	if(using_special_power == who && (which_special_power == BLUE_POWER_TELEPORT))
		return;

	// Don't move if the level is finished
	if(level_pause)
		return;


	// Advance the animation
	anim += 0.20f;
	if((int)anim > 3)
		anim = 0.0f;

	// Advance the turning animation
	if(turning) {
		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 = false;
		}
	}


	if(!walking && ((config.moving_style[who2] == MOV_RELATIVE && !key[config.key_up[who2]]) || (config.moving_style[who2] == MOV_ABSOLUTE && !key[config.key_up[who2]] && !key[config.key_down[who2]] && !key[config.key_left[who2]] && !key[config.key_right[who2]])))
		anim = 0.0f;

	// Check if we're on a block
	bool on_block = false;
	if(map_solid(x,y))
		on_block = true;

	// Don't move if we're using the flower power (absolute)
	if(on_block && config.moving_style[who2] == MOV_ABSOLUTE && (p1.num_flower_bombs > 0 || p2.num_flower_bombs > 0))
		return;


	// Check for turning input
	if(key[config.key_left[who2]]) {
		if(config.moving_style[who2] == MOV_RELATIVE) {
			// Relative moving
			if(!turn_key_down[0] && !turning) {
				// Turn left
				nextdir = dir - 1;
				if(nextdir < DIR_N)
					nextdir = DIR_W;

				if(!walking)
					dir = nextdir;

				turn_key_down[0] = true;
			}
		}
		else if(config.moving_style[who2] == MOV_ABSOLUTE && !walking) {
			// Absolute moving
			dir = DIR_W;
			walking = true;
			offset = 0.0f;

			tx = x - 1;
			ty = y;

			// Check if the target is passable?
			if(map_solid(tx, ty)) {
				tx = x;
				ty = y;
				walking = false;
			}

			if(on_block) {
				// We're on a block, jump down from it
				jump(tx, ty, 2.0f, 0.05f);
				tx = x;
				ty = y;
				anim = 0;
				on_block = true;

				// Play the jumping sound
				if(jumping)
					play_sound(SND_JUMP, false);
			}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -