#include "npc.h" #include "tile.h" #include "stubs.h" // for interface #include "game.h" // for current_map /**** npcThink Catch-all function for processing each NPC's think operations - these operations include decision making and the attempt to act on that decision. Arguments: struct Tile *npc Returns: void ****/ void npcThink(struct Tile *npc) { struct NpcTile *npc_data = npc->data; struct Tile *target; switch (npc_data->behavior) { case BEHAVE_AGGRESSIVE: if (!npc_data->target) { // find a player if ((target = npcFindTile(npc, PLAYER))) { interfacePrint("The nupi, fueled by bloodlust, shrieks in rage"); npc_data->target = target; } } else { npcMoveToTarget(npc, npc_data); } break; case BEHAVE_WANDER: npcMoveRandom(npc); break; } } /**** npcMoveToTarget Called from npcThink, this function attempts to move the given NPC to its target's location. Arguments: struct Tile *npc, struct NpcTile *npc_tile Returns: void TODO: should return the change in x/y. It is redundant to pass NpcTile as well, but since parent operations hold that info as well, it makes some sense to pass it as well - not sure if this should be changed. ****/ void npcMoveToTarget(struct Tile *npc, struct NpcTile *npc_data) { int current_x = npc->x; int current_y = npc->y; struct Tile *target_tile; target_tile = npc_data->target; if (target_tile) { if (npc->x < target_tile->x) { current_x++; } else if (npc->x > target_tile->x) { current_x--; } if (npc->y < target_tile->y) { current_y++; } else if (npc->y > target_tile->y) { current_y--; } if (!gameCollision(current_x, current_y)) { gameMoveTile(npc, current_x, current_y); } } } /**** npcMoveRandom Simply moves the given NPC in a random direction Arguments: struct Tile *npc Returns: void ****/ void npcMoveRandom(struct Tile *npc) { int target_x = npc->x + (roll(0, 2)-1); int target_y = npc->y + (roll(0, 2)-1); if (!gameCollision(target_x, target_y)) { gameMoveTile(npc, target_x, target_y); } } /**** npcFindTile Dumb function that blindly iterates through a square around the NPC until a Tile of tile_type(PLAYER, ITEM, etc.) is (hopefully) found. Upon being found, returns the found Tile. Arguments: struct Tile *npc, int tile_type Returns: struct Tile* TODO: This function should be removed and re-implemented in map.c as a generic findTile function that takes start x, start y, width, height (or radius?), and the target tile type. TODO: Also should have a version that takes a Tile struct as the target instead of a type id. ****/ struct Tile *npcFindTile(struct Tile *npc, int tile_type) { struct Tile *final_target; struct NpcTile *npc_data = npc->data; struct Tile *current_tile; int step_x = npc->x - npc_data->vision; int step_y = npc->y - npc_data->vision; int end_x = npc->x + npc_data->vision; int end_y = npc->y + npc_data->vision; int found_x = 0; int found_y = 0; while (step_x < end_x) { step_y = npc->y - (npc_data->vision); while (step_y < end_y) { if (step_x >= 0 && step_y >= 0 && step_x < current_map->width && step_y < current_map->height) { current_tile = ¤t_map->matrix[step_x][step_y]; while (current_tile) { if (current_tile->tid == tile_type) { if ( ( (npc->x-step_x) + (npc->y-step_y)) < (npc->x-found_x + npc->y-found_y) ) { found_x = step_x; found_y = step_y; final_target = current_tile; } } current_tile = current_tile->next; } } step_y++; } step_x++; } return final_target; }