diff --git a/src/npc.c b/src/npc.c index 12dd57b..40ea8ad 100644 --- a/src/npc.c +++ b/src/npc.c @@ -34,7 +34,7 @@ float length( float x, float y ) int npc_clear_path(NPC *npc) { npc->currentPoint = 0; - npc->hasPath = 1; + npc->hasPath = 0; npc->path_length = 0; free(npc->xpath); free(npc->ypath); @@ -46,10 +46,10 @@ int npc_clear_path(NPC *npc) int npc_append_path(uint16_t x, uint16_t y, NPC *npc) { - npc->path_length++; - npc->xpath = realloc(npc->xpath, npc->path_length*2); - npc->ypath = realloc(npc->ypath, npc->path_length*2); + npc->xpath = realloc(npc->xpath, npc->path_length*2+2); + npc->ypath = realloc(npc->ypath, npc->path_length*2+2); if(npc->xpath == NULL || npc->ypath == NULL) return 1; + npc->path_length++; npc->xpath[npc->path_length-1] = x - npc->x; npc->ypath[npc->path_length-1] = y - npc->y; return 0; @@ -73,12 +73,14 @@ int as_reconstruct_path(int16_t *came_from, int w, int h, int16_t spos, for(i = 0; i < 64; i++) { - if(next == -1) goto as_recons_fail; - if(npc_append_path(next%w, next/h, npc)) goto as_recons_fail; + if(npc_append_path((next%w)*T_WIDTH,(next/h)*T_HEIGHT, npc)) + { + goto as_recons_fail; + } next = came_from[next]; if(next == spos){ - if(npc_append_path(spos%w, spos/h, npc)) + if(npc_append_path((spos%w)*T_WIDTH,(spos/h)*T_HEIGHT, npc)) goto as_recons_fail; break; } @@ -88,18 +90,20 @@ int as_reconstruct_path(int16_t *came_from, int w, int h, int16_t spos, //Flip the path because it started from the end - for(i = 1; i < npc->path_length/2; i++) + for(i = 0; i < npc->path_length/2; i++) { tx = npc->xpath[i]; ty = npc->ypath[i]; - npc->xpath[i] = npc->xpath[npc->path_length-i]; - npc->ypath[i] = npc->ypath[npc->path_length-i]; - npc->ypath[npc->path_length-i] = tx; - npc->ypath[npc->path_length-i] = ty; + npc->xpath[i] = npc->xpath[npc->path_length-i-1]; + npc->ypath[i] = npc->ypath[npc->path_length-i-1]; + npc->ypath[npc->path_length-i-1] = tx; + npc->ypath[npc->path_length-i-1] = ty; } free(came_from); + npc->hasPath = true; + return 0; as_recons_fail: @@ -112,16 +116,21 @@ int as_reconstruct_path(int16_t *came_from, int w, int h, int16_t spos, //Returns non zero error code on failure //Custom a* implemetation //Unoptimized, may become an issue -int npc_pathfind(uint32_t dest_x, uint32_t dest_y, Map *full_map, NPC *npc) +int npc_pathfind(int32_t dest_x, int32_t dest_y, Map *full_map, NPC *npc) { - uint32_t i, j; + int32_t i, j; + + int32_t w = full_map->w; + int32_t h = full_map->h; + int32_t x = floor(npc->curx)/T_WIDTH; + int32_t y = floor(npc->cury)/T_HEIGHT; + dest_x /= T_WIDTH; + dest_y /= T_HEIGHT; + int32_t spos = y*w+x; - uint32_t w = full_map->w; - uint32_t h = full_map->h; - uint32_t x = floor(npc->curx); - uint32_t y = floor(npc->cury); - uint32_t spos = y*w+x; uint8_t *map = full_map->walkable; + + if(dest_x < 0 || dest_x > w || dest_y < 0 || dest_x > h) return 2; if(map[spos]) return 2; if(map[dest_y*w+dest_x]) return 2; @@ -134,26 +143,26 @@ int npc_pathfind(uint32_t dest_x, uint32_t dest_y, Map *full_map, NPC *npc) int16_t *came_from = malloc(w*h*2); for(i=0; i bscore) continue; bx = i%w; by = i/w; @@ -162,7 +171,8 @@ int npc_pathfind(uint32_t dest_x, uint32_t dest_y, Map *full_map, NPC *npc) if(bx == dest_x && by == dest_y) { as_clean(visited, gscore, fscore); - return as_reconstruct_path(came_from, w, h, spos, dest_y*w+dest_x, npc); + return as_reconstruct_path(came_from, w, h, spos, + dest_y*w+dest_x, npc); } visited[by*w+bx] = 1; @@ -174,14 +184,16 @@ int npc_pathfind(uint32_t dest_x, uint32_t dest_y, Map *full_map, NPC *npc) if(i > w) break; for(j = by-1; j < by+2; j++) { - if(j > h ) break; - if(map[j*w+i]) continue; - att_score = gscore[by*w+bx] + ceil(length(bx-i,by-j)); + if(j > h) break; + if(map[j*w+i] == 1) continue; + if(i == bx && j == by) continue; + att_score = gscore[by*w+bx] + round(length(bx-i,by-j)); if(att_score < gscore[j*w+i]) { came_from[j*w+i] = by*w+bx; gscore[j*w+i] = att_score; - fscore[j*w+i] = att_score + ceil(length(dest_x-i, dest_y-j)); + fscore[j*w+i] = att_score + round( + length(dest_x-i, dest_y-j)); if(visited[j*w+i]) visited[j*w+i] = 0; } } @@ -194,11 +206,34 @@ int npc_pathfind(uint32_t dest_x, uint32_t dest_y, Map *full_map, NPC *npc) return 3; } +NPC *npc_create() +{ + //Use temp pointer to avoid breaking the whole npcRPG on failure + void *temp = realloc(npcRPG, (nbNPC+1)*sizeof(NPC)); + if(temp == NULL) return NULL; + npcRPG = temp; + nbNPC++; + NPC *npc = &npcRPG[nbNPC-1]; + npc->xpath = malloc(2); + npc->ypath = malloc(2); + return npc; +} + +void npc_remove(NPC *npc) +{ + uint32_t pos = ((uint32_t)npc - (uint32_t)npcRPG)/sizeof(NPC); + if(pos > nbNPC-1) return; + if(pos == nbNPC-1) + { + nbNPC--; + return; + } + memmove(npc, &npc[1], (nbNPC-pos-1)*sizeof(NPC)); +} + //Refactoring to make adding complexity cleaner void update_npcs([[maybe_unused]] Game *game) { - //npc_pathfind(game->player.x, game->player.y, game->map_level, &npcRPG[0]); - for( uint32_t u=0; uhasPath && npc->paused==true) return; + /* if the NPC has no path or is paused, skip it */ + if (!npc->hasPath || npc->paused==true) return; float vecX = (float) (npc->xpath[ npc->currentPoint ] + npc->x) - npc->curx; @@ -232,7 +267,6 @@ void update_npc(NPC *npc) } -//TODO ; Add malloc() failure case void reload_npc(Game *game) { if (npcRPG!=NULL) @@ -256,6 +290,7 @@ void reload_npc(Game *game) } npcRPG = (NPC*) malloc( nbNPC * sizeof(NPC) ); + if(npcRPG == NULL) return; int currentNPC=0; for (uint32_t u=0; umap_level->nbextradata; u++) diff --git a/src/npc.h b/src/npc.h index d284ae8..f47369d 100644 --- a/src/npc.h +++ b/src/npc.h @@ -38,12 +38,14 @@ typedef struct int16_t *xpath; int16_t *ypath; + int type; + + int8_t current_group; int8_t hostile_to_group; - - /* is the current NPC in pause (during dialog) */ bool paused; + } NPC; //Frees then malloc()s a new path to npc @@ -57,7 +59,14 @@ int npc_append_path(uint16_t x, uint16_t y, NPC *npc); //Clears the NPCs path and creates a new one going to dest, //avoiding non-walkable tiles //Returns non-zero on failure -int npc_pathfind(uint32_t dest_x, uint32_t dest_y, Map *full_map, NPC *npc); +int npc_pathfind(int32_t dest_x, int32_t dest_y, Map *full_map, NPC *npc); + +//realloc()s npcRPG to adequate size and returns a pointer to the new element +//Returns NULL on failure +NPC *npc_create(); + +//Pops the NPC from npcRPG +void npc_remove(NPC *npc); /* Draws the player player. This function should be called after drawing the * map! */