Collab_RPG/src/player.c

267 lines
8.3 KiB
C

#include "player.h"
#include "dialogs.h"
#include "game.h"
#include "map.h"
#include "config.h"
#include "npc.h"
#include <gint/display.h>
const char one_px_mov[8] = {
0, -1, /* Up */
0, 1, /* Down */
-1, 0, /* Left */
1, 0 /* Right */
};
/* TODO: Search for all hard tiles in the tileset. hard_tiles is a list of their
* IDs */
/* The speed of the player on the diffrent tiles in the walkable layer. */
#define WALKABLE_TILE_MAX 4
const short int walkable_speed[WALKABLE_TILE_MAX] = {
SPEED, 0, PXSIZE, PXSIZE
};
/* How much damage the player takes on the diffrent tiles in the walkable
* layer. */
const char damage_taken_walkable[WALKABLE_TILE_MAX] = {
0, 0, 5, 0
};
extern bopti_image_t demo_player_img;
extern NPC *npcRPG;
extern uint32_t nbNPC;
void player_draw(Game *game) {
Player *player = &game->player;
dimage(player->px-P_WIDTH/2, player->py-P_HEIGHT/2, &demo_player_img);
}
void player_move(Game *game, Direction direction) {
Player *player = &game->player;
/* How this player movement will modify the player x and y. */
char dx, dy;
/* If the player will collide with a hard tile or if the will go outside of
* the map. */
if(player_collision(game, direction, P_CENTER)){
/* If the will collide with the center of the player. */
dx = one_px_mov[direction*2]*player->speed;
dy = one_px_mov[direction*2+1]*player->speed;
player_fix_position(game, dx, dy);
}
else{
if(player_collision(game, direction, P_RIGHTDOWN) ||
player_collision(game, direction, P_LEFTUP)){
/* If the will collide with the edges of the player. */
/* I fix his position so he won't be partially in the tile. */
/* I invert dx and dy to fix the axis where he is not moving on. */
/* Do not replace dx==0 with !dx or dy==0 with !dy, it won't work!
*/
dx = one_px_mov[direction*2]*player->speed;
dy = one_px_mov[direction*2+1]*player->speed;
player_fix_position(game, dx==0, dy==0);
}
/* If he won't collide with the center, so I just move him normally */
dx = one_px_mov[direction*2]*player->speed;
dy = one_px_mov[direction*2+1]*player->speed;
player->x += dx;
player->y += dy;
}
player->wx = game->map_level->xmin * PXSIZE + player->x;
player->wy = game->map_level->ymin * PXSIZE + player->y;
}
extern bopti_image_t demo_player_img;
extern bopti_image_t NPC_Icon_img;
extern bopti_image_t SGN_Icon_img;
extern bopti_image_t INFO_Icon_img;
void player_action(Game *game) {
if( game->player.isDoingAction ) return; /* alreday doing something (action IS NOT with an NPC ) */
if( game->player.canDoSomething && !game->player.isInteractingWithNPC ) /* we can do something */
{
/* we indicate that the player is occupied */
game->player.isDoingAction = true;
ExtraData *currentData = &game->map_level->extradata[game->player.whichAction];
/* we use the correct image as per the class of the item */
bopti_image_t *face;
/* we use the correct image as per the class of the item */
if (strcmp("INFO", currentData->type)==0)
face = &INFO_Icon_img;
//else if (strcmp("NPC", currentData->type)==0)
// face = &NPC_Icon_img;
else if (strcmp("SGN", currentData->type)==0)
face = &SGN_Icon_img;
else face = &demo_player_img;
uint32_t dialogStart = currentData->dialogID;
initiate_dialog_sequence( game, face, dialogStart );
/* when done we release the occupied status of the player */
game->player.isDoingAction = false;
}
else if( game->player.canDoSomething && game->player.isInteractingWithNPC ) /* we can do something (action IS with an NPC ) */
{
/* we indicate that the player is occupied */
game->player.isDoingAction = true;
NPC *currentNPC = &npcRPG[game->player.whichAction];
/* we use the correct image as per the class of the item */
bopti_image_t *face = &NPC_Icon_img;
uint32_t dialogStart = currentNPC->dialogID;
/* we setr this NPC to paused to avoid changing its position while talking (the rest of the NPCs pursue their action)*/
currentNPC->paused = true;
initiate_dialog_sequence( game, face, dialogStart );
/* when done we release the occupied status of the player */
game->player.isDoingAction = false;
currentNPC->paused = false;
}
}
bool player_collision(Game *game, Direction direction,
Checkpos nomov_axis_check) {
Player *player = &game->player;
/* Where is the tile where he will go to from his position. */
char dx = one_px_mov[direction*2];
char dy = one_px_mov[direction*2+1];
if(!dx){
dx += nomov_axis_check;
}else if(!dy){
dy += nomov_axis_check;
}
dx = dx*(P_WIDTH/2+1);
dy = dy*(P_HEIGHT/2+1);
/* The tile he will go to. */
int player_tile_x = player->x+dx;
int player_tile_y = player->y+dy;
/* check where the player is expected to go on the next move */
/* if outside the map, we check if there is a map on the other */
/* side of the current map*/
if (get_walkable(game, player_tile_x, player_tile_y) == MAP_OUTSIDE)
{
// we compute the expected world coordinates accordingly
// while taking care of the scaling between fx and cg models (PXSIZE)
int worldX = (player->wx+dx) / PXSIZE;
int worldY = (player->wy+dy) / PXSIZE;
Map *map = get_map_for_coordinates(game, worldX, worldY );
if (map!=NULL && map!=game->map_level)
{
Map *backupmap = game->map_level;
int backupx = player->x;
int backupy = player->y;
int backupwx = player->wx;
int backupwy = player->wy;
game->map_level = map;
player->wx = worldX * PXSIZE;
player->wy = worldY * PXSIZE;
player->x = (worldX - map->xmin ) * PXSIZE;
player->y = (worldY - map->ymin ) * PXSIZE;
int on_walkable = get_walkable(game, player->x/T_WIDTH,
player->y/T_HEIGHT);
int speed = (on_walkable >= 0 && on_walkable < WALKABLE_TILE_MAX) ?
walkable_speed[on_walkable] : 0;
/* if he's on a hard tile and we need to revert the changes as */
/* tile on the next side of the border is not walkable */
if(!speed){
game->map_level = backupmap;
player->x = backupx;
player->y = backupy;
player->wx = backupwx;
player->wy = backupwy;
return true; /* He will collide with it. */
}
/* we update the list of NPCs in the current map */
/* to follow the trajectories */
reload_npc( game );
return false;
}
}
/* Handle a negative position differently than a positive one. */
if(player_tile_x < 0) player_tile_x = player_tile_x/T_WIDTH-1;
else player_tile_x = player_tile_x/T_WIDTH;
if(player_tile_y < 0) player_tile_y = player_tile_y/T_HEIGHT-1;
else player_tile_y = player_tile_y/T_HEIGHT;
int on_walkable = get_walkable(game, player_tile_x, player_tile_y);
int speed = (on_walkable >= 0 && on_walkable < WALKABLE_TILE_MAX) ?
walkable_speed[on_walkable] : 0;
/* if he's on a hard tile */
if(!speed){
return true; /* He will collide with it. */
}
player->speed = speed;
return false; /* He won't collide with a hard tile. */
}
void player_fix_position(Game *game, bool fix_x, bool fix_y) {
Player *player = &game->player;
/* I fix his poition on x or/and on y if y need to, so that he won't be over
* the hard tile that he collided with. */
if(fix_x) player->x = player->x/T_WIDTH*T_WIDTH+P_WIDTH/2;
if(fix_y) player->y = player->y/T_HEIGHT*T_HEIGHT+P_HEIGHT/2;
}
void player_damage(Game *game, int amount) {
Player *player = &game->player;
player->life-=amount;
/* TODO: Let the player dye if life < 1. */
};