#include "player.h" #include "config.h" #include "dialogs.h" #include "game.h" #include "map.h" #include "npc.h" #include extern bopti_image_t player_male_img; extern bopti_image_t player_female_img; extern bopti_image_t npc_male; extern bopti_image_t npc_female; extern bopti_image_t npc_milkman; extern bopti_image_t npc_police; extern bopti_image_t SGN_Icon_img; extern bopti_image_t INFO_Icon_img; const bopti_image_t *faces[FACES] = {&npc_male, &npc_female, &npc_milkman, &npc_police}; 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, player->is_male ? &player_male_img : &player_female_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; } /* Check if we should change map */ Map *target = map_get_for_tile(game, game->map_level->x + player->x / T_WIDTH + one_px_mov[direction * 2], game->map_level->y + player->y / T_HEIGHT + one_px_mov[direction * 2 + 1]); if(target != game->map_level) { if(target->x > game->map_level->x) { player->x = 0; } if(target->x < game->map_level->x) { player->x = target->w * T_WIDTH; } if(target->y > game->map_level->y) { player->y = 0; } if(target->y < game->map_level->y) { player->y = target->h * T_HEIGHT; } npc_reload(game); game->map_level = target; } } void player_action(Game *game) { /* already doing something, or can't do anything*/ if(game->player.isDoingAction || !game->player.canDoSomething) return; if(!game->player.isInteractingWithNPC) { /* we can do something */ /* we indicate that the player is occupied */ game->player.isDoingAction = true; Sign *sign = &game->map_level->signs[game->player.whichAction]; bopti_image_t *face; /* we use the correct image as per the type of the item */ if(sign->icon) face = &INFO_Icon_img; else face = &SGN_Icon_img; uint32_t dialogStart = sign->dialogID; dialogs_initiate_sequence(game, face, dialogStart); /* when done we release the occupied status of the player */ game->player.isDoingAction = false; } else { /* we can do something (action IS with an NPC) */ /* we indicate that the player is occupied */ game->player.isDoingAction = true; NPC *currentNPC = &game->map_level->npcs[game->player.whichAction]; /* we use the correct image as per the class of the item */ bopti_image_t *face = &npc_male; /* It's a NPC */ face = (bopti_image_t *)faces[currentNPC->face]; uint32_t dialogStart = currentNPC->dialogID; /* we set this NPC to paused to avoid changing its position while * talking (the rest of the NPCs pursue their action) */ currentNPC->paused = true; dialogs_initiate_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; /* 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 = map_get_walkable(game, player_tile_x, player_tile_y); int speed = (on_walkable >= 0 && on_walkable < WALKABLE_TILE_MAX) ? walkable_speed[on_walkable] : 0; // speed = SPEED; /* 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. */ };