Asteroids

This commit is contained in:
Zeno Rogue 2019-03-30 17:51:37 +01:00
parent 4727e71590
commit 5356eba11c
12 changed files with 216 additions and 34 deletions

View File

@ -1257,6 +1257,10 @@ LAND( 0x30FF30, "Irradiated Field", laVariant, ZERO, itVarTreasure, RESERVED,
// add new content here
LAND( 0x202020, "Asteroids", laAsteroids, ZERO, itAsteroid, RESERVED, NODESCYET)
ITEM( '*', 0xFFFFFF, "Ice Diamond", itAsteroid, IC_TREASURE, ZERO, RESERVED, osNone, NODESCYET)
MONSTER('A', 0x606040, "Asteroid", moAsteroid, ZERO, RESERVED, moAsteroid, NODESCYET)
//shmupspecials
MONSTER( '@', 0xC0C0C0, "Rogue", moPlayer, ZERO | CF_PLAYER, RESERVED, moNone, "In the Shoot'em Up mode, you are armed with thrown Knives.")
MONSTER( '*', 0xC0C0C0, "Knife", moBullet, ZERO | CF_BULLET, RESERVED, moNone, "A simple, but effective, missile, used by rogues.")

View File

@ -888,7 +888,7 @@ bool passable_for(eMonster m, cell *w, cell *from, flagtype extra) {
if(m == moPair)
return !(w && from && againstPair(from, w, m)) && passable(w, from, extra);
if(m == passive_switch) return false;
if(minf[m].mgroup == moYeti || isBug(m) || isDemon(m) || m == moHerdBull || m == moMimic) {
if(minf[m].mgroup == moYeti || isBug(m) || isDemon(m) || m == moHerdBull || m == moMimic || m == moAsteroid) {
if((isWitch(m) || m == moEvilGolem) && w->land != laPower && w->land != laHalloween)
return false;
return passable(w, from, extra);
@ -6958,6 +6958,7 @@ bool collectItem(cell *c2, bool telekinesis) {
else playSound(c2, "pickup-orb");
if(items[itOrbChoice]) items[itOrbChoice] = 0, had_choice = true;
int oc = orbcharges(it);
if(c2->land == laAsteroids) oc = 10;
if(markOrb(itOrbIntensity)) oc = oc * 6 / 5;
if(!items[it]) items[it]++;
items[it] += oc;

View File

@ -27,6 +27,8 @@ ld hexshift;
ld sword_size = 0;
ld asteroid_size[8];
// the results are:
// hexf = 0.378077 hcrossf = 0.620672 tessf = 1.090550
// hexhexdist = 0.566256

View File

@ -1891,6 +1891,11 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, color_t col,
ShadowV(V, shTentHead, PPR::GIANTSHADOW);
return false;
}
case moAsteroid: {
queuepoly(V, shAsteroid[1], darkena(col, 0, 0xFF));
return false;
}
default: ;
}

View File

@ -233,6 +233,7 @@ constexpr transmatrix diag(ld a, ld b, ld c, ld d) {
#endif
}
const static hyperpoint Hypc = hyperpoint(0, 0, 0, 0);
// identity matrix
const static transmatrix Id = diag(1,1,1,1);
@ -898,18 +899,19 @@ namespace shmup {
eMonster parenttype; // type of the parent
int nextshot; // when will it be able to shot (players/flailers)
int pid; // player ID
char hitpoints;
int hitpoints; // hitpoints; or time elapsed in Asteroids
int stunoff;
int blowoff;
double swordangle; // sword angle wrt at
double vel; // velocity, for flail balls
double footphase;
bool isVirtual; // off the screen: gmatrix is unknown, and pat equals at
hyperpoint inertia;// for frictionless lands
monster() {
dead = false; inBoat = false; parent = NULL; nextshot = 0;
stunoff = 0; blowoff = 0; footphase = 0; no_targetting = false;
swordangle = 0;
swordangle = 0; inertia = Hypc;
}
void store();
@ -1641,6 +1643,7 @@ void destroyBoats(cell *c, cell *cf, bool strandedToo);
extern bool showoff;
extern int lastexplore;
extern int truelotus;
extern int asteroids_generated, asteroid_orbs_generated;
extern eLand lastland;
extern time_t timerstart;
extern bool timerstopped;

View File

@ -136,9 +136,6 @@ hyperpoint hpxy3(ld x, ld y, ld z) {
return hpxyz3(x,y,z, euclid ? 1 : sphere ? sqrt(1-x*x-y*y-z*z) : sqrt(1+x*x+y*y+z*z));
}
// center of the pseudosphere
const hyperpoint Hypc = hyperpoint(0,0,0,0);
// origin of the hyperbolic plane
const hyperpoint C02 = hyperpoint(0,0,1,0);
const hyperpoint C03 = hyperpoint(0,0,0,1);
@ -241,6 +238,16 @@ transmatrix cspin(int a, int b, ld alpha) {
transmatrix spin(ld alpha) { return cspin(0, 1, alpha); }
transmatrix random_spin() {
if(DIM == 2) return spin(randd() * 2 * M_PI);
else {
ld alpha2 = acos(randd() * 2 - 1);
ld alpha = randd() * 2 * M_PI;
ld alpha3 = randd() * 2 * M_PI;
return cspin(0, 1, alpha) * cspin(0, 2, alpha2) * cspin(1, 2, alpha3);
}
}
transmatrix eupush(ld x, ld y) {
transmatrix T = Id;
T[0][DIM] = x;

View File

@ -2377,6 +2377,9 @@ void giantLandSwitch(cell *c, int d, cell *from) {
c->monst = moGhost;
break;
case laAsteroids:
break;
case landtypes: break;
}
}

View File

@ -237,6 +237,9 @@ int isNative(eLand l, eMonster m) {
case laMagnetic:
return isMagneticPole(m) ? 2 : 0;
case laAsteroids:
return m == moAsteroid ? 2 : 0;
case landtypes: return 0;
}
return false;
@ -316,7 +319,7 @@ bool landUnlocked(eLand l) {
case laStorms: case laWhirlwind:
return gold() >= R60;
case laWildWest: case laHalloween:
case laWildWest: case laHalloween: case laAsteroids:
return false;
case laIce: case laJungle: case laCaves: case laDesert:

View File

@ -291,6 +291,7 @@ eItem wanderingTreasure(cell *c) {
if(l == laEAir) return itAirShard;
if(l == laEEarth) return itEarthShard;
if(l == laElementalWall) return itNone;
if(l == laAsteroids) return itNone;
if(l == laMirror && c->type != 6) return itNone;
if(l == laMirrorOld && c->type != 6) return itNone;
if(l == laEmerald) {
@ -498,6 +499,26 @@ void wandering() {
else if(c->monst || c->pathdist == PINFD) break;
else if(c->land == laAsteroids) {
int gen = 0;
if(asteroids_generated * 12 <= items[itAsteroid]) gen = 2;
if(gen == 0) {
int qty = 0;
for(cell *c: currentmap->allcells()) if(c->monst == moAsteroid) qty++;
if(!qty) gen = 1;
}
if(gen) c->monst = moAsteroid, c->hitpoints = 4;
if(gen == 2)
asteroids_generated++;
if(items[itAsteroid] > (asteroid_orbs_generated+2) * (asteroid_orbs_generated+3) && !c->item) {
c->item = pick(itOrbThorns, itOrbSide1, itOrbSide2, itOrbSide3, itOrbShield, itOrbLife);
asteroid_orbs_generated++;
}
break;
}
else if(c->land == laClearing && wchance(items[itMutant2], 150) && items[itMutant2] >= 15 && !c->monst && c->type == 7)
c->monst = moRedFox;

View File

@ -1677,7 +1677,7 @@ hpcshape
shDragonWings,
shSolidBranch, shWeakBranch, shBead0, shBead1,
shBatWings, shBatBody, shBatMouth, shBatFang, shBatEye,
shParticle[16],
shParticle[16], shAsteroid[8],
shReptile[5][4],
shReptileBody, shReptileHead, shReptileFrontFoot, shReptileRearFoot,
shReptileFrontLeg, shReptileRearLeg, shReptileTail, shReptileEye,
@ -2311,7 +2311,16 @@ void procedural_shapes() {
for(int i=0; i<16; i++) {
bshape(shParticle[i], PPR::PARTICLE);
for(int t=0; t<6; t++)
hpcpush(xspinpush0(M_PI * t * 2 / 6 + M_PI * 2/6 * hrand(100) / 150., (0.03 + hrand(100) * 0.0003) * scalefactor));
// hpcpush(xspinpush0(M_PI * t * 2 / 6 + M_PI * 2/6 * hrand(100) / 150., (0.03 + hrand(100) * 0.0003) * scalefactor));
hpcpush(xspinpush0(M_PI * t * 2 / 6 + M_PI * 2/6 * randd() / 1.5, (0.03 + randd() * 0.03) * scalefactor));
hpc.push_back(hpc[last->s]);
}
for(int i=0; i<8; i++) {
asteroid_size[i] = scalefactor * 0.1 * pow(2, (i-1) * 1. / DIM);
bshape(shAsteroid[i], PPR::PARTICLE);
for(int t=0; t<12; t++)
hpcpush(xspinpush0(M_PI * t / 6, asteroid_size[i] * (1 - randd() * .2)));
hpc.push_back(hpc[last->s]);
}

170
shmup.cpp
View File

@ -1283,6 +1283,27 @@ void visibleFor(int t) {
visibleAt = max(visibleAt, curtime + t);
}
ld bullet_velocity(eMonster t) {
switch(t) {
case moBullet:
return 1/300.;
case moFireball:
return 1/500.;
case moCrushball:
return 1/1000.;
case moAirball:
return 1/200.;
case moArrowTrap:
return 1/200.;
case moTongue:
return 1/1500.;
default:
return 1/300.;
}
}
int frontdir() { return DIM == 2 ? 0 : 2; }
void shootBullet(monster *m) {
monster* bullet = new monster;
bullet->base = m->base;
@ -1291,6 +1312,10 @@ void shootBullet(monster *m) {
bullet->parent = m;
bullet->pid = m->pid;
bullet->parenttype = m->type;
bullet->inertia = m->inertia;
bullet->inertia[frontdir()] += bullet_velocity(m->type) * SCALE;
bullet->hitpoints = 0;
additional.push_back(bullet);
eItem orbdir[8] = {
@ -1305,6 +1330,10 @@ void shootBullet(monster *m) {
bullet->parent = m;
bullet->pid = m->pid;
bullet->parenttype = m->type;
bullet->hitpoints = 0;
using namespace hyperpoint_vec;
bullet->inertia = spin(-M_PI/4 * i) * m->inertia;
bullet->inertia[frontdir()] += bullet_velocity(m->type) * SCALE;
additional.push_back(bullet);
}
}
@ -1592,6 +1621,8 @@ static const int reflectflag = P_MIRRORWALL;
void movePlayer(monster *m, int delta) {
bool inertia_based = m->base->land == laAsteroids;
cpid = m->pid;
#if CAP_RACING
@ -1720,6 +1751,7 @@ void movePlayer(monster *m, int delta) {
if(playerturn[cpid] && canmove && !blown && DIM == 2) {
m->swordangle -= playerturn[cpid];
nat = nat * spin(playerturn[cpid]);
if(inertia_based) m->inertia = spin(-playerturn[cpid]) * m->inertia;
}
transmatrix nat0 = nat;
@ -1752,6 +1784,7 @@ void movePlayer(monster *m, int delta) {
if(mdy > 1) mdy = 1;
if(mdy < -1) mdy = -1;
if(mdx > 1) mdx = 1;
if(mdx < -1) mdx = -1;
if(racing::on) {
if(m->vel * -mdy < 0) mdy *= 3;
@ -1795,6 +1828,14 @@ void movePlayer(monster *m, int delta) {
nextstep:
transmatrix nat1 = nat;
hyperpoint avg_inertia;
if(inertia_based) {
avg_inertia = m->inertia;
m->inertia[frontdir()] += playergo[cpid] / 1000;
avg_inertia[frontdir()] += playergo[cpid] / 2000;
}
for(int igo=0; igo<IGO && !go; igo++) {
@ -1802,10 +1843,21 @@ void movePlayer(monster *m, int delta) {
playergoturn[cpid] = igospan[go];
if(DIM == 3)
if(inertia_based) {
if(igo) { go = false; break; }
ld r = hypot_d(DIM, avg_inertia);
nat = nat * rspintox(avg_inertia) * xpush(r * delta) * spintox(avg_inertia);
}
else if(DIM == 3) {
nat = nat1 * cpush(0, playerstrafe[cpid]) * cpush(2, playergo[cpid]) * cspin(0, 2, playerturn[cpid]) * cspin(1, 2, playerturny[cpid]);
else if(playergo[cpid])
m->inertia[0] = playerstrafe[cpid] / delta;
m->inertia[1] = 0;
m->inertia[2] = playergo[cpid] / delta;
}
else if(playergo[cpid]) {
nat = nat1 * spin(igospan[igo]) * xpush(playergo[cpid]) * spin(-igospan[igo]);
m->inertia = spin(igospan[igo]) * xpush0(playergo[cpid] / delta);
}
// spin(span[igo]) * xpush(playergo[cpid]) * spin(-span[igo]);
@ -1898,13 +1950,16 @@ void movePlayer(monster *m, int delta) {
if(!go) {
playergo[cpid] = playergoturn[cpid] = playerstrafe[cpid] = 0;
if(DIM == 3) playerturn[cpid] = playerturny[cpid] = 0;
m->inertia = Hypc;
}
if(go) {
if(DIM == 3)
if(DIM == 3) {
swordmatrix[cpid] =
cspin(1, 2, -playerturny[cpid]) * cspin(0, 2, -playerturn[cpid]) * swordmatrix[cpid];
m->inertia = cspin(1, 2, -playerturny[cpid]) * cspin(0, 2, -playerturn[cpid]) * m->inertia;
}
if(c2 != m->base) {
if(cellUnstable(m->base) && !markOrb(itOrbAether))
@ -2320,7 +2375,37 @@ transmatrix frontpush(ld x) {
if(DIM == 2) return xpush(x);
else return cpush(2, x);
}
ld collision_distance(monster *bullet, monster *target) {
if(target->type == moAsteroid)
return SCALE * 0.15 + asteroid_size[target->hitpoints & 7];
return SCALE * 0.3;
}
void spawn_asteroids(monster *bullet, monster *target) {
if(target->hitpoints <= 1) return;
hyperpoint rnd = random_spin() * point2(SCALE/3000., 0);
hyperpoint bullet_inertia = inverse(target->pat) * bullet->pat * bullet->inertia;
for(int i=0; i<2; i++) {
using namespace hyperpoint_vec;
monster* child = new monster;
child->base = target->base;
child->at = target->at;
child->type = target->type;
child->parent = NULL;
child->pid = target->pid;
child->parenttype = target->type;
child->inertia = target->inertia;
child->inertia += bullet_inertia / 5;
child->hitpoints = target->hitpoints - 1;
if(i == 0) child->inertia += rnd;
if(i == 1) child->inertia -= rnd;
additional.push_back(child);
}
}
void moveBullet(monster *m, int delta) {
cpid = m->pid;
m->findpat();
@ -2329,6 +2414,12 @@ void moveBullet(monster *m, int delta) {
transmatrix nat0 = m->pat;
transmatrix nat = m->pat;
bool inertia_based = m->base->land == laAsteroids;
if(m->base->land == laAsteroids) {
m->hitpoints += delta;
if(m->hitpoints >= 500) m->dead = true;
}
if(isReptile(m->base->wall)) m->base->wparam = reptilemax();
@ -2339,22 +2430,17 @@ void moveBullet(monster *m, int delta) {
nat = nat * rspintox(inverse(m->pat) * m->parent->pat * C0) * spin(M_PI);
}
}
else if(m->type == moBullet)
m->vel = 1/300.;
else if(m->type == moFireball)
m->vel = 1/500.;
else if(m->type == moCrushball)
m->vel = 1/1000.;
else if(m->type == moAirball)
m->vel = 1/200.;
else if(m->type == moArrowTrap)
m->vel = 1/200.;
else if(m->type == moTongue) {
m->vel = 1/1500.;
if(m->isVirtual || !m->parent || intval(nat*C0, m->parent->pat*C0) > SCALE2 * 0.4)
m->dead = true;
else m->vel = bullet_velocity(m->type);
if(m->type == moTongue && (m->isVirtual || !m->parent || intval(nat*C0, m->parent->pat*C0) > SCALE2 * 0.4))
m->dead = true;
if(inertia_based) {
ld r = hypot_d(DIM, m->inertia);
nat = nat * rspintox(m->inertia) * xpush(r * delta) * spintox(m->inertia);
}
nat = nat * frontpush(delta * SCALE * m->vel / speedfactor());
else
nat = nat * frontpush(delta * SCALE * m->vel / speedfactor());
cell *c2 = m->findbase(nat);
if(m->parent && isPlayer(m->parent) && markOrb(itOrbLava) && c2 != m->base && !isPlayerOn(m->base))
@ -2410,6 +2496,8 @@ void moveBullet(monster *m, int delta) {
if(!m->isVirtual) for(monster* m2: nonvirtual) {
if(m2 == m || (m2 == m->parent && m->vel >= 0) || m2->parent == m->parent)
continue;
if(m2->dead) continue;
eMonster ptype = parentOrSelf(m)->type;
bool slayer = m->type == moCrushball ||
@ -2424,9 +2512,9 @@ void moveBullet(monster *m, int delta) {
// fireballs/airballs don't collide
if(m->type == moFireball && m2->type == moFireball) continue;
if(m->type == moAirball && m2->type == moAirball) continue;
double d = intval(m2->pat*C0, m->pat*C0);
double d = hdist(m2->pat*C0, m->pat*C0);
if(d < SCALE2 * 0.1) {
if(d < collision_distance(m, m2)) {
if(m2->type == passive_switch) { m->dead = true; continue; }
@ -2526,6 +2614,10 @@ void moveBullet(monster *m, int delta) {
multi::kills[cpid]--;
mirrorspirits++;
}
if(m2->dead && m2->type == moAsteroid) {
gainItem(itAsteroid);
spawn_asteroids(m, m2);
}
}
}
}
@ -2553,6 +2645,8 @@ bool dragonbreath(cell *dragon) {
void moveMonster(monster *m, int delta) {
bool inertia_based = m->type == moAsteroid;
bool stunned = m->stunoff > curtime || m->blowoff > curtime;
if(stunned && cellUnstable(m->base))
@ -2623,7 +2717,14 @@ void moveMonster(monster *m, int delta) {
if(nearplayer) markOrb(itOrbBeauty), step /= 2;
}
if(m->isVirtual) return;
if(m->isVirtual) {
if(m->type == moAsteroid) {
ld r = hypot_d(DIM, m->inertia);
transmatrix nat = m->pat * rspintox(m->inertia) * xpush(r * delta) * spintox(m->inertia);
m->rebasePat(nat);
}
return;
}
transmatrix nat = m->pat;
if(stunned) {
@ -2643,6 +2744,8 @@ void moveMonster(monster *m, int delta) {
}
else if(m->type == moRagingBull && m->stunoff == CHARGING) ;
else if(m->type == moAsteroid) ;
else {
@ -2809,7 +2912,12 @@ void moveMonster(monster *m, int delta) {
return;
}
if(DIM == 3 && igo) {
if(inertia_based) {
if(igo) return;
ld r = hypot_d(DIM, m->inertia);
nat = nat * rspintox(m->inertia) * xpush(r * delta) * spintox(m->inertia);
}
else if(DIM == 3 && igo) {
ld fspin = rand() % 1000;
nat = nat0 * cspin(1,2,fspin) * spin(igospan[igo]) * xpush(step) * spin(-igospan[igo]) * cspin(2,1,fspin);
}
@ -2818,7 +2926,7 @@ void moveMonster(monster *m, int delta) {
}
if(m->type != moRagingBull && !peace::on)
if(intval(nat*C0, goal*C0) >= intval(m->pat*C0, goal*C0) && !stunned && !carried) {
if(intval(nat*C0, goal*C0) >= intval(m->pat*C0, goal*C0) && !stunned && !carried && !inertia_based) {
igo++; goto igo_retry; }
for(int i=0; i<multi::players; i++) for(int b=0; b<2; b++) if(sword::orbcount(b)) {
@ -2832,11 +2940,14 @@ void moveMonster(monster *m, int delta) {
monster* crashintomon = NULL;
if(!m->isVirtual) for(monster *m2: nonvirtual) if(m2!=m && m2->type != moBullet && m2->type != moArrowTrap) {
if(!m->isVirtual && m->type != moAsteroid) for(monster *m2: nonvirtual) if(m2!=m && m2->type != moBullet && m2->type != moArrowTrap) {
double d = intval(m2->pat*C0, nat*C0);
if(d < SCALE2 * 0.1) crashintomon = m2;
}
if(m->type == moAsteroid) for(int i=0; i<players; i++) if(pc[i] && hdist(tC0(pc[i]->pat), tC0(m->pat)) < collision_distance(pc[i], m))
crashintomon = pc[i];
if(!peace::on)
for(int i=0; i<players; i++)
if(crashintomon == pc[i])
@ -2862,7 +2973,7 @@ void moveMonster(monster *m, int delta) {
}
}
if(crashintomon) { igo++; goto igo_retry; }
if(crashintomon && m->type != moAsteroid) { igo++; goto igo_retry; }
cell *c2 = m->findbase(nat);
if(reflectflag & P_MIRRORWALL) reflect(c2, m->base, nat);
@ -3129,6 +3240,9 @@ void activateMonstersAt(cell *c) {
enemy->hitpoints = c->hitpoints;
if(c->wall == waBoat && isLeader(c->monst))
enemy->inBoat = true, c->wall = waSea;
if(c->monst == moAsteroid) {
enemy->inertia = random_spin() * point2(SCALE/3000., 0);
}
c->monst = moNone;
active.push_back(enemy);
}
@ -3572,6 +3686,12 @@ bool drawMonster(const transmatrix& V, cell *c, const transmatrix*& Vboat, trans
transmatrix t = view * spin(curtime / 50.0);
queuepoly(mmscale(t, 1.15), shFlailMissile, (minf[m->type].color << 8) | 0xFF);
ShadowV(view, shFlailMissile);
break;
}
case moAsteroid: {
transmatrix t = view * spin(curtime / 500.0);
queuepoly(mmscale(t, 1.15), shAsteroid[m->hitpoints & 7], (minf[m->type].color << 8) | 0xFF);
ShadowV(t, shAsteroid[m->hitpoints & 7]);
break;
}

View File

@ -17,6 +17,8 @@ bool canvas_invisible;
int truelotus;
int gamecount;
int asteroids_generated, asteroid_orbs_generated;
time_t timerstart, savetime;
bool timerstopped;
int savecount;
@ -287,6 +289,8 @@ void initgame() {
gen_wandering = true;
}
truelotus = 0;
asteroids_generated = 0;
asteroid_orbs_generated = 0;
survivalist = true;
#if CAP_CRYSTAL
crystal::used_compass_inside = false;