#include "player.h" #include "dialogs.h" #include "game.h" #include "map.h" #include "config.h" #include "npc.h" #include 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. */ };