static void Paint_self_radar(double xf, double yf) { int x, y, x_1, y_1, xw, yw; if (selfVisible != 0 && loops % 16 < 13) { x = (int)(selfPos.x * xf + 0.5) - slidingradar_x; y = RadarHeight - (int)(selfPos.y * yf + 0.5) - 1 - slidingradar_y; if (x <= 0) x += 256; if (y <= 0) y += RadarHeight; x_1 = (int)(x + 8 * tcos(heading)); y_1 = (int)(y - 8 * tsin(heading)); XDrawLine(dpy, radarPixmap, radarGC, x, y, x_1, y_1); if (BIT(Setup->mode, WRAP_PLAY)) { xw = x_1 - (x_1 + 256) % 256; yw = y_1 - (y_1 + RadarHeight) % RadarHeight; if (xw != 0) XDrawLine(dpy, radarPixmap, radarGC, x - xw, y, x_1 - xw, y_1); if (yw != 0) { XDrawLine(dpy, radarPixmap, radarGC, x, y - yw, x_1, y_1 - yw); if (xw != 0) XDrawLine(dpy, radarPixmap, radarGC, x - xw, y - yw, x_1 - xw, y_1 - yw); } } } }
void Cannon_throw_items(cannon_t *c) { int i, dir; itemobject_t *item; double velocity; for (i = 0; i < NUM_ITEMS; i++) { if (i == ITEM_FUEL) continue; c->item[i] -= Cannon_get_initial_item(c, (Item_t)i); while (c->item[i] > 0) { int amount = world->items[i].max_per_pack - (int)(rfrac() * (1 + world->items[i].max_per_pack - world->items[i].min_per_pack)); LIMIT(amount, 0, c->item[i]); if (rfrac() < (options.dropItemOnKillProb * CANNON_DROP_ITEM_PROB) && (item = ITEM_PTR(Object_allocate())) != NULL) { item->type = OBJ_ITEM; item->item_type = i; item->color = RED; item->obj_status = GRAVITY; dir = (int)(c->dir - (CANNON_SPREAD * 0.5) + (rfrac() * CANNON_SPREAD)); dir = MOD2(dir, RES); item->id = NO_ID; item->team = TEAM_NOT_SET; Object_position_init_clpos(OBJ_PTR(item), c->pos); velocity = rfrac() * 6; item->vel.x = tcos(dir) * velocity; item->vel.y = tsin(dir) * velocity; item->acc.x = 0; item->acc.y = 0; item->mass = 10; item->life = 1500 + rfrac() * 512; item->item_count = amount; item->pl_range = ITEM_SIZE / 2; item->pl_radius = ITEM_SIZE / 2; world->items[i].num++; Cell_add_object(OBJ_PTR(item)); } c->item[i] -= amount; } } }
/* does the actual firing. also determines in which way to use weapons that have more than one possible use. */ static void Cannon_fire(cannon_t *c, int weapon, player_t *pl, int dir) { modifiers_t mods; bool played = false; int i, smartness = Cannon_get_smartness(c); double speed = Cannon_get_shot_speed(c); vector_t zero_vel = { 0.0, 0.0 }; Mods_clear(&mods); switch (weapon) { case CW_MINE: if (rfrac() < 0.25) Mods_set(&mods, ModsCluster, 1); if (rfrac() >= 0.2) Mods_set(&mods, ModsImplosion, 1); Mods_set(&mods, ModsPower, (int)(rfrac() * (MODS_POWER_MAX + 1))); Mods_set(&mods, ModsVelocity, (int)(rfrac() * (MODS_VELOCITY_MAX + 1))); if (rfrac() < 0.5) { /* place mine in front of cannon */ Place_general_mine(c->id, c->team, FROMCANNON, c->pos, zero_vel, mods); sound_play_sensors(c->pos, DROP_MINE_SOUND); played = true; } else { /* throw mine at player */ vector_t vel; Mods_set(&mods, ModsMini, (int)(rfrac() * MODS_MINI_MAX) + 1); Mods_set(&mods, ModsSpread, (int)(rfrac() * (MODS_SPREAD_MAX + 1))); speed = speed * 0.5 + 0.1 * smartness; vel.x = tcos(dir) * speed; vel.y = tsin(dir) * speed; Place_general_mine(c->id, c->team, GRAVITY|FROMCANNON, c->pos, vel, mods); sound_play_sensors(c->pos, DROP_MOVING_MINE_SOUND); played = true; } c->item[ITEM_MINE]--; break; case CW_MISSILE: if (rfrac() < 0.333) Mods_set(&mods, ModsCluster, 1); if (rfrac() >= 0.25) Mods_set(&mods, ModsImplosion, 1); Mods_set(&mods, ModsPower, (int)(rfrac() * (MODS_POWER_MAX + 1))); Mods_set(&mods, ModsVelocity, (int)(rfrac() * (MODS_VELOCITY_MAX + 1))); /* Because cannons don't have missile racks, all mini missiles would be fired from the same point and appear to the players as 1 missile (except heatseekers, which would appear to split in midair because of navigation errors (see Move_smart_shot)). Therefore, we don't minify cannon missiles. mods.mini = (int)(rfrac() * MODS_MINI_MAX) + 1; mods.spread = (int)(rfrac() * (MODS_SPREAD_MAX + 1)); */ /* smarter cannons use more advanced missile types */ switch ((int)(rfrac() * (1 + smartness))) { default: if (options.allowSmartMissiles) { Fire_general_shot(c->id, c->team, c->pos, OBJ_SMART_SHOT, dir, mods, pl->id); sound_play_sensors(c->pos, FIRE_SMART_SHOT_SOUND); played = true; break; } /* FALLTHROUGH */ case 1: if (options.allowHeatSeekers && Player_is_thrusting(pl)) { Fire_general_shot(c->id, c->team, c->pos, OBJ_HEAT_SHOT, dir, mods, pl->id); sound_play_sensors(c->pos, FIRE_HEAT_SHOT_SOUND); played = true; break; } /* FALLTHROUGH */ case 0: Fire_general_shot(c->id, c->team, c->pos, OBJ_TORPEDO, dir, mods, NO_ID); sound_play_sensors(c->pos, FIRE_TORPEDO_SOUND); played = true; break; } c->item[ITEM_MISSILE]--; break; case CW_LASER: /* stun and blinding lasers are very dangerous, so we don't use them often */ if ((rfrac() * (8 - smartness)) >= 1) Mods_set(&mods, ModsLaser, (int)(rfrac() * (MODS_LASER_MAX + 1))); Fire_general_laser(c->id, c->team, c->pos, dir, mods); sound_play_sensors(c->pos, FIRE_LASER_SOUND); played = true; break; case CW_ECM: Fire_general_ecm(c->id, c->team, c->pos); c->item[ITEM_ECM]--; sound_play_sensors(c->pos, ECM_SOUND); played = true; break; case CW_TRACTORBEAM: /* smarter cannons use tractors more often and also push/pull longer */ c->tractor_is_pressor = (rfrac() * (smartness + 1) >= 1); c->tractor_target_id = pl->id; c->tractor_count = 11 + rfrac() * (3 * smartness + 1); break; case CW_TRANSPORTER: c->item[ITEM_TRANSPORTER]--; if (Wrap_length(pl->pos.cx - c->pos.cx, pl->pos.cy - c->pos.cy) < TRANSPORTER_DISTANCE * CLICK) { int item = -1; double amount = 0.0; Do_general_transporter(c->id, c->pos, pl, &item, &amount); if (item != -1) Cannon_add_item(c, item, amount); } else { sound_play_sensors(c->pos, TRANSPORTER_FAIL_SOUND); played = true; } break; case CW_GASJET: /* use emergency thrusts to make extra big jets */ if ((rfrac() * (c->item[ITEM_EMERGENCY_THRUST] + 1)) >= 1) { Make_debris(c->pos, zero_vel, NO_ID, c->team, OBJ_SPARK, THRUST_MASS, GRAVITY|FROMCANNON, RED, 8, (int)(300 + 400 * rfrac()), dir - 4 * (4 - smartness), dir + 4 * (4 - smartness), 0.1, speed * 4, 3.0, 20.0); c->item[ITEM_EMERGENCY_THRUST]--; } else { Make_debris(c->pos, zero_vel, NO_ID, c->team, OBJ_SPARK, THRUST_MASS, GRAVITY|FROMCANNON, RED, 8, (int)(150 + 200 * rfrac()), dir - 3 * (4 - smartness), dir + 3 * (4 - smartness), 0.1, speed * 2, 3.0, 20.0); } c->item[ITEM_FUEL]--; sound_play_sensors(c->pos, THRUST_SOUND); played = true; break; case CW_SHOT: default: if (options.cannonFlak) Mods_set(&mods, ModsCluster, 1); /* smarter cannons fire more accurately and can therefore narrow their bullet streams */ for (i = 0; i < (1 + 2 * c->item[ITEM_WIDEANGLE]); i++) { int a_dir = dir + (4 - smartness) * (-c->item[ITEM_WIDEANGLE] + i); a_dir = MOD2(a_dir, RES); Fire_general_shot(c->id, c->team, c->pos, OBJ_CANNON_SHOT, a_dir, mods, NO_ID); } /* I'm not sure cannons should use rearshots. After all, they are restricted to 60 degrees when picking their target. */ for (i = 0; i < c->item[ITEM_REARSHOT]; i++) { int a_dir = (int)(dir + (RES / 2) + (4 - smartness) * (-((c->item[ITEM_REARSHOT] - 1) * 0.5) + i)); a_dir = MOD2(a_dir, RES); Fire_general_shot(c->id, c->team, c->pos, OBJ_CANNON_SHOT, a_dir, mods, NO_ID); } } /* finally, play sound effect */ if (!played) { sound_play_sensors(c->pos, CANNON_FIRE_SOUND); } }
static void ashiksamp( /* sample anisotropic Ashikhmin-Shirley specular */ ASHIKDAT *np ) { RAY sr; FVECT h; double rv[2], dtmp; double cosph, sinph, costh, sinth; int maxiter, ntrials, nstarget, nstaken; int i; if (np->specfl & SPA_BADU || rayorigin(&sr, SPECULAR, np->rp, np->scolor) < 0) return; nstarget = 1; if (specjitter > 1.5) { /* multiple samples? */ nstarget = specjitter*np->rp->rweight + .5; if (sr.rweight <= minweight*nstarget) nstarget = sr.rweight/minweight; if (nstarget > 1) { dtmp = 1./nstarget; scalecolor(sr.rcoef, dtmp); sr.rweight *= dtmp; } else nstarget = 1; } dimlist[ndims++] = (int)(size_t)np->mp; maxiter = MAXITER*nstarget; for (nstaken = ntrials = 0; nstaken < nstarget && ntrials < maxiter; ntrials++) { if (ntrials) dtmp = frandom(); else dtmp = urand(ilhash(dimlist,ndims)+647+samplendx); multisamp(rv, 2, dtmp); dtmp = 2.*PI * rv[0]; cosph = sqrt(np->v_power + 1.) * tcos(dtmp); sinph = sqrt(np->u_power + 1.) * tsin(dtmp); dtmp = 1./sqrt(cosph*cosph + sinph*sinph); cosph *= dtmp; sinph *= dtmp; costh = pow(rv[1], 1./(np->u_power*cosph*cosph+np->v_power*sinph*sinph+1.)); if (costh <= FTINY) continue; sinth = sqrt(1. - costh*costh); for (i = 0; i < 3; i++) h[i] = cosph*sinth*np->u[i] + sinph*sinth*np->v[i] + costh*np->pnorm[i]; if (nstaken) rayclear(&sr); dtmp = -2.*DOT(h, np->rp->rdir); VSUM(sr.rdir, np->rp->rdir, h, dtmp); /* sample rejection test */ if (DOT(sr.rdir, np->rp->ron) <= FTINY) continue; checknorm(sr.rdir); rayvalue(&sr); multcolor(sr.rcol, sr.rcoef); addcolor(np->rp->rcol, sr.rcol); ++nstaken; } ndims--; }
static void agaussamp( /* sample anisotropic Gaussian specular */ ANISODAT *np ) { RAY sr; FVECT h; double rv[2]; double d, sinp, cosp; COLOR scol; int maxiter, ntrials, nstarget, nstaken; int i; /* compute reflection */ if ((np->specfl & (SP_REFL|SP_RBLT)) == SP_REFL && rayorigin(&sr, SPECULAR, np->rp, np->scolor) == 0) { nstarget = 1; if (specjitter > 1.5) { /* multiple samples? */ nstarget = specjitter*np->rp->rweight + .5; if (sr.rweight <= minweight*nstarget) nstarget = sr.rweight/minweight; if (nstarget > 1) { d = 1./nstarget; scalecolor(sr.rcoef, d); sr.rweight *= d; } else nstarget = 1; } setcolor(scol, 0., 0., 0.); dimlist[ndims++] = (int)(size_t)np->mp; maxiter = MAXITER*nstarget; for (nstaken = ntrials = 0; nstaken < nstarget && ntrials < maxiter; ntrials++) { if (ntrials) d = frandom(); else d = urand(ilhash(dimlist,ndims)+samplendx); multisamp(rv, 2, d); d = 2.0*PI * rv[0]; cosp = tcos(d) * np->u_alpha; sinp = tsin(d) * np->v_alpha; d = 1./sqrt(cosp*cosp + sinp*sinp); cosp *= d; sinp *= d; if ((0. <= specjitter) & (specjitter < 1.)) rv[1] = 1.0 - specjitter*rv[1]; if (rv[1] <= FTINY) d = 1.0; else d = sqrt(-log(rv[1]) / (cosp*cosp/(np->u_alpha*np->u_alpha) + sinp*sinp/(np->v_alpha*np->v_alpha))); for (i = 0; i < 3; i++) h[i] = np->pnorm[i] + d*(cosp*np->u[i] + sinp*np->v[i]); d = -2.0 * DOT(h, np->rp->rdir) / (1.0 + d*d); VSUM(sr.rdir, np->rp->rdir, h, d); /* sample rejection test */ if ((d = DOT(sr.rdir, np->rp->ron)) <= FTINY) continue; checknorm(sr.rdir); if (nstarget > 1) { /* W-G-M-D adjustment */ if (nstaken) rayclear(&sr); rayvalue(&sr); d = 2./(1. + np->rp->rod/d); scalecolor(sr.rcol, d); addcolor(scol, sr.rcol); } else { rayvalue(&sr); multcolor(sr.rcol, sr.rcoef); addcolor(np->rp->rcol, sr.rcol); } ++nstaken; } if (nstarget > 1) { /* final W-G-M-D weighting */ multcolor(scol, sr.rcoef); d = (double)nstarget/ntrials; scalecolor(scol, d); addcolor(np->rp->rcol, scol); } ndims--; } /* compute transmission */ copycolor(sr.rcoef, np->mcolor); /* modify by material color */ scalecolor(sr.rcoef, np->tspec); if ((np->specfl & (SP_TRAN|SP_TBLT)) == SP_TRAN && rayorigin(&sr, SPECULAR, np->rp, sr.rcoef) == 0) { nstarget = 1; if (specjitter > 1.5) { /* multiple samples? */ nstarget = specjitter*np->rp->rweight + .5; if (sr.rweight <= minweight*nstarget) nstarget = sr.rweight/minweight; if (nstarget > 1) { d = 1./nstarget; scalecolor(sr.rcoef, d); sr.rweight *= d; } else nstarget = 1; } dimlist[ndims++] = (int)(size_t)np->mp; maxiter = MAXITER*nstarget; for (nstaken = ntrials = 0; nstaken < nstarget && ntrials < maxiter; ntrials++) { if (ntrials) d = frandom(); else d = urand(ilhash(dimlist,ndims)+1823+samplendx); multisamp(rv, 2, d); d = 2.0*PI * rv[0]; cosp = tcos(d) * np->u_alpha; sinp = tsin(d) * np->v_alpha; d = 1./sqrt(cosp*cosp + sinp*sinp); cosp *= d; sinp *= d; if ((0. <= specjitter) & (specjitter < 1.)) rv[1] = 1.0 - specjitter*rv[1]; if (rv[1] <= FTINY) d = 1.0; else d = sqrt(-log(rv[1]) / (cosp*cosp/(np->u_alpha*np->u_alpha) + sinp*sinp/(np->v_alpha*np->v_alpha))); for (i = 0; i < 3; i++) sr.rdir[i] = np->prdir[i] + d*(cosp*np->u[i] + sinp*np->v[i]); if (DOT(sr.rdir, np->rp->ron) >= -FTINY) continue; normalize(sr.rdir); /* OK, normalize */ if (nstaken) /* multi-sampling */ rayclear(&sr); rayvalue(&sr); multcolor(sr.rcol, sr.rcoef); addcolor(np->rp->rcol, sr.rcol); ++nstaken; } ndims--; } }