static void m2_swipe_nearby_items(short player_index) { object_data *object; object_data *player_object; player_data *player= get_player_data(player_index); short next_object; polygon_data *polygon; short *neighbor_indexes; short i; player_object= get_object_data(get_monster_data(player->monster_index)->object_index); polygon= get_polygon_data(player_object->polygon); neighbor_indexes= get_map_indexes(polygon->first_neighbor_index, polygon->neighbor_count); // Skip this step if neighbor indexes were not found if (!neighbor_indexes) return; for (i=0;i<polygon->neighbor_count;++i) { polygon_data *neighboring_polygon= get_polygon_data(*neighbor_indexes++); if (POLYGON_IS_DETACHED(neighboring_polygon)) continue; next_object= neighboring_polygon->first_object; while(next_object != NONE) { object= get_object_data(next_object); if (GET_OBJECT_OWNER(object)==_object_is_item && !OBJECT_IS_INVISIBLE(object)) { if (guess_distance2d((world_point2d *) &player->location, (world_point2d *) &object->location)<=MAXIMUM_ARM_REACH) { world_distance radius, height; get_monster_dimensions(player->monster_index, &radius, &height); if (object->location.z >= player->location.z - MAXIMUM_ARM_REACH && object->location.z <= player->location.z + height && test_item_retrieval(player_object->polygon, &player_object->location, &object->location)) { if(get_item(player_index, next_object)) { /* Start the search again.. */ next_object= neighboring_polygon->first_object; continue; } } } } next_object= object->next_object; } } }
// Main routine void RenderVisTreeClass::build_render_tree() { assert(view); // Idiot-proofing /* initialize the queue where we remember polygons we need to fire at */ initialize_polygon_queue(); /* initialize our node list to contain the root, etc. */ initialize_render_tree(); /* reset clipping buffers */ initialize_clip_data(); // LP change: // Adjusted for long-vector handling // Using start index of list of nodes: 0 long_vector2d view_edge; short_to_long_2d( view->left_edge, view_edge ); cast_render_ray( &view_edge, NONE, &Nodes.front(), _counterclockwise_bias ); short_to_long_2d( view->right_edge, view_edge ); cast_render_ray( &view_edge, NONE, &Nodes.front(), _clockwise_bias ); /* pull polygons off the queue, fire at all their new endpoints, building the tree as we go */ while (polygon_queue_size) { auto polygon_index = PolygonQueue[ --polygon_queue_size ]; polygon_data *polygon = get_polygon_data(polygon_index); assert( !POLYGON_IS_DETACHED(polygon) ); const ix vertex_count = polygon->vertex_count; for( ix vertex_index = 0; vertex_index < vertex_count; ++vertex_index ) { const auto endpoint_index = polygon->endpoint_indexes[vertex_index]; endpoint_data *endpoint = get_endpoint_data(endpoint_index); if (TEST_RENDER_FLAG(endpoint_index, _endpoint_has_been_visited)) continue; // LP change: move toward correct handling of long distances long_vector2d _vector; /* transform all visited endpoints */ endpoint->transformed = endpoint->vertex; transform_overflow_point2d( &endpoint->transformed, (world_point2d *) &view->origin, view->yaw, &endpoint->flags ); /* calculate an outbound vector to this endpoint */ // LP: changed to do long distance correctly. _vector.i = int32( endpoint->vertex.x ) - int32( view->origin.x ); _vector.j = int32( endpoint->vertex.y ) - int32( view->origin.y ); // LP change: compose a true transformed point to replace endpoint->transformed, // and use it in the upcoming code long_vector2d transformed_endpoint; overflow_short_to_long_2d( endpoint->transformed, endpoint->flags, transformed_endpoint ); if (transformed_endpoint.i > 0) { const int32 x = view->half_screen_width + ( transformed_endpoint.j * view->world_to_screen_x ) / transformed_endpoint.i; endpoint_x_coordinates[ endpoint_index ] = static_cast< int16 >( PIN(x, INT16_MIN, INT16_MAX) ); SET_RENDER_FLAG(endpoint_index, _endpoint_has_been_transformed); } /* do two cross products to determine whether this endpoint is in our view cone or not (we don't have to cast at points outside the cone) */ const auto ri = view->right_edge.i; const auto rj = view->right_edge.j; const int32 crossprod_right = ( ri * _vector.j ) - ( rj * _vector.i ); const auto li = view->left_edge.i; const auto lj = view->left_edge.j; const int32 crossprod_left = ( li * _vector.j ) - ( lj * _vector.i ); if( crossprod_right <= 0 && crossprod_left >= 0 ) { //it's in our view, cast at it int16 endpoint_; if( ENDPOINT_IS_TRANSPARENT(endpoint) ) endpoint_ = NONE; else endpoint_ = endpoint_index; cast_render_ray(&_vector, endpoint_, &Nodes.front(), _no_bias); } SET_RENDER_FLAG(endpoint_index, _endpoint_has_been_visited); } } }
static void a1_swipe_nearby_items(short player_index) { object_data *object; object_data *player_object; player_data *player = get_player_data(player_index); short next_object; polygon_data *polygon; short *neighbor_indexes; short i; player_object = get_object_data(get_monster_data(player->monster_index)->object_index); polygon= get_polygon_data(player_object->polygon); neighbor_indexes= get_map_indexes(polygon->first_neighbor_index, polygon->neighbor_count); // Skip this step if neighbor indexes were not found if (!neighbor_indexes) return; for (i=0;i<polygon->neighbor_count;++i) { struct polygon_data *neighboring_polygon= get_polygon_data(*neighbor_indexes++); /* LP change: since precalculate_map_indexes() and its associated routine intersecting_flood_proc() appear to have some bugs in them, I will instead search the neighbors of each indexed polygon. Starting the search from -1 is a kludge designed to include a search for the current polygon. */ polygon_data *source_polygon = neighboring_polygon; for (int ngbr_indx = -1; ngbr_indx<source_polygon->vertex_count; ngbr_indx++) { if (ngbr_indx >= 0) { // Be sure to check on whether there is a valid polygon on the other side auto adjacent_index = source_polygon->adjacent_polygon_indexes[ngbr_indx]; if (adjacent_index == NONE) continue; neighboring_polygon = get_polygon_data(adjacent_index); } else neighboring_polygon = source_polygon; if (!POLYGON_IS_DETACHED(neighboring_polygon)) { next_object= neighboring_polygon->first_object; while(next_object != NONE) { object= get_object_data(next_object); if (GET_OBJECT_OWNER(object)==_object_is_item && !OBJECT_IS_INVISIBLE(object)) { if (guess_distance2d((world_point2d *) &player->location, (world_point2d *) &object->location)<=MAXIMUM_ARM_REACH) { world_distance radius, height; get_monster_dimensions(player->monster_index, &radius, &height); if (object->location.z >= player->location.z - MAXIMUM_ARM_REACH && object->location.z <= player->location.z + height && test_item_retrieval(player_object->polygon, &player_object->location, &object->location)) { if(get_item(player_index, next_object)) { /* Start the search again.. */ next_object= neighboring_polygon->first_object; continue; } } } } next_object= object->next_object; } } // LP addition: end of that kludgy search loop } } }
/* returns next polygon index or NONE if there are no more polygons left cheaper than maximum_cost */ short flood_map( short first_polygon_index, long maximum_cost, cost_proc_ptr cost_proc, short flood_mode, void *caller_data) { short lowest_cost_node_index, node_index; struct node_data *node; short polygon_index; long lowest_cost; /* initialize ourselves if first_polygon_index!=NONE */ if (first_polygon_index!=NONE) { /* clear the visited polygon array */ memset(visited_polygons, NONE, sizeof(short)*MAXIMUM_POLYGONS_PER_MAP); node_count= 0; last_node_index_expanded= NONE; add_node(NONE, first_polygon_index, 0, 0, (flood_mode==_flagged_breadth_first) ? *((long*)caller_data) : 0); } switch (flood_mode) { case _best_first: /* find the unexpanded node with the lowest cost */ lowest_cost= maximum_cost, lowest_cost_node_index= NONE; for (node= nodes, node_index= 0; node_index<node_count; ++node_index, ++node) { if (NODE_IS_UNEXPANDED(node)&&node->cost<lowest_cost) { lowest_cost_node_index= node_index; lowest_cost= node->cost; } } break; case _breadth_first: case _flagged_breadth_first: /* find the next unexpanded node in the list under maximum_cost */ node_index= (last_node_index_expanded==NONE) ? 0 : (last_node_index_expanded+1); for (node= nodes+node_index; node_index<node_count; ++node_index, ++node) { if (node->cost<maximum_cost) break; } if (node_index==node_count) { lowest_cost_node_index= NONE; lowest_cost= maximum_cost; } else { lowest_cost_node_index= node_index; lowest_cost= node->cost; } break; case _depth_first: /* implementation left to the caller (c.f., zen() in fareast.c) */ halt(); default: halt(); } /* if we found a node, mark it as expanded and add itÕs adjacent non-solid polygons to the search tree */ if (lowest_cost_node_index!=NONE) { struct polygon_data *polygon; short i; /* for flood_depth() and reverse_flood_map(), remember which node we successfully expanded last */ last_node_index_expanded= lowest_cost_node_index; /* get pointer to lowest cost node */ assert(lowest_cost_node_index>=0&&lowest_cost_node_index<node_count); node= nodes+lowest_cost_node_index; polygon= get_polygon_data(node->polygon_index); assert(!POLYGON_IS_DETACHED(polygon)); /* mark node as expanded */ MARK_NODE_AS_EXPANDED(node); for (i= 0; i<polygon->vertex_count; ++i) { short destination_polygon_index= polygon->adjacent_polygon_indexes[i]; if (destination_polygon_index!=NONE && (maximum_cost!=LONG_MAX || visited_polygons[destination_polygon_index]==UNVISITED)) { long new_user_flags= node->user_flags; long cost= cost_proc ? cost_proc(node->polygon_index, polygon->line_indexes[i], destination_polygon_index, (flood_mode==_flagged_breadth_first) ? &new_user_flags : caller_data) : polygon->area; /* polygons with zero or negative costs are not added to the node list */ if (cost>0) add_node(lowest_cost_node_index, destination_polygon_index, node->depth+1, lowest_cost+cost, new_user_flags); } } polygon_index= node->polygon_index; if (flood_mode==_flagged_breadth_first) *((long*)caller_data)= node->user_flags; } else { polygon_index= NONE; } return polygon_index; }