コード例 #1
0
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));
    }
}
コード例 #2
0
ファイル: game.c プロジェクト: NikkiKoole/coggies
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;
}
コード例 #3
0
ファイル: linked_list.c プロジェクト: matcap/data-structures
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--;
}
コード例 #4
0
ファイル: game.c プロジェクト: NikkiKoole/coggies
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;
}
コード例 #5
0
ファイル: game.c プロジェクト: NikkiKoole/coggies
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);

}
コード例 #6
0
ファイル: linked_list.c プロジェクト: matcap/data-structures
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);
}
コード例 #7
0
ファイル: linked_list.c プロジェクト: matcap/data-structures
void* list_get(linked_list list, const int index){
    struct list_node* n = get_node_at(list, index);

    return n->elem;
}
コード例 #8
0
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);
}