void list_swap(t_list *list, int idx_first, int idx_second) { if (idx_first < list->size && idx_second < list->size && idx_first != idx_second && idx_second >= 0 && idx_first >= 0) { swap_value(get_node_at(list, idx_first), get_node_at(list, idx_second)); } }
internal grid_node* get_random_walkable_node(Grid *grid) { grid_node *result; do { result = get_node_at(grid, rand_int(grid->width), rand_int(grid->height), rand_int(grid->depth)); } while (!result->walkable); return result; }
void list_remove(linked_list list, const int index){ struct list_node* n; // The node to remove // Handle head case if(index == 0 && list->size > 0){ n = list->head; list->head = list->head->next; } else { n = get_node_at(list, index-1); // Handle tail case if(index == list->size - 1){ list->tail = n; n = list->tail->next; list->tail->next = NULL; } else { // Handle normal case, link previous with following node struct list_node* to_remove = n->next; n->next = to_remove->next; n = to_remove; } } // Custom free if(list->fun != NULL) list->fun(n->elem); // Free node and its element free(n->elem); free(n); // Decrease size list->size--; }
internal grid_node* get_neighboring_walkable_node(Grid *grid, int x, int y, int z){ grid_node *result = NULL; for (int h = -1; h<2; h++) { for (int v = -1; v <2; v++) { result = get_node_at(grid, x+h, y+v, z); if (result->walkable) { return result; } } } return result; }
extern void game_update_and_render(Memory* memory, RenderState *renderer, float last_frame_time_seconds, const u8 *keys, SDL_Event e) { UNUSED(keys); UNUSED(e); ASSERT(sizeof(PermanentState) <= memory->permanent_size); PermanentState *permanent = (PermanentState *)memory->permanent; ASSERT(sizeof(ScratchState) <= memory->scratch_size); ScratchState *scratch = (ScratchState *)memory->scratch; ASSERT(sizeof(DebugState) <= memory->debug_size); DebugState *debug = (DebugState *)memory->debug; ASSERT(sizeof(Node16Arena) <= memory->node16_size); Node16Arena *node16 = (Node16Arena *)memory->node16; ASSERT(sizeof(Node16) == sizeof(Node16*)*2 + 16); ASSERT(sizeof(FoundPathNode) == sizeof(BarNode)); if (memory->is_initialized == false) { initialize_memory(permanent, node16, renderer, memory); } // dynamic blocks for (u32 i = 0; i < permanent->dynamic_block_count; i++) { if ( permanent->dynamic_blocks[i].total_frames > 1) { permanent->dynamic_blocks[i].frame_duration_left += last_frame_time_seconds; if (permanent->dynamic_blocks[i].frame_duration_left >= permanent->dynamic_blocks[i].duration_per_frame) { int frame_index = permanent->dynamic_blocks[i].current_frame; if (permanent->dynamic_blocks[i].plays_forward == 1) { frame_index +=1; if (frame_index > permanent->dynamic_blocks[i].last_frame) frame_index = permanent->dynamic_blocks[i].first_frame; } else { frame_index -= 1; if (frame_index < permanent->dynamic_blocks[i].first_frame) frame_index = permanent->dynamic_blocks[i].last_frame; } permanent->dynamic_blocks[i].current_frame = frame_index; permanent->dynamic_blocks[i].frame_duration_left = 0; SimpleFrame f = generated_frames[frame_index]; permanent->dynamic_blocks[i].frame.x_pos = f.frameX; permanent->dynamic_blocks[i].frame.y_pos = f.frameY; permanent->dynamic_blocks[i].frame.width = f.frameW; permanent->dynamic_blocks[i].frame.height = f.frameH; permanent->dynamic_blocks[i].frame.y_internal_off = f.ssH - (f.sssY + f.frameH); permanent->dynamic_blocks[i].frame.x_internal_off = f.ssW - (f.sssX + f.frameW); } } } permanent->colored_line_count = 0; #if 1 { permanent->colored_line_count = 0; for (u32 i = 0; i < permanent->actor_count; i++) { if (permanent->paths[i].Sentinel->Next != permanent->paths[i].Sentinel) { float distance = Vector3Distance(permanent->steer_data[i].location, permanent->paths[i].Sentinel->Next->path.node); if (distance < 5.f){ Node16 *First = permanent->paths[i].Sentinel->Next; permanent->paths[i].Sentinel->Next = First->Next; First->Next = node16->Free->Next; node16->Free->Next = First; First->Prev = node16->Free; } } BEGIN_PERFORMANCE_COUNTER(actors_steering); { Vector3 seek_force = seek_return(&permanent->steer_data[i], permanent->paths[i].Sentinel->Next->path.node); seek_force = Vector3MultiplyScalar(seek_force, 1); actor_apply_force(&permanent->steer_data[i], seek_force); permanent->steer_data[i].velocity = Vector3Add(permanent->steer_data[i].velocity, permanent->steer_data[i].acceleration); permanent->steer_data[i].velocity = Vector3Limit(permanent->steer_data[i].velocity, permanent->steer_data[i].max_speed); permanent->steer_data[i].location = Vector3Add(permanent->steer_data[i].location, Vector3MultiplyScalar(permanent->steer_data[i].velocity, last_frame_time_seconds)); permanent->steer_data[i].acceleration = Vector3MultiplyScalar(permanent->steer_data[i].acceleration, 0); // left = frame 0, down = frame 1 right = frame 2,up = frame 3 double angle = (180.0 / PI) * atan2(permanent->steer_data[i].velocity.x, permanent->steer_data[i].velocity.y); angle = angle + 180; if (angle > 315 || angle < 45) { permanent->anim_data[i].frame = 10; //11 } else if (angle >= 45 && angle <= 135) { permanent->anim_data[i].frame = 4;// 5 } else if (angle >=135 && angle <= 225) { permanent->anim_data[i].frame = 6; //7 } else if (angle > 225 && angle <= 315) { permanent->anim_data[i].frame = 8; //9 } permanent->anim_data[i].frame_duration_left += last_frame_time_seconds; if (permanent->anim_data[i].frame_duration_left > 0.1f) { permanent->anim_data[i].frame += 1; } if (permanent->anim_data[i].frame_duration_left > 0.2f) { permanent->anim_data[i].frame_duration_left = 0; } END_PERFORMANCE_COUNTER(actors_steering); } #if 1 if (permanent->paths[i].Sentinel->Next != permanent->paths[i].Sentinel) { Node16 * d= permanent->paths[i].Sentinel->Next; u32 c = permanent->colored_line_count; while (d->Next != permanent->paths[i].Sentinel){ //if (d->path.node.z != d->Next->path.node.z) { // printf("going from %f,%f,[%f] to %f,%f,[%f]\n", d->path.node.x, d->path.node.y, d->path.node.z, d->Next->path.node.x, d->Next->path.node.y, d->Next->path.node.z); //} permanent->colored_lines[c].x1 = getRotatedXFloat(d->path.node.x, d->path.node.y, facing_side, permanent->dims); permanent->colored_lines[c].y1 = getRotatedYFloat(d->path.node.x, d->path.node.y, facing_side, permanent->dims); permanent->colored_lines[c].z1 = d->path.node.z; permanent->colored_lines[c].x2 = getRotatedXFloat(d->Next->path.node.x, d->Next->path.node.y, facing_side, permanent->dims); permanent->colored_lines[c].y2 = getRotatedYFloat(d->Next->path.node.x, d->Next->path.node.y, facing_side, permanent->dims); permanent->colored_lines[c].z2 = d->Next->path.node.z; permanent->colored_lines[c].r = 0.0f; permanent->colored_lines[c].g = 0.0f; permanent->colored_lines[c].b = 0.0f; d = d->Next; c++; } permanent->colored_line_count = c; } #endif ASSERT( permanent->colored_line_count < LINE_BATCH_COUNT * MAX_IN_BUFFER) if (permanent->paths[i].Sentinel->Next != permanent->paths[i].Sentinel) { continue; } BEGIN_PERFORMANCE_COUNTER(mass_pathfinding); TempMemory temp_mem = begin_temporary_memory(&scratch->arena); grid_node * Start = get_node_at(permanent->grid, permanent->steer_data[i].location.x/permanent->block_size.x, permanent->steer_data[i].location.y/permanent->block_size.y, (permanent->steer_data[i].location.z + 10)/permanent->block_size.z_level); if (Start->walkable) { } else { Start = get_neighboring_walkable_node(permanent->grid, Start->X, Start->Y, Start->Z); if (!Start->walkable) { Start = get_random_walkable_node(permanent->grid); } } grid_node * End = get_random_walkable_node(permanent->grid); ASSERT(Start->walkable); ASSERT(End->walkable); path_list * PathRaw = find_path(Start, End, permanent->grid, &scratch->arena); path_list *Path = NULL; if (PathRaw) { //Path = smooth_path(PathRaw, &scratch->arena, permanent->grid); Path = PathRaw; if (Path) { path_node * done= Path->Sentinel->Prev; while (done != Path->Sentinel) { Node16 *N = NULL; if ( node16->Free->Next != node16->Free) { N = node16->Free->Next; node16->Free->Next = N->Next; node16->Free->Next->Prev = node16->Free; } else { N = PUSH_STRUCT(&node16->arena, Node16); } ActorPath * p = &(permanent->paths[i]); // TODO iam not sure about this, is this the right way to center all positions in the path nodes? // should it be done somewhere else instead? // TODO and why o why does it need something extra when facing Front and not under other circumstances. //float xMult = 0;//facing_side == Front ? 1 : facing_side == Left ? -0.5 : 0.5; //float yMult = 0;//facing_side == Front ? 0.5 : 1; N->path.node.x = (permanent->block_size.x/2) + done->X * permanent->block_size.x; N->path.node.y = (permanent->block_size.y/2) + done->Y * permanent->block_size.y; N->path.node.z = done->Z * permanent->block_size.z_level; /* if (done->Prev != Path->Sentinel) { */ /* // going up */ /* if (done->Z > done->Prev->Z) { */ /* printf("going up\n"); */ /* printf("%d,%d,%d %d,%d,%d\n", done->X,done->Y,done->Z, done->Prev->X, done->Prev->Y, done->Prev->Z); */ /* } */ /* if (done->Z < done->Prev->Z) { */ /* printf("going down 222\n"); */ /* printf("%d,%d,%d %d,%d,%d\n", done->X,done->Y,done->Z, done->Prev->X, done->Prev->Y, done->Prev->Z); */ /* } */ /* } */ /* if (done->Next != Path->Sentinel) { */ /* // going down */ /* if (done->Z < done->Next->Z) { */ /* printf("going down\n"); */ /* printf("%d,%d,%d %d,%d,%d\n", done->X,done->Y,done->Z, done->Next->X, done->Next->Y, done->Next->Z); */ /* } */ /* } */ // if this is part of a stair move going up east/west // TODO: this routine patches some issues which, IMO would better be solved at the root, dunno how wnad where though./ #if 0 // pathing movemenst going up on east/west stairs if (facing_side == Front) { if (done->Prev != Path->Sentinel) { // going up if (done->Z > done->Prev->Z) { if (done->X < done->Prev->X){ N->path.node.x += permanent->block_size.x; } else if (done->X > done->Prev->X){ N->path.node.x -= permanent->block_size.x; } } } if (done->Next != Path->Sentinel) { // going down if (done->Z < done->Next->Z) { if (done->X < done->Next->X){ N->path.node.x -= permanent->block_size.x; } else if (done->X > done->Next->X){ N->path.node.x += permanent->block_size.x; } } } } if (facing_side == Left) { if (done->Prev != Path->Sentinel) { // going up if (done->Z > done->Prev->Z) { if (done->Y < done->Prev->Y){ N->path.node.y += permanent->block_size.y; } else if (done->Y > done->Prev->Y){ N->path.node.y -= permanent->block_size.y; } } } if (done->Next != Path->Sentinel) { // going down if (done->Z < done->Next->Z) { if (done->Y < done->Next->Y){ N->path.node.y -= permanent->block_size.y; } else if (done->Y > done->Next->Y){ N->path.node.y += permanent->block_size.y; } } } } if (facing_side == Right) { if (done->Prev != Path->Sentinel) { // going up if (done->Z > done->Prev->Z) { if (done->Y < done->Prev->Y){ N->path.node.y += permanent->block_size.y; } else if (done->Y > done->Prev->Y){ N->path.node.y -= permanent->block_size.y; } } } if (done->Next != Path->Sentinel) { // going down if (done->Z < done->Next->Z) { if (done->Y < done->Next->Y){ N->path.node.y -= permanent->block_size.y; } else if (done->Y > done->Next->Y){ N->path.node.y += permanent->block_size.y; } } } } #endif DLIST_ADDFIRST(p, N); done = done->Prev; } } } END_PERFORMANCE_COUNTER(mass_pathfinding); //path_list * Path = ExpandPath(PathSmooth, &scratch->arena); BEGIN_PERFORMANCE_COUNTER(grid_cleaning); for (int i = 0; i < permanent->grid->width * permanent->grid->height * permanent->grid->depth;i++) { permanent->grid->nodes[i].f = 0; permanent->grid->nodes[i].g = 0; permanent->grid->nodes[i].opened = 0; permanent->grid->nodes[i].closed = 0; permanent->grid->nodes[i].Next = NULL; permanent->grid->nodes[i].parent = NULL; } END_PERFORMANCE_COUNTER(grid_cleaning); end_temporary_memory(temp_mem); } set_colored_line_batch_sizes(permanent, renderer); } #endif BEGIN_PERFORMANCE_COUNTER(actors_data_gathering); for (u32 i = 0; i < permanent->actor_count; i++) { permanent->actors[i]._location = getRotatedVec3( permanent->steer_data[i].location, facing_side, permanent->dims, permanent->block_size); permanent->actors[i]._palette_index = permanent->anim_data[i].palette_index; permanent->actors[i]._frame = permanent->anim_data[i].frame; permanent->actors[i].x_off = 0; permanent->actors[i].y_off = 0; if ( permanent->anim_data[i].frame == 4) { permanent->actors[i].complex = &generated_body_frames[BP_walking_west_body_000]; } else if (permanent->anim_data[i].frame == 5) { permanent->actors[i].complex = &generated_body_frames[BP_walking_west_body_001]; } else if (permanent->anim_data[i].frame == 6) { permanent->actors[i].complex = &generated_body_frames[BP_walking_south_body_000]; } else if (permanent->anim_data[i].frame == 7) { permanent->actors[i].complex = &generated_body_frames[BP_walking_south_body_001]; } else if (permanent->anim_data[i].frame == 8) { permanent->actors[i].complex = &generated_body_frames[BP_walking_east_body_000]; } else if (permanent->anim_data[i].frame == 9) { permanent->actors[i].complex = &generated_body_frames[BP_walking_east_body_001]; } else if (permanent->anim_data[i].frame == 10) { permanent->actors[i].complex = &generated_body_frames[BP_walking_north_body_000]; } else if (permanent->anim_data[i].frame == 11) { permanent->actors[i].complex = &generated_body_frames[BP_walking_north_body_001]; } /* if ( permanent->anim_data[i].frame % 2 == 0) { */ /* permanent->actors[i].complex = &generated_body_frames[BP_total_east_body_000]; */ /* } else { */ /* permanent->actors[i].complex = &generated_body_frames[BP_total_east_body_001]; */ /* } */ } for (u32 i = permanent->actor_count; i < permanent->actor_count*2; i++) { u32 j = i - permanent->actor_count; permanent->actors[i]._location = getRotatedVec3( permanent->steer_data[j].location, facing_side, permanent->dims, permanent->block_size); permanent->actors[i]._palette_index = (1.0f / 16.0f) * (j % 16);//permanent->anim_data[j].palette_index; permanent->actors[i]._frame = permanent->anim_data[j].frame; int deltaX = permanent->actors[j].complex->anchorX - permanent->actors[j].complex->pivotX; int deltaY = permanent->actors[j].complex->anchorY - permanent->actors[j].complex->pivotY; permanent->actors[i].x_off = deltaX; permanent->actors[i].y_off = -1 * deltaY; if ( permanent->anim_data[j].frame == 4) { permanent->actors[i].complex = &generated_body_frames[BP_facing_west_head_000]; } else if (permanent->anim_data[j].frame == 5) { permanent->actors[i].complex = &generated_body_frames[BP_facing_west_head_000]; } else if (permanent->anim_data[j].frame == 6) { permanent->actors[i].complex = &generated_body_frames[BP_facing_south_head_000]; } else if (permanent->anim_data[j].frame == 7) { permanent->actors[i].complex = &generated_body_frames[BP_facing_south_head_000]; } else if (permanent->anim_data[j].frame == 8) { permanent->actors[i].complex = &generated_body_frames[BP_facing_east_head_000]; } else if (permanent->anim_data[j].frame == 9) { permanent->actors[i].complex = &generated_body_frames[BP_facing_east_head_000]; } else if (permanent->anim_data[j].frame == 10) { permanent->actors[i].complex = &generated_body_frames[BP_facing_north_head_000]; } else if (permanent->anim_data[j].frame == 11) { permanent->actors[i].complex = &generated_body_frames[BP_facing_north_head_000]; } } END_PERFORMANCE_COUNTER(actors_data_gathering); BEGIN_PERFORMANCE_COUNTER(actors_sort); Actor_quick_sort(permanent->actors, permanent->actor_count*2); END_PERFORMANCE_COUNTER(actors_sort); }
void list_set(linked_list list, const int index, const void *elem){ struct list_node* n = get_node_at(list, index); // Copy new element memory content onto the old one memcpy(n->elem, elem, list->elem_size); }
void* list_get(linked_list list, const int index){ struct list_node* n = get_node_at(list, index); return n->elem; }
bool NPC::pathfind_to_closest_item(const string & item_id, World & world) { // leave this for debugging // cout << "\nSearching for path from " << x << "," << y << " to any " << item_id << ".\n"; /* Pathfinding resources: http://www.redblobgames.com/pathfinding/a-star/introduction.html http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html#S7 F = G + H G : actual cost to reach a certain room H : estimated cost to reach destination from a certain room F-cost = G + H */ vector<Node> open_list, closed_list; // Add current room to open list. open_list.push_back(Node(this->x, this->y, "")); // cost to reach current room is of course 0 open_list[0].set_g(0); // Do do { // -- Find lowest f - cost room on open list // -- Move it to closed list // find the cheapest room in the open list. Select it and move it to the closed list const Node current_room = move_and_get_lowest_g_cost(open_list, closed_list); // for each room adjacent to current for (const string & direction : C::direction_ids) { if (direction == C::UP || direction == C::DOWN) { continue; } // only pathfinding in 2D now // calculate the location deltas int dx = 0, dy = 0, dz = 0; R::assign_movement_deltas(direction, dx, dy, dz); // skip if the room if it is out of bounds, if (!R::bounds_check(current_room.x + dx, current_room.y + dy, C::GROUND_INDEX)) { continue; } // or it is not loaded, if (world.room_at(current_room.x + dx, current_room.y + dy, C::GROUND_INDEX) == nullptr) { continue; } // or it is not within view distance, if (!world.room_at(current_room.x + dx, current_room.y + dy, C::GROUND_INDEX)->is_observed_by(this->name)) { continue; } // or we can not travel to it from the current room if (validate_movement(current_room.x, current_room.y, C::GROUND_INDEX, direction, dx, dy, 0, world) != C::GOOD_SIGNAL) { continue; } // create a node to select the next adjacent room Node adjacent_room(current_room.x + dx, current_room.y + dy, direction); // pass if the adjacent node is already on the closed list if (room_in_node_list(adjacent_room.x, adjacent_room.y, closed_list)) { continue; } // if the room is not on the open list if (!room_in_node_list(adjacent_room.x, adjacent_room.y, open_list)) { // make the current room the parent of the adjacent room adjacent_room.parent_x = current_room.x; adjacent_room.parent_y = current_room.y; // calculate the movement cost int move_cost = ( // check if the NPC will have to move through a forest (world.room_at(adjacent_room.x, adjacent_room.y, C::GROUND_INDEX)->contains_item(C::TREE_ID)) ? // determine if the movement is in a primary direction ((R::contains(C::primary_direction_ids, direction) ? C::AI_MOVEMENT_COST_FOREST : C::AI_MOVEMENT_COST_FOREST_DIAGONAL)) : ((R::contains(C::primary_direction_ids, direction) ? C::AI_MOVEMENT_COST : C::AI_MOVEMENT_COST_DIAGONAL)) ); // calculate the cost to this room adjacent_room.set_g(current_room.g + move_cost); } // else the room is on the open list else { // pull adjacent_room out of open_list for (unsigned i = 0; i < open_list.size(); ++i) // for each node in the open list { if (open_list[i].x == adjacent_room.x && open_list[i].y == adjacent_room.y) // if the node is the current room { adjacent_room = get_node_at(adjacent_room.x, adjacent_room.y, open_list); // save it open_list.erase(open_list.begin() + i); // erase the original break; // adjacent_room is now the one from the list } } // calculate the move cost int move_cost = ( // check if the NPC will have to move through a forest (world.room_at(adjacent_room.x, adjacent_room.y, C::GROUND_INDEX)->contains_item(C::TREE_ID)) ? // determine if the movement is in a primary direction ((R::contains(C::primary_direction_ids, direction) ? C::AI_MOVEMENT_COST_FOREST : C::AI_MOVEMENT_COST_FOREST_DIAGONAL)) : ((R::contains(C::primary_direction_ids, direction) ? C::AI_MOVEMENT_COST : C::AI_MOVEMENT_COST_DIAGONAL)) ); // if this way to the room is cheaper than the current best cost to the room if (current_room.g + move_cost < adjacent_room.g) { // update the adjacent room's parent room to the current room adjacent_room.parent_x = current_room.x; adjacent_room.parent_y = current_room.y; // update the g-score cost to the room adjacent_room.set_g(current_room.g + move_cost); } } // add the adjacent room to the open list open_list.push_back(adjacent_room); } // end for each adjacent room // keep searching as long as there are still rooms to search } while (open_list.size() > 0); // get the target (destination) room Node destination_room; destination_room.g = 999999; for (const Node & node : closed_list) { if (world.room_at(node.x, node.y, C::GROUND_INDEX)->contains_item(item_id) && node.g < destination_room.g) { destination_room = node; } } // if no destination was found, there is no path if (destination_room.x == -1 || destination_room.y == -1) { return false; } Node current_room = destination_room; // Starting from the target room, continue finding the parent room until the current room is found // (this represents the path in reverse) do { // get the parent room of the current room Node parent_room = get_node_at(current_room.parent_x, current_room.parent_y, closed_list); // leave this here for debugging // cout << "\nI can get to " << current_room.x << "," << current_room.y << " from " << parent_room.x << "," << parent_room.y << "."; // if the parent of current_room is our location if (parent_room.x == this->x && parent_room.y == this->y) { // move to current_room move(current_room.direction_from_parent, world); /* leave this here for debugging cout << endl; for (const Node & node : closed_list) { cout << "Parent of " << node.x << "," << node.y << " is " << node.parent_x << "," << node.parent_y << ". Actual cost to node: " << node.g << ". Estimated cost to target: " << node.h << endl; } */ return true; // we're done here } // if there is no parent room in the closed list (?!) else if (parent_room.x == -1 || parent_room.y == -1) { return false; // something went horribly wrong } // move up the path by one room current_room = parent_room; } while (true); }