int main() { { TimeCheck time; auto surface = create_surface(CAIRO_FORMAT_ARGB32, SURFACE_SIZE{ 256, 256 }); auto cr = create(surface); arc(cr, POINT{ 128.0, 128.0 }, 76.8, DEGRESS{ 0 }, DEGRESS{ 360 }); clip(cr); new_path(cr); /* current path is not consumed by cairo_clip() */ rectangle(cr, POINT{ 0, 0 }, SIZE{ 255, 255 }); fill(cr); source(cr, RGB{ 0, 1, 0 }); move_to(cr, POINT{ 0, 0 }); line_to(cr, POINT{ 256, 256 }); move_to(cr, POINT{ 256, 0 }); line_to(cr, POINT{ 0, 256 }); line_width(cr, 10.0); stroke(cr); write_to_png(surface, "image.png"); } return 0; }
void PathParser::append(const UnivocalPath& append_path) { const std::vector<Edge>& edges = append_path._path->m_edges; if (append_path._fill_type == UnivocalPath::FILL_LEFT) { std::for_each(edges.begin(), edges.end(), boost::bind(&PathParser::line_to, this, _1)); } else { for (std::vector<Edge>::const_reverse_iterator prev = edges.rbegin(), it = boost::next(prev), end = edges.rend(); it != end; ++it, ++prev) { if ((*prev).straight()) { lineTo((*it).ap); } else { line_to(Edge((*prev).cp, (*it).ap)); } } line_to(Edge(edges.front().cp, append_path.endPoint())); } _cur_endpoint = append_path.endPoint(); }
void mdeath::focused_beam(monster *z) { for (int k = g->m.i_at(z->posx(), z->posy()).size() - 1; k >= 0; k--) { if (g->m.i_at(z->posx(), z->posy())[k].type->id == "processor") { g->m.i_rem(z->posx(), z->posy(), k); } } if (z->inv.size() > 0) { if (g->u_see(z)) { add_msg(m_warning, _("As the final light is destroyed, it erupts in a blinding flare!")); } item &settings = z->inv[0]; int x = z->posx() + atoi(settings.item_vars["SL_SPOT_X"].c_str()); int y = z->posy() + atoi(settings.item_vars["SL_SPOT_Y"].c_str()); std::vector <point> traj = line_to(z->posx(), z->posy(), x, y, 0); for( auto &elem : traj ) { if( !g->m.trans( elem.x, elem.y ) ) { break; } g->m.add_field( elem.x, elem.y, fd_dazzling, 2 ); } } z->inv.clear(); g->explosion(z->posx(), z->posy(), 8, 0, false); }
void mdeath::focused_beam(monster *z) { for (int k = g->m.i_at(z->pos()).size() - 1; k >= 0; k--) { if (g->m.i_at(z->pos())[k].type->id == "processor") { g->m.i_rem(z->pos(), k); } } if (z->inv.size() > 0) { if (g->u.sees(*z)) { add_msg(m_warning, _("As the final light is destroyed, it erupts in a blinding flare!")); } item &settings = z->inv[0]; int x = z->posx() + settings.get_var( "SL_SPOT_X", 0 ); int y = z->posy() + settings.get_var( "SL_SPOT_Y", 0 ); tripoint p( x, y, z->posz() ); std::vector <tripoint> traj = line_to(z->pos(), p, 0, 0); for( auto &elem : traj ) { if( !g->m.trans( elem ) ) { break; } g->m.add_field( elem, fd_dazzling, 2, 0 ); } } z->inv.clear(); g->explosion(z->pos3(), 8, 0, false); }
/* * Function PlotPoly * writes a filled or not filled polyline to output file * @param aCornerList = buffer of corners coordinates * @param aFill = plot option (NO_FILL, FILLED_SHAPE, FILLED_WITH_BG_BODYCOLOR) * @param aWidth = Width of the line to plot. */ void GERBER_PLOTTER::PlotPoly( std::vector< wxPoint >& aCornerList, FILL_T aFill, int aWidth ) { if( aCornerList.size() <= 1 ) return; set_current_line_width( aWidth ); if( aFill ) fputs( "G36*\n", output_file ); move_to( aCornerList[0] ); for( unsigned ii = 1; ii < aCornerList.size(); ii++ ) { line_to( aCornerList[ii] ); } if( aFill ) { finish_to( aCornerList[0] ); fputs( "G37*\n", output_file ); } else { pen_finish(); } }
void MWcanvas16::curve_to( Coord x, Coord y, Coord x1, Coord y1, Coord x2, Coord y2) { PathRenderInfo* p = &MWcanvas16::path_; Coord px = p->curx_; Coord py = p->cury_; if (straight(matrix(), px, py, x1, y1, x2, y2, x, y)) { line_to(x, y); } else { Coord xx = mid(x1, x2); Coord yy = mid(y1, y2); Coord x11 = mid(px, x1); Coord y11 = mid(py, y1); Coord x22 = mid(x2, x); Coord y22 = mid(y2, y); Coord x12 = mid(x11, xx); Coord y12 = mid(y11, yy); Coord x21 = mid(xx, x22); Coord y21 = mid(yy, y22); Coord cx = mid(x12, x21); Coord cy = mid(y12, y21); curve_to(cx, cy, x11, y11, x12, y12); curve_to(x, y, x21, y21, x22, y22); } }
static cairo_status_t close_path (void *closure) { struct stroker *stroker = closure; cairo_status_t status; status = line_to (stroker, &stroker->first_point); if (unlikely (status)) return status; if (stroker->has_first_face && stroker->has_current_face) { /* Join first and final faces of sub path */ outer_close (stroker, &stroker->current_face, &stroker->first_face); inner_close (stroker, &stroker->current_face, &stroker->first_face); } else { /* Cap the start and end of the sub path as needed */ add_caps (stroker); } stroker->has_sub_path = FALSE; stroker->has_first_face = FALSE; stroker->has_current_face = FALSE; return CAIRO_STATUS_SUCCESS; }
void draw_line( std::function<void( const int, const int )>set, int x1, int y1, int x2, int y2 ) { std::vector<point> line = line_to( x1, y1, x2, y2, 0 ); for( auto &i : line ) { set( i.x, i.y ); } set( x1, y1 ); }
std::vector<point> continue_line(const std::vector<point> &line, const int distance) { const point start = line.back(); point end = line.back(); const std::pair<double, double> slope = slope_of(line); end.x += distance * slope.first; end.y += distance * slope.second; return line_to(start.x, start.y, end.x, end.y, 0); }
static cairo_status_t curve_to (void *closure, const cairo_point_t *b, const cairo_point_t *c, const cairo_point_t *d) { struct stroker *stroker = closure; cairo_spline_t spline; cairo_stroke_face_t face; if (stroker->has_limits) { if (! _cairo_spline_intersects (&stroker->current_face.point, b, c, d, &stroker->limit)) return line_to (closure, d); } if (! _cairo_spline_init (&spline, spline_to, stroker, &stroker->current_face.point, b, c, d)) return line_to (closure, d); compute_face (&stroker->current_face.point, &spline.initial_slope, stroker, &face); if (stroker->has_current_face) { int clockwise = join_is_clockwise (&stroker->current_face, &face); /* Join with final face from previous segment */ outer_join (stroker, &stroker->current_face, &face, clockwise); inner_join (stroker, &stroker->current_face, &face, clockwise); } else { if (! stroker->has_first_face) { /* Save sub path's first face in case needed for closing join */ stroker->first_face = face; _cairo_tristrip_move_to (stroker->strip, &face.cw); stroker->has_first_face = TRUE; } stroker->has_current_face = TRUE; _cairo_tristrip_add_point (stroker->strip, &face.cw); _cairo_tristrip_add_point (stroker->strip, &face.ccw); } stroker->current_face = face; return _cairo_spline_decompose (&spline, stroker->tolerance); }
/* * Calculate target_list based on origin and target class variables, and shapetype. */ point editmap::recalc_target(shapetype shape) { point ret = target; target_list.clear(); switch(shape) { case editmap_circle: { int radius = rl_dist(origin.x, origin.y, target.x, target.y); for ( int x = origin.x - radius; x <= origin.x + radius; x++ ) { for ( int y = origin.y - radius; y <= origin.y + radius; y++ ) { if(rl_dist(x, y, origin.x, origin.y) <= radius) { if ( inbounds(x, y) ) { target_list.push_back(point(x, y)); } } } } } break; case editmap_rect_filled: case editmap_rect: int sx; int sy; int ex; int ey; if ( target.x < origin.x ) { sx = target.x; ex = origin.x; } else { sx = origin.x; ex = target.x; } if ( target.y < origin.y ) { sy = target.y; ey = origin.y; } else { sy = origin.y; ey = target.y; } for ( int x = sx; x <= ex; x++ ) { for ( int y = sy; y <= ey; y++ ) { if ( shape == editmap_rect_filled || x == sx || x == ex || y == sy || y == ey ) { if ( inbounds(x, y) ) { target_list.push_back(point(x, y)); } } } } break; case editmap_line: int t = 0; target_list = line_to(origin.x, origin.y, target.x, target.y, t); break; } return ret; }
void add_function(graphics::plot& p, double x0, double x1, Function f, agg::rgba8 color, unsigned flags, int n = 512) { agg::rgba8 none(0,0,0,0); auto line = new graphics::path(); line->move_to(x0, f(x0)); for (int i = 1; i <= n; i++) { const double x = x0 + i * (x1 - x0) / n; line->line_to(x, f(x)); } p.add(line, color, 1.5, none, flags); }
int main() { { TimeCheck time; auto surface = create_surface(CAIRO_FORMAT_ARGB32, SURFACE_SIZE{ 256, 256 }); auto cr = create(surface); line_width(cr, 30.0); line_cap(cr, CAIRO_LINE_CAP_BUTT); /* default */ move_to(cr, POINT{ 64.0, 50.0 }); line_to(cr, POINT{ 64.0, 200.0 }); stroke(cr); line_cap(cr, CAIRO_LINE_CAP_ROUND); move_to(cr, POINT{ 128.0, 50.0 }); line_to(cr, POINT{ 128.0, 200.0 }); stroke(cr); line_cap(cr, CAIRO_LINE_CAP_SQUARE); move_to(cr, POINT{ 192.0, 50.0 }); line_to(cr, POINT{ 192.0, 200.0 }); stroke(cr); /* draw helping lines */ source(cr, RGB{ 1, 0.2, 0.2 }); line_width(cr, 2.56); move_to(cr, POINT{ 64.0, 50.0 }); line_to(cr, POINT{ 64.0, 200.0 }); move_to(cr, POINT{ 128.0, 50.0 }); line_to(cr, POINT{ 128.0, 200.0 }); move_to(cr, POINT{ 192.0, 50.0 }); line_to(cr, POINT{ 192.0, 200.0 }); stroke(cr); write_to_png(surface, "image.png"); } return 0; }
void Game::launch_projectile(Item it, Ranged_attack attack, Point origin, Point target) { int range = rl_dist(origin, target); int angle_missed_by = attack.roll_variance(); // Use 1800 since attack.variance is measured in 10ths of a degree double distance_missed_by = range * tan(angle_missed_by * PI / 1800); int tiles_off = int(distance_missed_by); if (tiles_off >= 1) { target.x += rng(0 - tiles_off, tiles_off); target.y += rng(0 - tiles_off, tiles_off); } // fine_distance is used later to see if we hit the target or "barely missed" int fine_distance = 100 * (distance_missed_by - tiles_off); debugmsg("angle %d, missed %f, tiles %d, fine %d", angle_missed_by, distance_missed_by, tiles_off, fine_distance); std::vector<Point> path = map->line_of_sight(origin, target); if (path.empty()) { // Lost line of sight at some point path = line_to(origin, target); } for (int i = 0; i < path.size(); i++) { if (map->move_cost(path[i].x, path[i].y) == 0) { // It's a solid tile, so let's try to smash through it! map->smash(path[i].x, path[i].y, attack.roll_damage(), false); if (map->move_cost(path[i].x, path[i].y) == 0) { return; // We didn't make it! } } else { Entity* entity_hit = entities.entity_at(path[i].x, path[i].y); if (entity_hit) { bool hit; // TODO: Incorporate the size of the monster if (i == path.size() - 1) { hit = rng(0, 100) >= fine_distance; } else { hit = one_in(3); } if (hit) { add_msg("You shoot %s!", entity_hit->get_name_to_player().c_str()); Damage_set dam = attack.roll_damage(); entity_hit->take_damage(DAMAGE_PIERCE, dam.get_damage(DAMAGE_PIERCE), "you"); return; } else if (i == path.size() - 1) { add_msg("You barely miss %s.", entity_hit->get_name_to_player().c_str()); } } } } }
void construct::done_tree(game *g, point p) { mvprintz(0, 0, c_red, _("Press a direction for the tree to fall in:")); int x = 0, y = 0; do get_direction(x, y, input()); while (x == -2 || y == -2); x = p.x + x * 3 + rng(-1, 1); y = p.y + y * 3 + rng(-1, 1); std::vector<point> tree = line_to(p.x, p.y, x, y, rng(1, 8)); for (int i = 0; i < tree.size(); i++) { g->m.destroy(g, tree[i].x, tree[i].y, true); g->m.ter_set(tree[i].x, tree[i].y, t_trunk); } }
void construct::done_tree( const tripoint &p ) { tripoint dirp; while( !choose_direction( _( "Press a direction for the tree to fall in:" ), dirp ) ) { // try again } tripoint to = p + point( 3 * dirp.x + rng( -1, 1 ), 3 * dirp.y + rng( -1, 1 ) ); std::vector<tripoint> tree = line_to( p, to, rng( 1, 8 ) ); for( auto &elem : tree ) { g->m.destroy( elem ); g->m.ter_set( elem, t_trunk ); } }
std::vector<tripoint> continue_line(const std::vector<tripoint> &line, const int distance) { // May want to optimize this, but it's called fairly infrequently as part of specific attack // routines, erring on the side of readability. tripoint start; tripoint end; start = end = line.back(); // slope <<x,y>,z> std::pair<std::pair<double, double>, double> slope; slope = slope_of(line); end.x += int(distance * slope.first.first); end.y += int(distance * slope.first.second); end.z += int(distance * slope.second); return line_to(start, end, 0, 0); }
static cairo_status_t close_path (void *closure) { struct stroker *stroker = closure; cairo_status_t status; status = line_to (stroker, &stroker->first_point); if (unlikely (status)) return status; if (stroker->has_first_face && stroker->has_current_face) { /* Join first and final faces of sub path */ outer_close (stroker, &stroker->current_face, &stroker->first_face); inner_close (stroker, &stroker->current_face, &stroker->first_face); #if 0 *_cairo_contour_first_point (&stroker->ccw.contour) = *_cairo_contour_last_point (&stroker->ccw.contour); *_cairo_contour_first_point (&stroker->cw.contour) = *_cairo_contour_last_point (&stroker->cw.contour); #endif _cairo_polygon_add_contour (stroker->polygon, &stroker->cw.contour); _cairo_polygon_add_contour (stroker->polygon, &stroker->ccw.contour); #if DEBUG { FILE *file = fopen ("contours.txt", "a"); _cairo_debug_print_contour (file, &stroker->path); _cairo_debug_print_contour (file, &stroker->cw.contour); _cairo_debug_print_contour (file, &stroker->ccw.contour); fclose (file); _cairo_contour_reset (&stroker->path); } #endif _cairo_contour_reset (&stroker->cw.contour); _cairo_contour_reset (&stroker->ccw.contour); } else { /* Cap the start and end of the sub path as needed */ add_caps (stroker); } stroker->has_initial_sub_path = FALSE; stroker->has_first_face = FALSE; stroker->has_current_face = FALSE; return CAIRO_STATUS_SUCCESS; }
std::vector<point> continue_line(std::vector<point> line, int distance) { point start = line.back(), end = line.back(); double slope = slope_of(line); int sX = (line.front().x < line.back().x ? 1 : -1), sY = (line.front().y < line.back().y ? 1 : -1); if (abs(slope) == 1) { end.x += distance * sX; end.y += distance * sY; } else if (abs(slope) < 1) { end.x += distance * sX; end.y += int(distance * abs(slope) * sY); } else { end.y += distance * sY; if (slope != SLOPE_VERTICAL) end.x += int(distance / abs(slope)) * sX; } return line_to(start.x, start.y, end.x, end.y, 0); }
int monster::group_bash_skill( point target ) { if( !has_flag(MF_GROUP_BASH) ) { return bash_skill(); } int bashskill = 0; // pileup = more bashskill, but only help bashing mob directly infront of target const int max_helper_depth = 5; const std::vector<point> bzone = get_bashing_zone( target, pos(), max_helper_depth ); for( point candidate : bzone ) { // Drawing this line backwards excludes the target and includes the candidate. std::vector<point> path_to_target = line_to( target.x, target.y, candidate.x, candidate.y, 0); bool connected = true; int mondex = -1; for( point in_path : path_to_target ) { // If any point in the line from zombie to target is not a cooperating zombie, // it can't contribute. mondex = g->mon_at( in_path ); if( mondex == -1 ) { connected = false; break; } monster &helpermon = g->zombie( mondex ); if( !helpermon.has_flag(MF_GROUP_BASH) ) { connected = false; break; } } if( !connected ) { continue; } // If we made it here, the last monster checked was the candidate. monster &helpermon = g->zombie( mondex ); // Contribution falls off rapidly with distance from target. bashskill += helpermon.bash_skill() / rl_dist( candidate, target ); } return bashskill; }
void scatter_chunks( const std::string &chunk_name, int chunk_amt, monster &z, int distance, int pile_size = 1 ) { // can't have less than one item in a pile or it would cause an infinite loop pile_size = std::max( pile_size, 1 ); // can't have more items in a pile than total items pile_size = std::min( chunk_amt, pile_size ); distance = abs( distance ); const item chunk( chunk_name, calendar::turn, pile_size ); for( int i = 0; i < chunk_amt; i += pile_size ) { bool drop_chunks = true; tripoint tarp( z.pos() + point( rng( -distance, distance ), rng( -distance, distance ) ) ); const auto traj = line_to( z.pos(), tarp ); for( size_t j = 0; j < traj.size(); j++ ) { tarp = traj[j]; if( one_in( 2 ) && z.bloodType() != fd_null ) { g->m.add_splatter( z.bloodType(), tarp ); } else { g->m.add_splatter( z.gibType(), tarp, rng( 1, j + 1 ) ); } if( g->m.impassable( tarp ) ) { g->m.bash( tarp, distance ); if( g->m.impassable( tarp ) ) { // Target is obstacle, not destroyed by bashing, // stop trajectory in front of it, if this is the first // point (e.g. wall adjacent to monster), don't drop anything on it if( j > 0 ) { tarp = traj[j - 1]; } else { drop_chunks = false; } break; } } } if( drop_chunks ) { g->m.add_item_or_charges( tarp, chunk ); } } }
int monster::group_bash_skill( const tripoint &target ) { if( !has_flag( MF_GROUP_BASH ) ) { return bash_skill(); } int bashskill = 0; // pileup = more bash skill, but only help bashing mob directly in front of target const int max_helper_depth = 5; const std::vector<tripoint> bzone = get_bashing_zone( target, pos(), max_helper_depth ); for( const tripoint &candidate : bzone ) { // Drawing this line backwards excludes the target and includes the candidate. std::vector<tripoint> path_to_target = line_to( target, candidate, 0, 0 ); bool connected = true; monster *mon = nullptr; for( const tripoint &in_path : path_to_target ) { // If any point in the line from zombie to target is not a cooperating zombie, // it can't contribute. mon = g->critter_at<monster>( in_path ); if( !mon ) { connected = false; break; } monster &helpermon = *mon; if( !helpermon.has_flag( MF_GROUP_BASH ) || helpermon.is_hallucination() ) { connected = false; break; } } if( !connected || !mon ) { continue; } // If we made it here, the last monster checked was the candidate. monster &helpermon = *mon; // Contribution falls off rapidly with distance from target. bashskill += helpermon.bash_skill() / rl_dist( candidate, target ); } return bashskill; }
// Returns a vector of the adjacent square in the direction of the target, // and the two squares flanking it. std::vector<point> squares_in_direction( const int x1, const int y1, const int x2, const int y2 ) { int junk = 0; point center_square = line_to( x1, y1, x2, y2, junk )[0]; std::vector<point> adjacent_squares; adjacent_squares.push_back( center_square ); if( x1 == center_square.x ) { // Horizontally adjacent. adjacent_squares.push_back( point( x1 + 1, center_square.y ) ); adjacent_squares.push_back( point( x1 - 1, center_square.y ) ); } else if( y1 == center_square.y ) { // Vertically adjacent. adjacent_squares.push_back( point( center_square.x, y1 + 1 ) ); adjacent_squares.push_back( point( center_square.x, y1 - 1 ) ); } else { // Diagonally adjacent. adjacent_squares.push_back( point( x1, center_square.y ) ); adjacent_squares.push_back( point( center_square.x, y1 ) ); } return adjacent_squares; }
/** * Function circle * writes a non filled circle to output file * Plot one circle as segments (6 to 16 depending on its radius * @param aCentre = center coordinates * @param aDiameter = diameter of the circle * @param aFill = plot option (NO_FILL, FILLED_SHAPE, FILLED_WITH_BG_BODYCOLOR) * not used here: circles are always not filled the gerber. Filled circles are flashed * @param aWidth = line width */ void GERBER_PLOTTER::circle( wxPoint aCentre, int aDiameter, FILL_T aFill, int aWidth ) { wxASSERT( output_file ); wxPoint start, end; double radius = aDiameter / 2; const int delta = 3600 / 32; /* increment (in 0.1 degrees) to draw circles */ start.x = aCentre.x + wxRound( radius ); start.y = aCentre.y; set_current_line_width( aWidth ); move_to( start ); for( int ii = delta; ii < 3600; ii += delta ) { end.x = aCentre.x + (int) ( radius * cos( DEG2RAD( (double)ii / 10.0 ) ) ); end.y = aCentre.y + (int) ( radius * sin( DEG2RAD( (double)ii / 10.0 ) ) ); line_to( end ); } finish_to( start ); }
void add_path(VertexSource& vs, unsigned path_id=0) { double x; double y; unsigned flag; vs.rewind(path_id); while(!agg::is_stop(flag = vs.vertex(&x, &y))) { if(agg::is_vertex(flag)) { if(agg::is_move_to(flag)) { move_to(int(x), int(y)); } else { line_to(int(x), int(y)); } } } }
void cairo_paths_c::arc(double x1, double y1, double rx, double ry, double x_axis_rotation, bool large_arc_flag, bool sweep_flag, double x2, double y2) { double sinf, cosf; double x1_, y1_; double cx_, cy_, cx, cy; double gamma; double theta1, delta_theta; double k1, k2, k3, k4, k5; int i, n_segs; if (x1 == x2 && y1 == y2) return; /* X-axis */ ts::sincos((float)(x_axis_rotation * M_PI / 180.0), sinf, cosf); rx = fabs (rx); ry = fabs (ry); /* Check the radius against floading point underflow. See http://bugs.debian.org/508443 */ if ((rx < DBL_EPSILON) || (ry < DBL_EPSILON)) { line_to (x2, y2); return; } k1 = (x1 - x2) / 2; k2 = (y1 - y2) / 2; x1_ = cosf * k1 + sinf * k2; y1_ = -sinf * k1 + cosf * k2; gamma = (x1_ * x1_) / (rx * rx) + (y1_ * y1_) / (ry * ry); if (gamma > 1) { rx *= sqrt (gamma); ry *= sqrt (gamma); } /* Compute the center */ k1 = rx * rx * y1_ * y1_ + ry * ry * x1_ * x1_; if (k1 == 0) return; k1 = sqrt (fabs ((rx * rx * ry * ry) / k1 - 1)); if (sweep_flag == large_arc_flag) k1 = -k1; cx_ = k1 * rx * y1_ / ry; cy_ = -k1 * ry * x1_ / rx; cx = cosf * cx_ - sinf * cy_ + (x1 + x2) / 2; cy = sinf * cx_ + cosf * cy_ + (y1 + y2) / 2; /* Compute start angle */ k1 = (x1_ - cx_) / rx; k2 = (y1_ - cy_) / ry; k3 = (-x1_ - cx_) / rx; k4 = (-y1_ - cy_) / ry; k5 = sqrt (fabs (k1 * k1 + k2 * k2)); if (k5 == 0) return; k5 = k1 / k5; k5 = ts::CLAMP (k5, -1, 1); theta1 = acos (k5); if (k2 < 0) theta1 = -theta1; /* Compute delta_theta */ k5 = sqrt (fabs ((k1 * k1 + k2 * k2) * (k3 * k3 + k4 * k4))); if (k5 == 0) return; k5 = (k1 * k3 + k2 * k4) / k5; k5 = ts::CLAMP (k5, -1, 1); delta_theta = acos (k5); if (k1 * k4 - k3 * k2 < 0) delta_theta = -delta_theta; if (sweep_flag && delta_theta < 0) delta_theta += M_PI * 2; else if (!sweep_flag && delta_theta > 0) delta_theta -= M_PI * 2; /* Now draw the arc */ n_segs = ts::lround( ceil (fabs (delta_theta / (M_PI * 0.5 + 0.001)))); for (i = 0; i < n_segs; i++) arc_segment ( cx, cy, (float)(theta1 + i * delta_theta / n_segs), (float)(theta1 + (i + 1) * delta_theta / n_segs), rx, ry, x_axis_rotation); }
// Why put this in a Big Switch? Why not let bionics have pointers to // functions, much like monsters and items? // // Well, because like diseases, which are also in a Big Switch, bionics don't // share functions.... void player::activate_bionic(int b, game *g) { bionic bio = my_bionics[b]; int power_cost = bionics[bio.id].power_cost; if (weapon.type->id == itm_bio_claws && bio.id == bio_claws) power_cost = 0; if (power_level < power_cost) { if (my_bionics[b].powered) { g->add_msg("Your %s powers down.", bionics[bio.id].name.c_str()); my_bionics[b].powered = false; } else g->add_msg("You cannot power your %s", bionics[bio.id].name.c_str()); return; } if (my_bionics[b].powered && my_bionics[b].charge > 0) { // Already-on units just lose a bit of charge my_bionics[b].charge--; } else { // Not-on units, or those with zero charge, have to pay the power cost if (bionics[bio.id].charge_time > 0) { my_bionics[b].powered = true; my_bionics[b].charge = bionics[bio.id].charge_time; } power_level -= power_cost; } std::string junk; std::vector<point> traj; std::vector<std::string> good; std::vector<std::string> bad; WINDOW* w; int dirx, diry, t, index; unsigned int l; item tmp_item; switch (bio.id) { case bio_painkiller: pkill += 6; pain -= 2; if (pkill > pain) pkill = pain; break; case bio_nanobots: healall(4); break; case bio_resonator: g->sound(posx, posy, 30, "VRRRRMP!"); for (int i = posx - 1; i <= posx + 1; i++) { for (int j = posy - 1; j <= posy + 1; j++) { g->m.bash(i, j, 40, junk); g->m.bash(i, j, 40, junk); // Multibash effect, so that doors &c will fall g->m.bash(i, j, 40, junk); if (g->m.is_destructable(i, j) && rng(1, 10) >= 4) g->m.ter(i, j) = t_rubble; } } break; case bio_time_freeze: moves += 100 * power_level; power_level = 0; g->add_msg("Your speed suddenly increases!"); if (one_in(3)) { g->add_msg("Your muscles tear with the strain."); hurt(g, bp_arms, 0, rng(5, 10)); hurt(g, bp_arms, 1, rng(5, 10)); hurt(g, bp_legs, 0, rng(7, 12)); hurt(g, bp_legs, 1, rng(7, 12)); hurt(g, bp_torso, 0, rng(5, 15)); } if (one_in(5)) add_disease(DI_TELEGLOW, rng(50, 400), g); break; case bio_teleport: g->teleport(); add_disease(DI_TELEGLOW, 300, g); break; // TODO: More stuff here (and bio_blood_filter) case bio_blood_anal: w = newwin(20, 40, 3, 10); wborder(w, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX, LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX ); if (has_disease(DI_FUNGUS)) bad.push_back("Fungal Parasite"); if (has_disease(DI_DERMATIK)) bad.push_back("Insect Parasite"); if (has_disease(DI_POISON)) bad.push_back("Poison"); if (radiation > 0) bad.push_back("Irradiated"); if (has_disease(DI_PKILL1)) good.push_back("Minor Painkiller"); if (has_disease(DI_PKILL2)) good.push_back("Moderate Painkiller"); if (has_disease(DI_PKILL3)) good.push_back("Heavy Painkiller"); if (has_disease(DI_PKILL_L)) good.push_back("Slow-Release Painkiller"); if (has_disease(DI_DRUNK)) good.push_back("Alcohol"); if (has_disease(DI_CIG)) good.push_back("Nicotine"); if (has_disease(DI_HIGH)) good.push_back("Intoxicant: Other"); if (has_disease(DI_TOOK_PROZAC)) good.push_back("Prozac"); if (has_disease(DI_TOOK_FLUMED)) good.push_back("Antihistamines"); if (has_disease(DI_ADRENALINE)) good.push_back("Adrenaline Spike"); if (good.size() == 0 && bad.size() == 0) mvwprintz(w, 1, 1, c_white, "No effects."); else { for (unsigned int line = 1; line < 39 && line <= good.size() + bad.size(); line++) { if (line <= bad.size()) mvwprintz(w, line, 1, c_red, bad[line - 1].c_str()); else mvwprintz(w, line, 1, c_green, good[line - 1 - bad.size()].c_str()); } } wrefresh(w); refresh(); getch(); delwin(w); break; case bio_blood_filter: rem_disease(DI_FUNGUS); rem_disease(DI_POISON); rem_disease(DI_PKILL1); rem_disease(DI_PKILL2); rem_disease(DI_PKILL3); rem_disease(DI_PKILL_L); rem_disease(DI_DRUNK); rem_disease(DI_CIG); rem_disease(DI_HIGH); rem_disease(DI_TOOK_PROZAC); rem_disease(DI_TOOK_FLUMED); rem_disease(DI_ADRENALINE); break; case bio_evap: if (query_yn("Drink directly? Otherwise you will need a container.")) { tmp_item = item(g->itypes[itm_water], 0); thirst -= 50; if (has_trait(PF_GOURMAND) && thirst < -60) { g->add_msg("You can't finish it all!"); thirst = -60; } else if (!has_trait(PF_GOURMAND) && thirst < -20) { g->add_msg("You can't finish it all!"); thirst = -20; } } else { t = g->inv("Choose a container:"); if (i_at(t).type == 0) { g->add_msg("You don't have that item!"); power_level += bionics[bio_evap].power_cost; } else if (!i_at(t).is_container()) { g->add_msg("That %s isn't a container!", i_at(t).tname().c_str()); power_level += bionics[bio_evap].power_cost; } else { it_container *cont = dynamic_cast<it_container*>(i_at(t).type); if (i_at(t).volume_contained() + 1 > cont->contains) { g->add_msg("There's no space left in your %s.", i_at(t).tname().c_str()); power_level += bionics[bio_evap].power_cost; } else if (!(cont->flags & con_wtight)) { g->add_msg("Your %s isn't watertight!", i_at(t).tname().c_str()); power_level += bionics[bio_evap].power_cost; } else { g->add_msg("You pour water into your %s.", i_at(t).tname().c_str()); i_at(t).put_in(item(g->itypes[itm_water], 0)); } } } break; case bio_lighter: g->draw(); mvprintw(0, 0, "Torch in which direction?"); get_direction(g, dirx, diry, input()); if (dirx == -2) { g->add_msg("Invalid direction."); power_level += bionics[bio_lighter].power_cost; return; } dirx += posx; diry += posy; if (!g->m.add_field(g, dirx, diry, fd_fire, 1)) // Unsuccessful. g->add_msg("You can't light a fire there."); break; case bio_claws: if (weapon.type->id == itm_bio_claws) { g->add_msg("You withdraw your claws."); weapon = ret_null; } else if (weapon.type->id != 0) { g->add_msg("Your claws extend, forcing you to drop your %s.", weapon.tname().c_str()); g->m.add_item(posx, posy, weapon); weapon = item(g->itypes[itm_bio_claws], 0); weapon.invlet = '#'; } else { g->add_msg("Your claws extend!"); weapon = item(g->itypes[itm_bio_claws], 0); weapon.invlet = '#'; } break; case bio_blaster: tmp_item = weapon; weapon = item(g->itypes[itm_bio_blaster], 0); weapon.curammo = dynamic_cast<it_ammo*>(g->itypes[itm_bio_fusion]); weapon.charges = 1; g->refresh_all(); g->plfire(false); weapon = tmp_item; break; case bio_laser: tmp_item = weapon; weapon = item(g->itypes[itm_v29], 0); weapon.curammo = dynamic_cast<it_ammo*>(g->itypes[itm_laser_pack]); weapon.charges = 1; g->refresh_all(); g->plfire(false); weapon = tmp_item; break; case bio_emp: g->draw(); mvprintw(0, 0, "Fire EMP in which direction?"); get_direction(g, dirx, diry, input()); if (dirx == -2) { g->add_msg("Invalid direction."); power_level += bionics[bio_emp].power_cost; return; } dirx += posx; diry += posy; g->emp_blast(dirx, diry); break; case bio_hydraulics: g->add_msg("Your muscles hiss as hydraulic strength fills them!"); break; case bio_water_extractor: for (unsigned int i = 0; i < g->m.i_at(posx, posy).size(); i++) { item tmp = g->m.i_at(posx, posy)[i]; if (tmp.type->id == itm_corpse && query_yn("Extract water from the %s", tmp.tname().c_str())) { i = g->m.i_at(posx, posy).size() + 1; // Loop is finished t = g->inv("Choose a container:"); if (i_at(t).type == 0) { g->add_msg("You don't have that item!"); power_level += bionics[bio_water_extractor].power_cost; } else if (!i_at(t).is_container()) { g->add_msg("That %s isn't a container!", i_at(t).tname().c_str()); power_level += bionics[bio_water_extractor].power_cost; } else { it_container *cont = dynamic_cast<it_container*>(i_at(t).type); if (i_at(t).volume_contained() + 1 > cont->contains) { g->add_msg("There's no space left in your %s.", i_at(t).tname().c_str()); power_level += bionics[bio_water_extractor].power_cost; } else { g->add_msg("You pour water into your %s.", i_at(t).tname().c_str()); i_at(t).put_in(item(g->itypes[itm_water], 0)); } } } if (i == g->m.i_at(posx, posy).size() - 1) // We never chose a corpse power_level += bionics[bio_water_extractor].power_cost; } break; case bio_magnet: for (int i = posx - 10; i <= posx + 10; i++) { for (int j = posy - 10; j <= posy + 10; j++) { if (g->m.i_at(i, j).size() > 0) { if (g->m.sees(i, j, posx, posy, -1, t)) traj = line_to(i, j, posx, posy, t); else traj = line_to(i, j, posx, posy, 0); } traj.insert(traj.begin(), point(i, j)); for (unsigned int k = 0; k < g->m.i_at(i, j).size(); k++) { if (g->m.i_at(i, j)[k].made_of(IRON) || g->m.i_at(i, j)[k].made_of(STEEL)){ tmp_item = g->m.i_at(i, j)[k]; g->m.i_rem(i, j, k); for (l = 0; l < traj.size(); l++) { index = g->mon_at(traj[l].x, traj[l].y); if (index != -1) { if (g->z[index].hurt(tmp_item.weight() * 2)) g->kill_mon(index, true); g->m.add_item(traj[l].x, traj[l].y, tmp_item); l = traj.size() + 1; } else if (l > 0 && g->m.move_cost(traj[l].x, traj[l].y) == 0) { g->m.bash(traj[l].x, traj[l].y, tmp_item.weight() * 2, junk); g->sound(traj[l].x, traj[l].y, 12, junk); if (g->m.move_cost(traj[l].x, traj[l].y) == 0) { g->m.add_item(traj[l - 1].x, traj[l - 1].y, tmp_item); l = traj.size() + 1; } } } if (l == traj.size()) g->m.add_item(posx, posy, tmp_item); } } } } break; case bio_lockpick: g->draw(); mvprintw(0, 0, "Unlock in which direction?"); get_direction(g, dirx, diry, input()); if (dirx == -2) { g->add_msg("Invalid direction."); power_level += bionics[bio_lockpick].power_cost; return; } dirx += posx; diry += posy; if (g->m.ter(dirx, diry) == t_door_locked) { moves -= 40; g->add_msg("You unlock the door."); g->m.ter(dirx, diry) = t_door_c; } else g->add_msg("You can't unlock that %s.", g->m.tername(dirx, diry).c_str()); break; // Unused enums added for completeness. default: break; } }
// Resets plans (list of squares to visit) and builds it as a straight line // to the destination (x,y). t is used to choose which eligable line to use. // Currently, this assumes we can see (x,y), so shouldn't be used in any other // circumstance (or else the monster will "phase" through solid terrain!) void monster::set_dest(int x, int y, int &t) { plans.clear(); // TODO: This causes a segfault, once in a blue moon! Whyyyyy. plans = line_to(_posx, _posy, x, y, t); }
static cairo_status_t _cairo_stroker_curve_to (void *closure, const cairo_point_t *b, const cairo_point_t *c, const cairo_point_t *d) { cairo_stroker_t *stroker = closure; cairo_spline_t spline; cairo_line_join_t line_join_save; cairo_stroke_face_t face; double slope_dx, slope_dy; cairo_path_fixed_line_to_func_t *line_to; cairo_status_t status = CAIRO_STATUS_SUCCESS; line_to = stroker->dash.dashed ? _cairo_stroker_line_to_dashed : _cairo_stroker_line_to; if (! _cairo_spline_init (&spline, (cairo_spline_add_point_func_t)line_to, stroker, &stroker->current_point, b, c, d)) { return line_to (closure, d); } /* If the line width is so small that the pen is reduced to a single point, then we have nothing to do. */ if (stroker->pen.num_vertices <= 1) return CAIRO_STATUS_SUCCESS; /* Compute the initial face */ if (! stroker->dash.dashed || stroker->dash.dash_on) { slope_dx = _cairo_fixed_to_double (spline.initial_slope.dx); slope_dy = _cairo_fixed_to_double (spline.initial_slope.dy); if (_compute_normalized_device_slope (&slope_dx, &slope_dy, stroker->ctm_inverse, NULL)) { _compute_face (&stroker->current_point, &spline.initial_slope, slope_dx, slope_dy, stroker, &face); } if (stroker->has_current_face) { status = _cairo_stroker_join (stroker, &stroker->current_face, &face); if (unlikely (status)) return status; } else if (! stroker->has_first_face) { stroker->first_face = face; stroker->has_first_face = TRUE; } stroker->current_face = face; stroker->has_current_face = TRUE; } /* Temporarily modify the stroker to use round joins to guarantee * smooth stroked curves. */ line_join_save = stroker->style.line_join; stroker->style.line_join = CAIRO_LINE_JOIN_ROUND; status = _cairo_spline_decompose (&spline, stroker->tolerance); if (unlikely (status)) return status; /* And join the final face */ if (! stroker->dash.dashed || stroker->dash.dash_on) { slope_dx = _cairo_fixed_to_double (spline.final_slope.dx); slope_dy = _cairo_fixed_to_double (spline.final_slope.dy); if (_compute_normalized_device_slope (&slope_dx, &slope_dy, stroker->ctm_inverse, NULL)) { _compute_face (&stroker->current_point, &spline.final_slope, slope_dx, slope_dy, stroker, &face); } status = _cairo_stroker_join (stroker, &stroker->current_face, &face); if (unlikely (status)) return status; stroker->current_face = face; } stroker->style.line_join = line_join_save; return CAIRO_STATUS_SUCCESS; }
void monster::explode() { if( is_hallucination() ) { //Can't gib hallucinations return; } if( type->has_flag( MF_NOGIB ) || type->has_flag( MF_VERMIN ) ) { return; } // Send body parts and blood all over! const itype_id meat = type->get_meat_itype(); const field_id type_blood = bloodType(); const field_id type_gib = gibType(); if( meat != "null" || type_blood != fd_null || type_gib != fd_null ) { // Only create chunks if we know what kind to make. int num_chunks = 0; switch( type->size ) { case MS_TINY: num_chunks = 1; break; case MS_SMALL: num_chunks = 2; break; case MS_MEDIUM: num_chunks = 4; break; case MS_LARGE: num_chunks = 8; break; case MS_HUGE: num_chunks = 16; break; } for( int i = 0; i < num_chunks; i++ ) { int tarx = _posx + rng( -3, 3 ), tary = _posy + rng( -3, 3 ); std::vector<point> traj = line_to( _posx, _posy, tarx, tary, 0 ); for( size_t j = 0; j < traj.size(); j++ ) { tarx = traj[j].x; tary = traj[j].y; if( one_in( 2 ) && type_blood != fd_null ) { g->m.add_field( tarx, tary, type_blood, 1 ); } else if( type_gib != fd_null ) { g->m.add_field( tarx, tary, type_gib, rng( 1, j + 1 ) ); } if( g->m.move_cost( tarx, tary ) == 0 ) { if( !g->m.bash( tarx, tary, 3 ).second ) { // Target is obstacle, not destroyed by bashing, // stop trajectory in front of it, if this is the first // point (e.g. wall adjacent to monster) , make it invalid. if( j > 0 ) { tarx = traj[j - 1].x; tary = traj[j - 1].y; } else { tarx = -1; } break; } } } if( meat != "null" && tarx != -1 ) { g->m.spawn_item( tarx, tary, meat, 1, 0, calendar::turn ); } } } }