void effect::drawcone(vec &o, vec dir, vec &axis, int angle, float radius, float size, int type, int elapse) { if(size <= 0) return; size *= this->size; int fade, gravity, num; setvars(this, type, fade, gravity, num); num *= angle * (particle == PART_STREAK || particle == PART_LIGHTNING ? 1 : partmul) / size / 30 * (elapse ? logf(elapse) / 3 : 1); num = max<int>(1, num); loopi(num) { vec ray = vec(dir).rotate(rnd(angle + 1) * RAD, axis).rotate(rnd(360), dir).mul(radius); switch(particle) { case PART_EXPLOSION: case PART_EXPLOSION_BLUE: ray.mul(rnd(101)/100.f).add(o); particle_fireball(ray, size, particle, fade, colour, size); break; case PART_STREAK: case PART_LIGHTNING: if(!curtime) return; particle_flare(o, ray.add(o), fade, particle, colour, size); break; default: ray.mul(rnd(101)/100.f).add(o); particle_splash(particle, 2, fade, ray, colour, size, max<int>(1, size * 2), gravity); break; } } }
void effect::drawaura(rpgent *d, float size, int type, int elapse) { if(size <= 0) return; size *= this->size; int fade, gravity, num; setvars(this, type, fade, gravity, num); num *= .2 * PI * d->radius / (1 + size) * partmul * (elapse ? logf(elapse) / 3 : 1); if(elapse && !num && rnd(int(10 / partmul))) return; //sometimes particles should not be drawn num = max<int>(1, num); loopi(num) { vec pos = vec(rnd(360) * RAD, 0).mul(d->radius + size).add(d->feetpos()); switch(particle) { case PART_EXPLOSION: case PART_EXPLOSION_BLUE: particle_fireball(pos, size, particle, fade, colour, size); break; case PART_STREAK: case PART_LIGHTNING: if(!curtime) return; particle_flare(pos, vec(0, 0, d->eyeheight + d->aboveeye).add(pos), fade, particle, colour, size); break; default: if(gravity >= 0) pos.add(vec(0, 0, d->eyeheight + d->aboveeye)); particle_splash(particle, 2, fade, pos, colour, size, max<int>(1, size * 2), gravity); break; } } }
void effect::drawwield(vec &from, vec &to, float size, int type, int elapse) { if(size <= 0) return; if(particle == PART_STREAK || particle == PART_LIGHTNING) { drawline(from, to, size, type, elapse); return; } size *= this->size; int fade, gravity, num; setvars(this, type, fade, gravity, num); num *= partmul * (elapse ? (logf(elapse) / 3) : 1) / (1 + size); if(elapse && !num && rnd(int(10 / partmul))) return; num = max<int>(1, num); vec delta = vec(to).sub(from); loopi(num) { vec pt = vec(delta).mul((float) rnd(0x10000) / 0xFFFF).add(from); switch(particle) { case PART_EXPLOSION: case PART_EXPLOSION_BLUE: particle_fireball(pt, size * 2, particle, fade, colour, size * 4); break; default: particle_splash(particle, 2, fade, pt, colour, size, max<int>(1, size * 5), gravity); } } }
void rpgent::tryattack(vec &lookatpos, rpgobj &weapon) { if(lastmillis-lastaction<weapon.s_attackrate) return; lastaction = lastmillis; switch(weapon.s_usetype) { case 1: if(!weapon.s_damage) return; weapon.usesound(this); loopallrpgobjsexcept(ro) tryattackobj(*eo, weapon); break; case 2: { if(!weapon.s_damage) return; weapon.usesound(this); particle_splash(PART_SPARK, 200, 250, lookatpos, 0xB49B4B, 0.24f); vec flarestart = o; flarestart.z -= 2; particle_flare(flarestart, lookatpos, 600, PART_STREAK, 0xFFC864, 0.28f); // FIXME hudgunorigin(), and shorten to maxrange float bestdist = 1e16f; rpgobj *best = NULL; loopallrpgobjsexcept(ro) { if(eo->ent->state!=CS_ALIVE) continue; if(!intersect(eo->ent, o, lookatpos)) continue; float dist = o.dist(eo->ent->o); if(dist<weapon.s_maxrange && dist<bestdist) { best = eo; bestdist = dist; } } if(best) weapon.useaction(*best, *this, true); break; } case 3: if(weapon.s_maxrange) // projectile, cast on target { if(magicprojectile) return; // only one in the air at once if(!ro->usemana(weapon)) return; magicprojectile = true; mpweapon = &weapon; mppos = o; //mpdir = vec(yaw*RAD, pitch*RAD); float worlddist = lookatpos.dist(o, mpdir); mpdir.normalize(); mpdist = min(float(weapon.s_maxrange), worlddist); } else { weapon.useaction(*ro, *this, true); // cast on self } break; } }
void effect::drawsplash(vec &o, vec dir, float radius, float size, int type, int elapse) { if(size <= 0) return; size *= this->size; int fade, gravity, num; setvars(this, type, fade, gravity, num); num *= .1 * radius / (1 + size) * partmul * (elapse ? logf(elapse) / 3 : 1); if(elapse && !num && rnd(int(10 / partmul))) return; //sometimes particles should not be drawn num = max(1, num); switch(particle) { case PART_EXPLOSION: case PART_EXPLOSION_BLUE: particle_fireball(o, radius ? radius : size, particle, fade, colour, size); break; case PART_STREAK: case PART_LIGHTNING: if(!curtime) break; if(!radius) //assume num == 1 { vec offset = vec(dir).mul(-2 * size).add(o); particle_flare(offset, o, fade, particle, colour, size); } else { num = (num / 2 + num % 2); loopi(num) { vec offset = vec(rnd(360) * RAD, (90 - rnd(180)) * RAD).mul(radius); vec offset2 = vec(rnd(360) * RAD, rnd(360) * RAD).mul(radius); particle_flare(vec(o).sub(offset), vec(o).add(offset2), fade, particle, colour, size); } } break; default: particle_splash(particle, num, fade, o, colour, size, max<int>(1, radius), gravity); break; } }
bool effect::drawline(vec &from, vec &to, float size, int type, int elapse) { if(size <= 0) return false; size *= this->size; int fade, gravity, num; setvars(this, type, fade, gravity, num); num *= from.dist(to) / (10 * size) * partmul * (elapse ? logf(elapse) / 3 : 1); if(particle == PART_STREAK || particle == PART_LIGHTNING) num /= 2; num = min<int>(min(num, linemaxsteps), from.dist(to) / linemininterval); if(!num) return false; vec delta = vec(to).sub(from).div(num); loopi(num) { switch(particle) { case PART_EXPLOSION: case PART_EXPLOSION_BLUE: particle_fireball(from, size * 2, particle, fade, colour, size * 2); break; case PART_STREAK: case PART_LIGHTNING: { if(!curtime) return false; vec start = vec(rnd(360) * RAD, rnd(360) * RAD).mul(4 * size).add(from); vec end = vec(delta).mul(1.5).add(start); particle_flare(start, end, fade, particle, colour, size); break; } default: particle_splash(particle, 2, fade, from, colour, size, max<int>(1, size * 5), gravity); break; } from.add(delta); } return true; }
void rpgent::updateprojectile() { if(!magicprojectile) return; regular_particle_splash(PART_SMOKE, 2, 300, mppos, 0x404040, 0.6f, 150, -20); particle_splash(PART_FIREBALL1+mpweapon->s_effectparticle, 1, 1, mppos, mpweapon->s_effectcolor, mpweapon->s_effectsize/100.0f); float dist = curtime/5.0f; if((mpdist -= dist)<0) { magicprojectile = false; return; }; vec mpto = vec(mpdir).mul(dist).add(mppos); loopallrpgobjsexcept(ro) // FIXME: make fast "give me all rpgobs in range R that are not X" function { if(eo->ent->o.dist(mppos)<32 && intersect(eo->ent, mppos, mpto)) // quick reject, for now { magicprojectile = false; mpweapon->useaction(*eo, *this, false); // cast on target } } mppos = mpto; }
void demoplaybackstep() { while(demoplayback && lastmillis>=playbacktime) { int len = gzgeti(); if(len<1 || len>MAXTRANS) { conoutf("error: huge packet during demo play (%d)", len); stopreset(); return; }; uchar buf[MAXTRANS]; gzread(f, buf, len); localservertoclient(buf, len); // update game state dynent *target = players[democlientnum]; assert(target); int extras; if(extras = gzget()) // read additional client side state not present in normal network stream { target->gunselect = gzget(); target->lastattackgun = gzget(); target->lastaction = scaletime(gzgeti()); target->gunwait = gzgeti(); target->health = gzgeti(); target->armour = gzgeti(); target->armourtype = gzget(); loopi(NUMGUNS) target->ammo[i] = gzget(); target->state = gzget(); target->lastmove = playbacktime; if(bdamage = gzgeti()) damageblend(bdamage); if(ddamage = gzgeti()) { gzgetv(dorig); particle_splash(3, ddamage, 1000, dorig); }; // FIXME: set more client state here }; // insert latest copy of player into history if(extras && (playerhistory.empty() || playerhistory.last()->lastupdate!=playbacktime)) { dynent *d = newdynent(); *d = *target; d->lastupdate = playbacktime; playerhistory.add(d); if(playerhistory.length()>20) { zapdynent(playerhistory[0]); playerhistory.remove(0); }; }; readdemotime(); }; if(demoplayback) { int itime = lastmillis-demodelaymsec; loopvrev(playerhistory) if(playerhistory[i]->lastupdate<itime) // find 2 positions in history that surround interpolation time point { dynent *a = playerhistory[i]; dynent *b = a; if(i+1<playerhistory.length()) b = playerhistory[i+1]; *player1 = *b; if(a!=b) // interpolate pos & angles { dynent *c = b; if(i+2<playerhistory.length()) c = playerhistory[i+2]; dynent *z = a; if(i-1>=0) z = playerhistory[i-1]; //if(a==z || b==c) printf("* %d\n", lastmillis); float bf = (itime-a->lastupdate)/(float)(b->lastupdate-a->lastupdate); fixwrap(a, player1); fixwrap(c, player1); fixwrap(z, player1); vdist(dist, v, z->o, c->o); if(dist<16) // if teleport or spawn, dont't interpolate { catmulrom(z->o, a->o, b->o, c->o, bf, player1->o); catmulrom(*(vec *)&z->yaw, *(vec *)&a->yaw, *(vec *)&b->yaw, *(vec *)&c->yaw, bf, *(vec *)&player1->yaw); }; fixplayer1range(); }; break; }; //if(player1->state!=CS_DEAD) showscores(false); }; };
void TargetingControl::determineMouseTarget(bool forceEntityCheck) { targetLogicEntity = NULL; TargetingControl::worldPosition = worldpos; if (logger::should_log(logger::INFO)) particle_splash(0, 50, 100, TargetingControl::worldPosition); // Kripken: Show some sparkles where the mouse points - for debug if (!editmode && !forceEntityCheck) { TargetingControl::targetLogicEntity = NULL; TargetingControl::targetPosition = TargetingControl::worldPosition; has_mouse_target = 0; } else { static long lastEntityCheck = -1; // Use this to not run an actual entity check more than 1/frame if (lastEntityCheck != lastmillis) { float dist; TargetingControl::intersectClosest(camera1->o, worldpos, camera1, dist, TargetingControl::targetLogicEntity); // If not edit mode, ignore the player itself if (!editmode && TargetingControl::targetLogicEntity && !TargetingControl::targetLogicEntity->isNone() && TargetingControl::targetLogicEntity->getUniqueId() == ClientSystem::uniqueId) { // Try to see if the player was the sole cause of collision - move it away, test, then move it back vec save = ClientSystem::playerLogicEntity->dynamicEntity->o; ClientSystem::playerLogicEntity->dynamicEntity->o.add(10000.0); TargetingControl::intersectClosest(camera1->o, worldpos, camera1, dist, TargetingControl::targetLogicEntity); ClientSystem::playerLogicEntity->dynamicEntity->o = save; } has_mouse_target = int(TargetingControl::targetLogicEntity && !TargetingControl::targetLogicEntity->isNone()); if (has_mouse_target) { vec temp(worldpos); temp.sub(camera1->o); temp.normalize(); temp.mul(dist); temp.add(camera1->o); TargetingControl::targetPosition = temp; } else TargetingControl::targetPosition = TargetingControl::worldPosition; lastEntityCheck = lastmillis; } } }