All courses now render properly. WIP items (shell, banana, fake item)

This commit is contained in:
riperiperi committed 2019-06-09 23:50:55 +01:00
1 parent e010627b5d
commit ff21142744
45 files changed
+3400 -1193

No files matched your search

+133 -7
View File
@@ -1,7 +1,7 @@
//
// bowserPlatforms.js
//--------------------
// Provides platforms for Bowser's Castle
// Provides moving platforms for Bowser's Castle and Delfino
// by RHY3756547
//
// includes:
@@ -78,6 +78,133 @@ window.ObjRotaryRoom = function(obji, scene) {
}
window.ObjBridge = function(obji, scene) {
var obji = obji;
var res = [];
var t = this;
t.collidable = true;
t.colMode = 0;
t.colRad = 512;
t.getCollision = getCollision;
t.moveWith = moveWith;
t.pos = vec3.clone(obji.pos);
t.angle = vec3.clone(obji.angle);
t.scale = vec3.clone(obji.scale);
t.requireRes = requireRes;
t.provideRes = provideRes;
t.update = update;
t.draw = draw;
t.largerUpAngle = obji.setting1&0xFFFF;
t.upDuration = obji.setting1>>16;
t.statDuration = obji.setting2&0xFFFF;
t.downDuration = obji.setting2>>16;
t.upAngle = obji.setting3&0xFFFF;
t.unknown = obji.setting4>>16; //10001
t.obji = obji;
t.colFrame = 0;
var dirVel = 0;
var genCol;
var prevMat;
var curMat;
var colMat = mat4.create();
prevMat = curMat;
var anim;
var animMat;
var frame = 0;
var mode = 0; //going up, stationary, going down, stationary
function setMat() {
prevMat = curMat;
var mat = mat4.create();
mat4.translate(mat, mat, t.pos);
if (t.angle[2] != 0) mat4.rotateZ(mat, mat, t.angle[2]*(Math.PI/180));
if (t.angle[1] != 0) mat4.rotateY(mat, mat, t.angle[1]*(Math.PI/180));
if (t.angle[0] != 0) mat4.rotateX(mat, mat, t.angle[0]*(Math.PI/180));
mat4.scale(mat, mat, vec3.scale([], t.scale, 16));
mat4.scale(colMat, mat, [genCol.scale, genCol.scale, genCol.scale]);
t.colFrame++;
curMat = mat;
}
function update(scene) {
var angle = 0;
frame++;
switch (mode) {
case 0:
var p = frame / t.upDuration;
angle = (0.5 - Math.cos(p * Math.PI) / 2) * t.largerUpAngle;
if (frame >= t.upDuration) {
mode = 1;
frame = 0;
}
break;
case 1:
case 3:
angle = (mode == 1) ? t.largerUpAngle : 0;
if (frame >= t.statDuration) {
mode = (mode + 1) % 4;
frame = 0;
}
break;
case 2:
var p = 1 - frame / t.downDuration;
angle = (0.5 - Math.cos(p * Math.PI) / 2) * t.largerUpAngle;
if (frame >= t.downDuration) {
mode = 3;
frame = 0;
}
break;
}
t.angle[0] = -angle;
animMat = anim.setFrame(0, 0, angle*1.5);
setMat();
}
function draw(view, pMatrix) {
var mat = mat4.create();
mat4.mul(mat, view, curMat);
res.mdl[0].draw(mat, pMatrix, animMat);
}
function requireRes() { //scene asks what resources to load
return {mdl:[{nsbmd:"bridge.nsbmd"}], other:[null, "bridge.nsbca"]};
}
function provideRes(r) {
res = r; //...and gives them to us. :)
var inf = res.mdl[0].getCollisionModel(0, 1, 7<<8); //dash
var inf2 = res.mdl[0].getCollisionModel(0, 0, 0); //regular
anim = new nitroAnimator(r.mdl[0].bmd, r.other[1]);
genCol = {dat:JSON.parse(JSON.stringify(inf.dat.concat(inf2.dat))), scale:inf.scale};
}
function getCollision() {
return { tris: genCol.dat, mat: colMat, frame: t.colFrame };
}
function moveWith(obj) { //used for collidable objects that move.
//the most general way to move something with an object is to multiply its position by the inverse mv matrix of that object, and then the new mv matrix.
vec3.transformMat4(obj.pos, obj.pos, mat4.invert([], prevMat))
vec3.transformMat4(obj.pos, obj.pos, curMat)
}
}
window.ObjRoutePlatform = function(obji, scene) {
var obji = obji;
var res = [];
@@ -111,12 +238,14 @@ window.ObjRoutePlatform = function(obji, scene) {
t.elapsedTime = 0;
t.mode = 0;
t.colFrame = 0;
var movVel;
//t.speed = (obji.setting1&0xFFFF)/8192;
function update(scene) {
t.colFrame++;
if (t.mode == 0) {
t.elapsedTime += t.routeSpeed;
movVel = vec3.sub([], t.nextNode.pos, t.prevPos);
@@ -159,15 +288,11 @@ window.ObjRoutePlatform = function(obji, scene) {
function generateCol() {
genCol = {dat: [
{
Vertex1: [25, 0, 11],
Vertex2: [25, 0, -11],
Vertex3: [-25, 0, -11],
Vertices: [[25, 0, 11], [25, 0, -11], [-25, 0, -11]],
Normal: [0, 1, 0]
},
{
Vertex1: [-25, 0, -11],
Vertex2: [-25, 0, 11],
Vertex3: [25, 0, 11],
Vertices: [[-25, 0, -11], [-25, 0, 11], [25, 0, 11]],
Normal: [0, 1, 0]
},
], scale: 1};
@@ -182,6 +307,7 @@ window.ObjRoutePlatform = function(obji, scene) {
mat4.scale(mat, mat, vec3.mul([], [16*inf.scale, 16*inf.scale, 16*inf.scale], t.scale));
obj.mat = mat;
obj.frame = t.colFrame;
return obj;
}
+184 -64
View File
@@ -32,34 +32,44 @@ var itemTypes = {
'$koura_w': BlueShellC
}
window.Item = function(scene, owner, type) {
window.Item = function(scene, owner, type, id) {
var t = this;
var minimumMove = 0.01;
this.id = 0;
this.id = id;
this.pos = vec3.transformMat4([], [0, (-owner.params.colRadius)+1, 16], owner.mat);
this.vel = vec3.create();
this.gravity = [0, -0.17, 0]; //100% confirmed by me messing around with the gravity value in mkds
this.minBounceVel = 0.5;
this.airResist = 0.95;
this.airResist = 0.99;
this.enablePhysics = true;
this.floorBounce = 0.5;
this.held = true;
this.type = type;
this.owner = owner;
this.holdTime = 20;
this.dead = false;
this.angle = owner.angle;
this.speed = 10;
this.yvel = 0;
this.xyScale = [1, 1];
this.colRadius = 4;
this.holdDist = 16;
this.holdDist = 2;
this.safeKart = owner;
var safeTimeMax = 4;
this.safeTime = safeTimeMax; //time the object needs to not be colliding with the source to start considering collisions with it
this.stuckTo = null;
var deadTimerLength = 20;
var throwVelocity = 16;
var throwAngle = (Math.PI / 3) * 2;
this.groundTime = 0;
var deadTimerLength = 30;
var throwVelocity = 7; //xz velocity for throw. angle adds a y component
var throwAngle = (Math.PI / 10) * 2;
var working = vec3.create();
this.deadTimer = 0; //animates death. goes to 20, then deletes for real. dead objects can't run update or otherwise
//a controller makes this item what it is...
@@ -69,6 +79,8 @@ window.Item = function(scene, owner, type) {
// update?: (scene: CourseScene) => void
// draw?: (mvMatrix, pMatrix) => void // OVERRIDES NORMAL DRAW FUNCTION!
// release?: (direction: number) => boolean //direction is 1 for forward, -1 for back. returns if the item has more uses
// onRest?: (normal: vec3) => void //when the object comes to a rest (first time, or after leaving the ground for a while)
// onDie?: (final: boolean) => void //when the object dies
// collide?: (item: Item | Kart)
// collideKart?: (item: Kart)
var subtypeInd = type.indexOf('-');
@@ -91,10 +103,16 @@ window.Item = function(scene, owner, type) {
function updateHold(kart) {
//move the object behind the kart (physical direction without drift off)
//assuming this will only be called for something that can be held
var dir = -kart.driftOff;
var dir = kart.driftOff / 4;
//offset the kart's drift offset (on direction)
var pos = [Math.sin(dir)*t.holdDist, 0, -Math.cos(dir)*t.holdDist];
var pos;
if (t.holdPos != null) {
pos = vec3.clone(t.holdPos);
} else {
var dist = t.colRadius + kart.params.colRadius + t.holdDist;
var pos = [Math.sin(dir)*dist, -kart.params.colRadius, -Math.cos(dir)*dist];
}
//make relative to the kart's position
vec3.transformMat4(pos, pos, kart.mat);
@@ -105,18 +123,37 @@ window.Item = function(scene, owner, type) {
function release(forward) {
//release the item, either forward or back
if (t.canBeHeld()) t.updateHold(owner);
t.holdTime = 0;
if (t.canBeHeld()) {
t.updateHold(owner);
updateCollision(scene);
}
t.enablePhysics = true;
if (t.controller.release) t.controller.release(forward);
else {
//default drop and throw. just here for template purposes
if (forward >= 0) {
var dir = owner.physicalDir;
vec3.zero(t.vel);
if (forward > 0) {
nitroAudio.playSound(218, {volume: 2}, 0, owner);
var dir = owner.driftOff / 4;
//offset the kart's drift offset (on direction). add y component
var vel = [-Math.sin(dir)*throwVelocity, Math.tan(throwAngle) * throwVelocity, Math.cos(dir)*throwVelocity];
var z = [0, 0, 0];
//make relative to the kart's orientation
vec3.transformMat4(vel, vel, owner.mat);
vec3.transformMat4(z, z, owner.mat);
vec3.sub(vel, vel, z);
var v2 = vec3.scale([], owner.vel, 2);
vec3.add(vel, vel, v2);
t.vel = vel;
} else {
vec3.zero(t.vel);
t.vel = vec3.create();
t.safeKart = null;
}
}
this.held = false;
t.held = false;
}
function canBeHeld() {
@@ -124,7 +161,8 @@ window.Item = function(scene, owner, type) {
}
function canBeDropped() {
return t.controller.canBeDropped || true;
if (t.controller.canBeDropped == null) return true;
return t.controller.canBeDropped;
}
function isDestructive() {
@@ -132,13 +170,22 @@ window.Item = function(scene, owner, type) {
}
function isSolid() {
return t.controller.isSolid || true;
if (t.controller.isSolid == null) return true;
return t.controller.isSolid;
}
function finalize() {
//kill instantly
if (t.controller.onDie) t.controller.onDie(true);
t.deadTimer = deadTimerLength;
scene.items.removeItem(t);
t.dead = true;
}
function intensityMax(targ, vec) {
if (Math.abs(vec[0]) > Math.abs(targ[0])*0.5) targ[0] = vec[0];
if (Math.abs(vec[1]) > Math.abs(targ[1])*0.5) targ[1] = vec[1];
if (Math.abs(vec[2]) > Math.abs(targ[2])*0.5) targ[2] = vec[2];
}
function collide(item) {
@@ -152,15 +199,19 @@ window.Item = function(scene, owner, type) {
if (item.isDestructive() || t.isDestructive()) {
//mutual destruction. other side will deal with how they handle the collision
t.deadTimer++;
item.deadTimer++;
} else if (item.isSolid() && t.isSolid()) {
//bounce off other items that are not destructive
//set our velocity to move away (not too intensely)
//(only apply if our id is before, to avoid double adding the velocity)
if (t.id < item.id) {
var diff = vec3.sub([], t.pos, item.pos);
vec3.scale(diff, diff, 0.5);
vec3.add(t.vel, t.vel, diff);
vec3.sub(item.vel, item.vel, diff);
var diff = vec3.sub(working, t.pos, item.pos);
vec3.scale(diff, diff, 0.33);
intensityMax(t.vel, diff);
vec3.scale(diff, diff, -1);
intensityMax(item.vel, diff);
//vec3.add(t.vel, t.vel, diff);
//vec3.sub(item.vel, item.vel, diff);
t.enablePhysics = true;
item.enablePhysics = true;
}
@@ -175,77 +226,131 @@ window.Item = function(scene, owner, type) {
function update(scene) {
if (t.controller.update) t.controller.update(scene);
if (t.holdTime > 0 && t.holdTime-- > 7) {
if (t.holdTime == 7) {
nitroAudio.playSound(231, {volume: 2}, 0, owner);
}
return;
}
if (t.pos[2] < -10000) finalize(); //out of bounds failsafe
if (t.deadTimer > 0) {
if (t.deadTimer == 1 && t.controller.onDie) t.controller.onDie(false);
t.deadTimer++;
if (t.deadTimer >= 20) t.finalize();
t.sprMat = mat4.create();
mat4.translate(t.sprMat, t.sprMat, [t.deadTimer/50, Math.sin((t.deadTimer/30) * Math.PI) * 0.5, 0]);
mat4.rotateZ(t.sprMat, t.sprMat, (t.deadTimer/-15) * Math.PI);
if (t.deadTimer >= 30) t.finalize();
return;
}
if (t.held) {
t.updateHold(owner);
}
var hitSafe = false;
//search for player collisions, collisions with other items
for (var i=0; i<scene.karts.length; i++) {
var ok = scene.karts[i];
var dist = vec3.dist(vec3.add([], t.pos, [0,1,0]), ok.pos);
if (dist < t.colRadius + 12) {
var dist = vec3.dist(vec3.add(working, t.pos, [0,t.colRadius/2,0]), ok.pos);
if (dist < t.colRadius + ok.params.colRadius) {
//colliding with a kart.
//do we need to do something?
if (ok === t.safeKart) {
hitSafe = true;
continue;
}
t.collide(ok);
}
}
for (var i=0; i<scene.items.length; i++) {
var ot = scene.items[i];
var dist = vec3.dist(t.pos, ot.pos);
if (dist < t.colRadius + ot.colRadius) {
//two items are colliding.
t.collide(ot);
if (t.safeKart && !hitSafe && !t.held) {
t.safeTime--;
if (t.safeTime <= 0) {
t.safeKart = null;
}
}
if (t.enablePhysics) {
if (!t.held) {
vec3.add(t.vel, t.vel, t.gravity);
vec3.scale(t.vel, t.vel, t.airResist);
}
//by default, items use raycast collision against the world (rather than ellipse)
//this speeds things up considerably
var steps = 0;
var remainingT = 1;
var velSeg = vec3.clone(t.vel);
var posSeg = vec3.clone(t.pos);
var ignoreList = [];
while (steps++ < 10 && remainingT > 0.01) {
var result = lsc.raycast(posSeg, velSeg, scene.kcl, 0.05, ignoreList);
if (result != null) {
if (t.controller.colResponse) t.controller.colResponse(posSeg, velSeg, result, ignoreList)
else colResponse(posSeg, velSeg, result, ignoreList)
remainingT -= result.t;
if (remainingT > 0.01) {
velSeg = vec3.scale(vec3.create(), t.vel, remainingT);
}
} else {
vec3.add(posSeg, posSeg, velSeg);
remainingT = 0;
if (t.holdTime == 0) { //avoid mutual item destruction on the first frame
for (var i=0; i<scene.items.items.length; i++) {
var ot = scene.items.items[i];
if (ot == t || (t.held && ot.held)) continue;
var dist = vec3.dist(t.pos, ot.pos);
if (dist < t.colRadius + ot.colRadius && ot.holdTime <= 7 && ot.deadTimer == 0) {
//two items are colliding.
t.collide(ot);
}
}
t.pos = posSeg;
}
if (t.groundTime > 0) t.groundTime++;
if (t.stuckTo != null) {
if (t.stuckTo.moveWith != null) t.stuckTo.moveWith(t);
t.enablePhysics = true;
t.stuckTo = null;
}
if (t.enablePhysics) {
updateCollision(scene);
}
}
function updateCollision(scene) {
if (!t.held) {
vec3.add(t.vel, t.vel, t.gravity);
vec3.scale(t.vel, t.vel, t.airResist);
}
//by default, items use raycast collision against the world (rather than ellipse)
//this speeds things up considerably
var steps = 0;
var remainingT = 1;
var velSeg = vec3.clone(t.vel);
var posSeg = vec3.clone(t.pos);
var ignoreList = [];
while (steps++ < 10 && remainingT > 0.01) {
var result = lsc.raycast(posSeg, velSeg, scene, 0.05, ignoreList);
if (result != null) {
if (t.controller.colResponse && !t.held) t.controller.colResponse(posSeg, velSeg, result, ignoreList)
else colResponse(posSeg, velSeg, result, ignoreList)
remainingT -= result.t;
if (remainingT > 0.01) {
velSeg = vec3.scale(velSeg, t.vel, remainingT);
}
} else {
vec3.add(posSeg, posSeg, velSeg);
remainingT = 0;
}
}
t.pos = posSeg;
}
function draw(mvMatrix, pMatrix) {
if (t.holdTime > 7) return;
if (t.deadTimer > 0) nitroRender.setColMult([1, 1, 1, 1-(t.deadTimer/deadTimerLength)]); //fade out
if (t.controller.draw) {
t.controller.draw(mvMatrix, pMatrix);
} else {
var mat = mat4.translate(mat4.create(), mvMatrix, vec3.add(vec3.create(), t.pos, [0, 3, 0]));
var mat = mat4.translate(mat4.create(), mvMatrix, vec3.add(vec3.create(), t.pos, [0, t.colRadius * t.xyScale[1], 0]));
spritify(mat);
mat4.scale(mat, mat, [16, 16, 16]);
var scale = 6*t.colRadius * (1 - t.holdTime/7);
mat4.scale(mat, mat, [scale, scale, scale]);
scene.gameRes.items[type].draw(mat, pMatrix);
var mdl = scene.gameRes.items[type];
//apply our custom mat (in sprite space), if it exists
//used for destruction animation, scaling
if (t.sprMat) {
var oldMat = mdl.baseMat;
mdl.setBaseMat(t.sprMat);
mdl.draw(mat, pMatrix);
mdl.setBaseMat(oldMat);
} else {
mdl.draw(mat, pMatrix);
}
}
if (t.deadTimer > 0) nitroRender.setColMult([1, 1, 1, 1]);
}
@@ -272,13 +377,28 @@ window.Item = function(scene, owner, type) {
//normally, item collision with a wall cause a perfect reflection of the velocity.
var proj = vec3.dot(t.vel, n) * 2;
vec3.sub(t.vel, t.vel, vec3.scale(vec3.create(), n, proj));
t.safeKart = null;
} else if (colType == MKDS_COLTYPE.OOB || colType == MKDS_COLTYPE.FALL) {
if (t.deadTimer == 0) t.deadTimer++;
} else if (MKDS_COLTYPE.GROUP_ROAD.indexOf(colType) != -1) {
//sliding plane
var proj = vec3.dot(t.vel, n) * (1 + t.floorBounce);
var bounce = t.held ? 0 : t.floorBounce;
var proj = vec3.dot(t.vel, n) * (1 + bounce);
vec3.sub(t.vel, t.vel, vec3.scale(vec3.create(), n, proj));
if (t.floorBounce == 0 || Math.abs(proj) < t.minBounceVel) t.enablePhysics = false;
if (!t.held && (t.floorBounce == 0 || Math.abs(proj) < t.minBounceVel)) {
t.vel[0] = 0;
t.vel[1] = 0;
t.vel[2] = 0;
t.enablePhysics = false;
if (t.groundTime == 0) {
t.groundTime = 1;
if (t.controller.onRest) {
t.controller.onRest(n);
}
}
}
t.stuckTo = dat.object;
} else {
adjustPos = false;
ignoreList.push(plane);
+4 -1
View File
@@ -98,12 +98,15 @@ window.ItemBox = function(obji, scene) {
}
function sndUpdate(view) {
/*
t.soundProps.pos = vec3.transformMat4([], t.pos, view);
if (t.soundProps.lastPos != null) t.soundProps.vel = vec3.sub([], t.soundProps.pos, t.soundProps.lastPos);
else t.soundProps.vel = [0, 0, 0];
*/
t.soundProps.lastPos = t.soundProps.pos;
t.soundProps.pos = t.pos; //todo: reintroduce doppler via emulation
t.soundProps.refDistance = 192/1024;
t.soundProps.refDistance = 192;
t.soundProps.rolloffFactor = 1;
}
+105 -16
View File
@@ -1,15 +1,42 @@
window.BananaC = function(item, scene, type) {
var t = this;
this.canBeHeld = true;
this.canBeDropped = true;
this.isDestructive = false;
item.minBounceVel = 0;
item.floorBounce = 0;
this.collideKart = collideKart;
this.onRest = onRest;
this.update = update;
function collideKart(kart) {
item.deadTimerLength = 20;
item.deadTimer = 1;
kart.damage(MKDSCONST.DAMAGE_SPIN);
}
function onRest(normal) {
nitroAudio.playSound(219, {volume: 2}, 0, item);
}
function update(argument) {
if (!item.held && item.colRadius < 6) {
item.colRadius += 0.2;
if (item.colRadius > 6) item.colRadius = 6;
}
if (item.groundTime < 30) {
var t = (1-item.groundTime/29);
var s = Math.sin(item.groundTime * Math.PI/14);
var sprMat = mat4.create();
mat4.translate(sprMat, sprMat, [0, -1/6, 0]);
mat4.scale(sprMat, sprMat, [1 + s * 0.6 * t, 1 - s * 0.6 * t, 1]);
mat4.translate(sprMat, sprMat, [0, 1/6, 0]);
item.sprMat = sprMat;
} else {
item.sprMat = null;
}
}
}
window.BananaGroupC = function(item, scene, type) {
@@ -28,27 +55,89 @@ window.BananaGroupC = function(item, scene, type) {
}
window.FakeBoxC = function(item, scene, type) {
var t = this;
this.canBeHeld = true;
this.canBeDropped = true;
this.isDestructive = false;
this.isSolid = true;
var model = scene.gameRes.fakeBox;
this.isSolid = false;
item.floorBounce = 0;
item.airResist = 0.98;
this.collideKart = collideKart;
this.onRest = onRest;
this.update = update;
this.draw = draw;
function draw(view, pMatrix) {
mat4.translate(mat, view, t.pos);
mat4.translate(mat, view, [0, 16, 0]);
this.xyScale = [1,1];
this.dir = 0;
function collideKart(kart) {
item.deadTimer = 1;
nitroAudio.playSound(250, {volume: 2}, 0, item);
kart.damage(MKDSCONST.DAMAGE_FLIP);
}
function onRest(normal) {
nitroAudio.playSound(251, {volume: 2}, 0, item);
}
function update(argument) {
if (item.held) {
t.dir = -(item.owner.physicalDir + item.owner.driftOff / 4);
}
if (!item.held && item.colRadius < 8) {
item.colRadius += 0.2;
if (item.colRadius > 8) item.colRadius = 8;
}
if (item.groundTime < 20) {
var linear = (1-item.groundTime/19);
var s = Math.sin(item.groundTime * Math.PI/8);
t.xyScale = [1 + s * 0.25 * linear, 1 - s * 0.25 * linear];
} else {
t.xyScale = [1,1];
}
}
function draw(mvMatrix, pMatrix) {
var mat = mat4.translate(mat4.create(), mvMatrix, vec3.add(vec3.create(), item.pos, [0, item.colRadius*1.5 * t.xyScale[1], 0]));
var scale = 2*item.colRadius * (1 - item.holdTime/7);
mat4.scale(mat, mat, [scale*t.xyScale[0], scale*t.xyScale[1], scale*t.xyScale[0]]);
mat4.rotateY(mat, mat, t.dir);
mat4.rotateZ(mat, mat, Math.PI/-6);
mat4.rotateY(mat, mat, Math.PI/6);
mat4.rotateX(mat, mat, Math.PI/-6);
/* adjust to make it rest on a corner
if (t.angle[2] != 0) mat4.rotateZ(mat, mat, t.angle[2]*(Math.PI/180));
if (t.angle[1] != 0) mat4.rotateY(mat, mat, t.angle[1]*(Math.PI/180));
if (t.angle[0] != 0) mat4.rotateX(mat, mat, t.angle[0]*(Math.PI/180));
*/
mat4.scale(mat, mat, vec3.scale([], t.scale, 16));
model.draw(mat, pMatrix, animMat);
var mdl = scene.gameRes.items.fakeBox;
mdl.draw(mat, pMatrix);
}
}
window.BombC = null;
window.BombC = function(item, scene, type) {
var t = this;
this.canBeHeld = true;
this.canBeDropped = true;
this.isDestructive = true;
this.isExploding = false;
this.collideKart = collideKart;
this.onRest = onRest;
this.update = update;
function collideKart(kart) {
item.deadTimer = 1;
kart.damage(MKDSCONST.DAMAGE_EXPLODE);
}
function onRest(normal) {
}
function update(argument) {
if (!item.held && item.colRadius < 6) {
item.colRadius += 0.2;
if (item.colRadius > 6) item.colRadius = 6;
}
}
}
+181 -2
View File
@@ -1,7 +1,97 @@
window.GreenShellC = function(item, scene) {
var t = this;
this.canBeHeld = true;
this.canBeDropped = true;
this.isDestructive = true;
this.angle = 0;
this.speed = 6; //base speed + kart speed
this.sound = null;
this.soundCooldown = 0;
item.colRadius = 3;
var minimumMove = 0.17;
this.gravity = [0, -0.17, 0]; //100% confirmed by me messing around with the gravity value in mkds
this.collideKart = collideKart;
this.update = update;
this.release = release;
this.onDie = onDie;
this.colResponse = colResponse;
function release(forward) {
t.sound = nitroAudio.playSound(215, {volume: 1.5}, 0, item);
t.speed = 6;
t.angle = item.owner.physicalDir;
if (forward < 0) {
t.angle += Math.PI;
t.angle %= Math.PI*2;
} else {
t.speed += item.owner.speed;
}
}
function onDie(final) {
if (!final) {
nitroAudio.playSound(214, {volume: 2}, 0, item);
}
if (t.sound) {
nitroAudio.instaKill(t.sound);
t.sound = null;
}
}
function collideKart(kart) {
item.deadTimer = 1;
kart.damage(MKDSCONST.DAMAGE_FLIP);
}
function update(scene) {
item.vel = [Math.sin(t.angle)*t.speed, item.vel[1], -Math.cos(t.angle)*t.speed]
vec3.add(item.vel, item.vel, t.gravity);
if (this.soundCooldown > 0) this.soundCooldown--;
}
function colResponse(pos, pvel, dat, ignoreList) {
var plane = dat.plane;
var colType = (plane.CollisionType>>8)&31;
vec3.add(pos, pos, vec3.scale(vec3.create(), pvel, dat.t));
var n = dat.normal;
vec3.normalize(n, n);
var gravS = Math.sqrt(vec3.dot(t.gravity, t.gravity));
var angle = Math.acos(vec3.dot(vec3.scale(vec3.create(), t.gravity, -1/gravS), n));
var adjustPos = true
if (MKDS_COLTYPE.GROUP_WALL.indexOf(colType) != -1) { //wall
//shell reflection code - slide y vel across plane, bounce on xz
if (this.soundCooldown <= 0) {
nitroAudio.playSound(213, {volume: 2.5}, 0, item);
this.soundCooldown = 30;
}
vec3.add(item.vel, vec3.scale(vec3.create(), n, -2*(vec3.dot(item.vel, n)/vec3.dot(n,n))), item.vel);
item.vel[1] = 0;
var v = item.vel;
t.angle = Math.atan2(v[0], -v[2]);
} else if (colType == MKDS_COLTYPE.OOB || colType == MKDS_COLTYPE.FALL) {
if (item.deadTimer == 0) item.deadTimer++;
} else if (MKDS_COLTYPE.GROUP_ROAD.indexOf(colType) != -1) {
//sliding plane
var proj = vec3.dot(item.vel, n);
vec3.sub(item.vel, item.vel, vec3.scale(vec3.create(), n, proj));
} else {
adjustPos = false;
ignoreList.push(plane);
}
var rVelMag = Math.sqrt(vec3.dot(item.vel, item.vel));
vec3.scale(item.vel, item.vel, t.speed/rVelMag); //force speed to shell speed for green shells.
if (adjustPos) { //move back from plane slightly
vec3.add(pos, pos, vec3.scale(vec3.create(), n, minimumMove));
}
}
}
window.RedShellC = function(item, scene) {
@@ -11,11 +101,100 @@ window.RedShellC = function(item, scene) {
}
window.ShellGroupC = function(item, scene, type) {
this.canBeHeld = false;
this.canBeDropped = 'func';
var t = this;
this.canBeHeld = "func";
this.canBeDropped = "func";
this.rotationPeriod = 45;
item.colRadius = -Infinity;
this.draw = draw;
this.update = update;
this.release = release;
this.onDie = onDie;
this.children = [];
var itemType = "koura_g";
var itemCount = 3;
if (type.length > 0) {
var typeParse = type.split("-");
if (typeParse.length == 1) {
itemType = type;
} else if (typeParse.length == 2 && !isNaN(typeParse[1]-0)) {
itemType = typeParse[0];
itemCount = typeParse[1]-0;
}
}
this.phase = 0;
var spinDist = 6;
init();
function init() {
t.remaining = itemCount;
item.holdPos = [0, 0, 0];
//create children
for (var i=0; i<itemCount; i++) {
var sub = scene.items.createItem(itemType, item.owner);
sub.holdTime = 7;
t.children.push(sub);
}
nitroAudio.playSound(231, {volume: 2}, 0, item);
this.sound = nitroAudio.playSound(227, {volume: 1.5}, 0, item);
}
function onDie(final) {
if (t.sound) {
nitroAudio.instaKill(t.sound);
t.sound = null;
}
}
function update(scene) {
for (var i=0; i<t.children.length; i++) {
var child = t.children[i];
if (child == null) continue;
if (child.deadTimer > 0) {
t.children[i] = null;
t.remaining--;
continue;
}
var angle = ((i / itemCount + t.phase / t.rotationPeriod) * Math.PI * 2);
var rad = item.owner.params.colRadius;
var dist = spinDist + rad;
child.holdPos = [-Math.sin(angle) * dist, -item.owner.params.colRadius, Math.cos(angle) * dist];
}
t.phase++;
t.phase %= t.rotationPeriod;
}
function release(forward) {
//forward the release to our last child
var toUse;
for (var i=0; i<t.children.length; i++) {
var child = t.children[i];
if (child == null) continue;
if (child.deadTimer > 0) {
t.children[i] = null;
t.remaining--;
continue;
}
toUse = child;
t.children[i] = null;
t.remaining--;
break;
}
if (toUse != null) {
toUse.release(forward);
}
if (t.remaining == 0) {
item.finalize();
}
}
function draw(mvMatrix, pMatrix) {
//the group itself is invisible - the shells draw individually
+253 -165
View File
@@ -73,6 +73,11 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
this.getPosition = getPosition;
this.playCharacterSound = playCharacterSound;
//functions for external objects to trigger
this.damage = damage;
this.damageTime = 0;
this.damageType = -1;
this.trackAttach = null; //a normal for the kart to attach to (loop)
this.boostMT = 0;
this.boostNorm = 0;
@@ -399,7 +404,8 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
mat4.rotateX(mat, mat, c.angle[0]*(-Math.PI/180));
k.pos = vec3.clone(c2.pos);
vec3.add(k.pos, k.pos, vec3.transformMat4([], [0,16,16], mat));
vec3.add(k.pos, k.pos, vec3.transformMat4([], [0,16,32], mat));
k.airTime = 4;
k.physicalDir = (180-c2.angle[1])*(Math.PI/180);
k.angle = k.physicalDir;
@@ -438,7 +444,6 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
}
}
} else { //default kart mode
if (k.OOB > 0) {
playCharacterSound(0);
var current = checkpoints[k.checkPointNumber];
@@ -466,180 +471,176 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
var top = params.topSpeed*effect.topSpeedMul; //if you let go of accel, drift ends anyway, so always accel in drift.
var boosting = (k.boostNorm + k.boostMT)>0;
if (boosting) {
var top2
if (k.boostNorm>0){
top2 = params.topSpeed*1.3;
k.boostNorm--;
} else {
top2 = params.topSpeed*((effect.topSpeedMul >= 1)?1.3:effect.topSpeedMul);
}
if (k.boostMT>0) {
k.boostMT--;
}
if (k.speed <= top2) {
k.speed += 1;
if (k.speed > top2) k.speed = top2;
} else {
k.speed *= 0.95;
}
}
//kart controls
if (k.drifting) {
if ((onGround) && !(input.accel && input.drift && (k.speed > 2 || !k.driftLanded))) {
//end drift, execute miniturbo
k.drifting = false;
clearWheelParticles();
if (sounds.powerslide != null) {
nitroAudio.instaKill(sounds.powerslide);
sounds.powerslide = null;
}
if (k.driftPSMode == 3) {
k.boostMT = params.miniTurbo;
}
k.driftPSMode = 0;
k.driftPSTick = 0;
}
if (k.driftMode == 0) {
if (input.turn > 0.30) {
k.driftMode = 2;
} else if (input.turn < -0.30) {
k.driftMode = 1;
}
} else {
if (k.driftLanded) {
var change = (((k.driftMode-1.5)*Math.PI/1.5)-k.driftOff)*0.05;
k.driftOff += change;
k.physicalDir -= change;
if (k.specialControlHandler != null) k.specialControlHandler();
else {
if (boosting) {
var top2
if (k.boostNorm>0){
top2 = params.topSpeed*1.3;
k.boostNorm--;
} else {
top2 = params.topSpeed*((effect.topSpeedMul >= 1)?1.3:effect.topSpeedMul);
}
//if we're above the initial y position, add a constant turn with a period of 180 frames.
if (!k.driftLanded && k.ylock>=0) {
k.physicalDir += (Math.PI*2/180)*(k.driftMode*2-3);
if (k.boostMT>0) {
k.boostMT--;
}
if (k.speed <= top2) {
k.speed += 1;
if (k.speed > top2) k.speed = top2;
} else {
k.speed *= 0.95;
}
}
if (onGround) {
if (!k.driftLanded) {
if (k.driftMode == 0) {
k.drifting = false;
clearWheelParticles();
//kart controls
if (k.drifting) {
if ((onGround) && !(input.accel && input.drift && (k.speed > 2 || !k.driftLanded))) {
//end drift, execute miniturbo
endDrift();
if (k.driftPSMode == 3) {
k.boostMT = params.miniTurbo;
}
else {
k.driftPSMode = 0;
k.driftPSTick = 0;
k.driftLanded = true;
if (k.drifting) setWheelParticles(20, 1); //20 = smoke, 1 = drift priority
k.driftPSMode = 0;
k.driftPSTick = 0;
}
if (k.driftMode == 0) {
if (input.turn > 0.30) {
k.driftMode = 2;
} else if (input.turn < -0.30) {
k.driftMode = 1;
}
} else {
if (k.driftLanded) {
var change = (((k.driftMode-1.5)*Math.PI/1.5)-k.driftOff)*0.05;
k.driftOff += change;
k.physicalDir -= change;
}
//if we're above the initial y position, add a constant turn with a period of 180 frames.
if (!k.driftLanded && k.ylock>=0) {
k.physicalDir += (Math.PI*2/180)*(k.driftMode*2-3);
}
}
if (k.drifting) {
if (onGround) {
if (!k.driftLanded) {
if (k.driftMode == 0) {
endDrift();
}
else {
k.driftPSMode = 0;
k.driftPSTick = 0;
k.driftLanded = true;
if (k.drifting) setWheelParticles(20, 1); //20 = smoke, 1 = drift priority
}
}
if (k.drifting) {
if (!boosting) {
if (k.speed <= top) {
k.speed += (k.speed/top > params.driftAccelSwitch)?params.driftAccel2:params.driftAccel1;
if (k.speed > top) k.speed = top;
} else {
k.speed *= 0.95;
}
}
var turn = ((k.driftMode == 1)?(input.turn-1):(input.turn+1))/2;
k.physicalDir += params.driftTurnRate*turn+((k.driftMode == 1)?-1:1)*(50/32768)*Math.PI; //what is this mystery number i hear you ask? well my friend, this is the turn rate for outward drift.
//miniturbo code
if (input.turn != 0) {
var inward = ((input.turn>0) == k.driftMode-1); //if we're turning
switch (k.driftPSMode) {
case 0: //dpad away from direction for 10 frames
if (!inward) k.driftPSTick++;
else if (k.driftPSTick > 9) {
k.driftPSMode++;
k.driftPSTick = 1;
//play blue spark sound, flare
setWheelParticles(126, 2); //126 = blue flare, 2 = flare priority
var blue = nitroAudio.playSound(210, {}, 0, k);
blue.gainN.gain.value = 2;
} else k.driftPSTick = 0;
break;
case 1: //dpad toward direction for 10 frames
if (inward) k.driftPSTick++;
else if (k.driftPSTick > 9) {
k.driftPSMode++;
k.driftPSTick = 1;
} else k.driftPSTick = 0;
break;
case 2: //dpad away from direction for 10 frames
if (!inward) k.driftPSTick++;
else if (k.driftPSTick > 9) {
k.driftPSMode++;
k.driftPSTick = 1;
//play red sparks sound, full MT!
setWheelParticles(22, 2); //22 = red flare, 2 = flare priority
setWheelParticles(17, 1); //17 = red mt, 1 = drift priority ... 18 is sparks that come out - but their mode is not working yet (spark mode)
sounds.powerslide = nitroAudio.playSound(209, {}, 0, k);
sounds.powerslide.gainN.gain.value = 2;
} else k.driftPSTick = 0;
break;
case 3: //turbo charged
break;
}
}
}
}
}
if (!k.drifting) {
if (onGround) {
var effect = params.colParam[groundEffect];
if (!boosting) {
if (k.speed <= top) {
k.speed += (k.speed/top > params.driftAccelSwitch)?params.driftAccel2:params.driftAccel1;
if (k.speed > top) k.speed = top;
if (input.accel) {
if (k.speed <= top) {
k.speed += (k.speed/top > params.accelSwitch)?params.accel2:params.accel1;
if (k.speed > top) k.speed = top;
} else {
k.speed *= 0.95;
}
} else {
k.speed *= 0.95;
k.speed *= params.decel;
}
}
var turn = ((k.driftMode == 1)?(input.turn-1):(input.turn+1))/2;
k.physicalDir += params.driftTurnRate*turn+((k.driftMode == 1)?-1:1)*(50/32768)*Math.PI; //what is this mystery number i hear you ask? well my friend, this is the turn rate for outward drift.
//miniturbo code
if (input.turn != 0) {
var inward = ((input.turn>0) == k.driftMode-1); //if we're turning
switch (k.driftPSMode) {
case 0: //dpad away from direction for 10 frames
if (!inward) k.driftPSTick++;
else if (k.driftPSTick > 9) {
k.driftPSMode++;
k.driftPSTick = 1;
//play blue spark sound, flare
setWheelParticles(126, 2); //126 = blue flare, 2 = flare priority
var blue = nitroAudio.playSound(210, {}, 0, k);
blue.gainN.gain.value = 2;
} else k.driftPSTick = 0;
break;
case 1: //dpad toward direction for 10 frames
if (inward) k.driftPSTick++;
else if (k.driftPSTick > 9) {
k.driftPSMode++;
k.driftPSTick = 1;
} else k.driftPSTick = 0;
break;
case 2: //dpad away from direction for 10 frames
if (!inward) k.driftPSTick++;
else if (k.driftPSTick > 9) {
k.driftPSMode++;
k.driftPSTick = 1;
//play red sparks sound, full MT!
setWheelParticles(22, 2); //22 = red flare, 2 = flare priority
setWheelParticles(17, 1); //17 = red mt, 1 = drift priority
sounds.powerslide = nitroAudio.playSound(209, {}, 0, k);
sounds.powerslide.gainN.gain.value = 2;
} else k.driftPSTick = 0;
break;
case 3: //turbo charged
break;
}
if ((input.accel && k.speed >= 0) || (k.speed > 0.1)) {
k.physicalDir += params.turnRate*input.turn;
} else if ( k.speed < -0.1) {
k.physicalDir -= params.turnRate*input.turn;
}
}
}
}
if (!k.drifting) {
if (onGround) {
var effect = params.colParam[groundEffect];
if (!boosting) {
if (input.accel) {
if (k.speed <= top) {
k.speed += (k.speed/top > params.accelSwitch)?params.accel2:params.accel1;
if (k.speed > top) k.speed = top;
} else {
k.speed *= 0.95;
}
} else {
k.speed *= params.decel;
if (input.drift) {
ylvel = 1.25;
k.vel[1] += 1.25;
k.airTime = 4;
k.drifting = true;
k.driftLanded = false;
k.driftMode = 0;
k.ylock = 0;
onGround = false;
var boing = nitroAudio.playSound(207, {transpose: -4}, 0, k);
boing.gainN.gain.value = 2;
}
} else {
if (input.drift) {
ylvel = 0;
k.drifting = true;
k.driftLanded = false;
k.driftMode = 0;
k.ylock = -0.001;
}
}
if ((input.accel && k.speed >= 0) || (k.speed > 0.1)) {
k.physicalDir += params.turnRate*input.turn;
} else if ( k.speed < -0.1) {
k.physicalDir -= params.turnRate*input.turn;
}
if (input.drift) {
ylvel = 1.25;
k.vel[1] += 1.25;
k.airTime = 4;
k.drifting = true;
k.driftLanded = false;
k.driftMode = 0;
k.ylock = 0;
onGround = false;
var boing = nitroAudio.playSound(207, {transpose: -4}, 0, k);
boing.gainN.gain.value = 2;
}
} else {
if (input.drift) {
ylvel = 0;
k.drifting = true;
k.driftLanded = false;
k.driftMode = 0;
k.ylock = -0.001;
}
}
}
@@ -708,8 +709,6 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
//move kart.
var steps = 0;
var remainingT = 1;
var baseVel = k.vel;
@@ -754,6 +753,7 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
var mat = mat4.create();
mat4.translate(mat, mat, k.pos);
k.mat = mat4.mul(mat, mat, k.basis);
if (k.damageMat != null) mat4.mul(mat, mat, k.damageMat);
if (input.item) {
scene.items.addItem(0, scene.karts.indexOf(k), {})
@@ -763,6 +763,83 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
positionChanged(lastPos, k.pos);
}
function endDrift() {
k.drifting = false;
clearWheelParticles();
if (sounds.powerslide != null) {
nitroAudio.instaKill(sounds.powerslide);
sounds.powerslide = null;
}
}
function damage(damageType) {
if (k.damageType >= damageType) {
return; //we are already damaged
}
//TODO: check invuln state
k.specialControlHandler = damagedControls;
playCharacterSound((damageType == 0) ? 1 : 0);
k.damageType = damageType;
k.ylock = 0;
k.anim.setAnim(k.charRes.spinA);
k.animMode = "spin";
if (k.drifting) {
endDrift();
}
k.boostMT = 0;
k.boostNorm = 0;
switch (damageType) {
case 0:
k.damageTime = 40;
break;
case 1:
k.damageTime = 80;
k.vel[1] += 3;
ylvel = 3;
k.airTime = 4;
break;
case 2:
k.damageTime = 105;
k.vel[1] += 8;
ylvel = 8;
k.airTime = 4;
break;
}
}
function damagedControls(kart) {
if (--k.damageTime == 0) {
k.anim.setAnim(k.charRes.driveA);
k.animMode = "drive";
k.specialControlHandler = null;
k.damageType = -1;
k.damageMat = null;
}
vec3.scale(k.vel, k.vel, 0.98);
k.speed *= 0.98;
var total = 40;
switch (k.damageType) {
case 1:
total = 80;
break;
case 2:
total = 105;
break;
}
var anim = 1 - (k.damageTime / total);
k.damageMat = mat4.create();
var flip = ((k.damageType%2) == 1)? 1 : -1;
var animOff = Math.min(1, anim*1.75);
mat4.rotateX(k.damageMat, k.damageMat, Math.PI*2 * animOff * k.damageType * flip);
if (k.damageType == 0) mat4.rotateY(k.damageMat, k.damageMat, Math.PI*-2 * anim);
else mat4.rotateY(k.damageMat, k.damageMat, Math.PI/12 * Math.sin(animOff*Math.PI));
}
function triggerCannon(id) {
if (k.cannon != null) return;
k.cannon = id;
@@ -923,7 +1000,7 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
k.kartColVel[1] = 0;
//play this kart's horn
nitroAudio.playSound(192 + charRes.sndOff/14, { volume: 2 }, 0, k);
nitroAudio.playSound(193 + charRes.sndOff/14, { volume: 2 }, 0, k);
}
function fixDir(dir) {
@@ -940,6 +1017,7 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
}
function updateKartSound(mode, input) {
if (!k.local) return; //for now, don't play kart sounds from other racers.
var turn = (onGround && !k.drifting)?(1-Math.abs(input.turn)/11):1;
var transpose = (mode == 0)?0:(22*turn*Math.min(1.3, k.speed/params.topSpeed));
@@ -1028,12 +1106,15 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
}
function sndUpdate(view) {
/*
k.soundProps.pos = vec3.transformMat4([], k.pos, view);
if (k.soundProps.lastPos != null) k.soundProps.vel = vec3.sub([], k.soundProps.pos, k.soundProps.lastPos);
else k.soundProps.vel = [0, 0, 0];
*/
k.soundProps.lastPos = k.soundProps.pos;
k.soundProps.pos = k.pos; //todo: reintroduce doppler via emulation
k.soundProps.refDistance = 192/1024;
k.soundProps.refDistance = 192;
k.soundProps.rolloffFactor = 1;
var calcVol = (k.soundProps.refDistance / (k.soundProps.refDistance + k.soundProps.rolloffFactor * (Math.sqrt(vec3.dot(k.soundProps.pos, k.soundProps.pos)) - k.soundProps.refDistance)));
@@ -1080,7 +1161,7 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
var angle = Math.acos(vec3.dot(vec3.scale(vec3.create(), k.gravity, -1/gravS), n));
var adjustPos = true;
if (colType == MKDS_COLTYPE.OOB || colType == MKDS_COLTYPE.FALL) {
if (MKDS_COLTYPE.GROUP_OOB.indexOf(colType) != -1) {
k.OOB = 1;
}
@@ -1101,12 +1182,18 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
}
vec3.sub(k.vel, k.vel, vec3.scale(vec3.create(), adjN, proj));
if (colType == MKDS_COLTYPE.KNOCKBACK_DAMAGE && k.damageType == -1) {
if (dat.object.vel) vec3.add(k.vel, k.vel, dat.object.vel);
vec3.add(k.vel, k.vel, vec3.scale(vec3.create(), adjN, 1.25));
k.damage(MKDSCONST.DAMAGE_FLIP);
}
//convert back to angle + speed to keep change to kart vel
var v = k.vel;
k.speed = Math.sqrt(v[0]*v[0]+v[2]*v[2]);
k.angle = Math.atan2(v[0], -v[2]);
stuckTo = dat.object;
} else if (MKDS_COLTYPE.GROUP_ROAD.indexOf(colType) != -1) {
//sliding plane
if (MKDS_COLTYPE.GROUP_BOOST.indexOf(colType) != -1) {
@@ -1117,7 +1204,8 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
if (k.vel[1] > 0) k.vel[1] = 0;
var proj = vec3.dot(k.vel, an);
if (!stick && proj < -4 && k.vel[1] < -2) { proj -= 1.5; }
if (k.damageType > 0) proj *= 1.7;
else if (!stick && proj < -4 && k.vel[1] < -2) { proj -= 1.5; }
vec3.sub(k.vel, k.vel, vec3.scale(vec3.create(), an, proj));
if (stick) {
+47 -8
View File
@@ -2,19 +2,20 @@
window.KartItems = function(kart, scene) {
var t = this;
t.heldItem = null; //of type Item
t.heldItem = null; //held item, or item that is bound to us. (bound items have hold type 'func', eg. triple shell)
t.currentItem = null; //string name for item
t.specificItem = null;
t.empty = true;
t.cycleTime = 0;
t.totalTime = 230;
var maxItemTime = 230;
var minItemTime = 80;
var carouselSfx = null;
var lastItemState = false;
var holdAppearDelay = 15;
var hurtExplodeDelay = 105 //turn right slightly, huge double backflip, small bounces.
var hurtExplodeDelay = 105; //turn right slightly, huge double backflip, small bounces.
var hurtFlipDelay = 80; //turn right slightly, bounce twice, forward flip
var hurtSpinDelay = 40; //counter clockwise spin
@@ -43,8 +44,22 @@ window.KartItems = function(kart, scene) {
}
}
function createItem() {
var item = scene.items.createItem(t.currentItem, kart);
return item;
}
function release(input) {
if (t.heldItem != null) {
t.heldItem.release(input.airTurn);
}
t.heldItem = null;
kart.playCharacterSound(7);
}
function update(input) {
var pressed = (input.item && !lastItemState);
var released = (lastItemState && !input.item);
if (!t.empty) {
if (t.currentItem == null) {
//carousel
@@ -53,24 +68,48 @@ window.KartItems = function(kart, scene) {
if (carouselSfx != null) nitroAudio.kill(carouselSfx);
//decide on an item
var item = "koura_g";
var item = "banana"; //koura_g, banana, f_box, koura_group, koura_group-bomb-7
sfx((specialItems.indexOf(item) == -1) ? 63 : 64);
t.currentItem = item;
} else {
//if item button is pressed, we speed up the carousel
if (pressed) {
if (pressed && t.heldItem == null) {
t.totalTime = Math.max(minItemTime, t.totalTime - 20);
}
}
} else {
} else if (t.heldItem == null) {
if (pressed) {
//fire?
t.currentItem = null;
t.empty = true;
kart.playCharacterSound(7);
t.heldItem = createItem();
//t.currentItem = null;
//t.empty = true;
if (t.heldItem.canBeHeld()) {
//begin holding
} else {
release(input);
}
pressed = false;
}
}
}
//todo: if held item has been destroyed, stop holding it.
if (t.heldItem != null) {
if (t.heldItem.dead) {
t.heldItem = null;
} else {
//t.heldItem.updateHold(kart);
if (released) {
if (t.heldItem.canBeHeld() !== 'func') release(input);
} else if (pressed) {
//special release: triple shells, bananas. object stays bound when released
t.heldItem.release(input.airTurn);
kart.playCharacterSound(7);
if (t.heldItem.dead) t.heldItem = null;
}
}
}
lastItemState = input.item;
}
+1 -1
View File
@@ -75,7 +75,7 @@ window.objDatabase = new (function(){
t[0x0195] = ObjBus;
t[0x00CC] = ObjDecor; //DEBUG: pianta bridge
t[0x00CC] = ObjBridge; //DEBUG: pianta bridge
t[0x000D] = ObjDecor; //DEBUG: puddle
t[0x0158] = ObjDecor; //DEBUG: airship (routed)
+13 -26
View File
@@ -41,11 +41,15 @@ window.ObjGear = function(obji, scene) {
t.angle = 0;
t.dir = (t.wB1 == 0)
t.colFrame = 0;
var colRes;
var dirVel = 0;
var prevMat;
var curMat;
setMat();
var colMat = mat4.create();
prevMat = curMat;
function setMat() {
@@ -59,6 +63,8 @@ window.ObjGear = function(obji, scene) {
mat4.rotateX(mat, mat, obji.angle[0]*(Math.PI/180));
mat4.rotateY(mat, mat, t.angle);
mat4.scale(colMat, mat, [colRes.scale, colRes.scale, colRes.scale]);
t.colFrame++;
curMat = mat;
}
@@ -119,43 +125,24 @@ window.ObjGear = function(obji, scene) {
}
}
function cloneKCL(kcl) {
return JSON.parse(JSON.stringify(kcl));
}
function provideRes(r) {
res = r; //...and gives them to us. :)
colRes = cloneKCL(res.mdl[0].getCollisionModel(0, 0));
}
function getCollision() {
var obj = {};
var inf = res.mdl[0].getCollisionModel(0, 0);
obj.tris = inf.dat;
var mat = mat4.translate([], mat4.create(), t.pos);
mat4.scale(mat, mat, vec3.mul([], [16*inf.scale, 16*inf.scale, 16*inf.scale], t.scale));
mat4.rotateY(mat, mat, obji.angle[1]*(Math.PI/180));
mat4.rotateX(mat, mat, obji.angle[0]*(Math.PI/180));
mat4.rotateY(mat, mat, t.angle);
obj.mat = mat;
return obj;
return { tris: colRes.dat, mat: colMat, frame: t.colFrame };
}
function moveWith(obj) { //used for collidable objects that move.
//the most general way to move something with an object is to multiply its position by the inverse mv matrix of that object, and then the new mv matrix.
vec3.transformMat4(obj.pos, obj.pos, mat4.invert([], prevMat))
vec3.transformMat4(obj.pos, obj.pos, curMat)
/*var p = vec3.sub([], obj.pos, t.pos);
if (obji.ID == 0x00D1) { //todo: maybe something more general
vec3.transformMat4(p, p, mat4.rotateX([], mat4.create(), dirVel));
vec3.add(obj.pos, t.pos, p);
} else {
vec3.transformMat4(p, p, mat4.rotateY([], mat4.create(), dirVel));
vec3.add(obj.pos, t.pos, p);
obj.physicalDir -= dirVel;
}*/
}
}
+4 -2
View File
@@ -34,7 +34,7 @@ window.GreenShell = function(scene, owner, time, itemID, cliID, params) {
var posSeg = vec3.clone(t.pos);
var ignoreList = [];
while (steps++ < 10 && remainingT > 0.01) {
var result = lsc.raycast(posSeg, velSeg, scene.kcl, 0.05, ignoreList);
var result = lsc.raycast(posSeg, velSeg, kcl, 0.05, ignoreList);
if (result != null) {
colResponse(posSeg, velSeg, result, ignoreList)
remainingT -= result.t;
@@ -87,7 +87,9 @@ window.GreenShell = function(scene, owner, time, itemID, cliID, params) {
var v = t.vel;
t.angle = Math.atan2(v[0], -v[2]);
item.safeKart = null;
} else if (colType == MKDS_COLTYPE.OOB || colType == MKDS_COLTYPE.FALL) {
if (item.deadTimer == 0) item.deadTimer++;
} else if (MKDS_COLTYPE.GROUP_ROAD.indexOf(colType) != -1) {
//sliding plane
var proj = vec3.dot(t.vel, n);
+8 -4
View File
@@ -44,16 +44,20 @@ window.ObjSoundMaker = function(obji, scene) {
}
function sndUpdate(view) {
t.soundProps.pos = vec3.transformMat4([], t.pos, view);
t.soundProps.pos = [0, 0, Math.sqrt(vec3.dot(t.soundProps.pos, t.soundProps.pos))]
//t.soundProps.pos = vec3.transformMat4([], t.pos, view);
//t.soundProps.pos = [0, 0, Math.sqrt(vec3.dot(t.soundProps.pos, t.soundProps.pos))]
//if (t.soundProps.lastPos != null) t.soundProps.vel = vec3.sub([], t.soundProps.pos, t.soundProps.lastPos);
//else t.soundProps.vel = [0, 0, 0];
//t.soundProps.lastPos = t.soundProps.pos;
t.soundProps.refDistance = 1024/1024;
t.soundProps.pos = t.pos; //todo: when reintroducing doppler, disable it on this source
t.soundProps.refDistance = 1024;
//t.soundProps.rolloffFactor = 1;
var calcVol = (t.soundProps.refDistance / (t.soundProps.refDistance + t.soundProps.rolloffFactor * (t.soundProps.pos[2] - t.soundProps.refDistance)));
var relPos = vec3.transformMat4([], t.pos, view);
var calcVol = (t.soundProps.refDistance / (t.soundProps.refDistance + t.soundProps.rolloffFactor * (relPos[2] - t.soundProps.refDistance)));
if (calcVol<threshold) {
if (sound != null) {
+133 -18
View File
@@ -17,6 +17,7 @@ window.ObjTruck = function(obji, scene) {
t.pos = vec3.clone(obji.pos);
//t.angle = vec3.clone(obji.angle);
t.scale = vec3.clone(obji.scale);
t.vel = vec3.create();
t.requireRes = requireRes;
t.provideRes = provideRes;
@@ -24,45 +25,138 @@ window.ObjTruck = function(obji, scene) {
t.draw = draw;
t.route = scene.paths[obji.routeID];
t.routeSpeed = (obji.setting1>>16)/100;
t.routePos = (obji.setting1&0xFFFF)%t.route.length;
t.routeSpeed = 0.01;
t.unknown = (obji.setting1&0xFFFF);
t.routePos = (obji.setting1>>16); //(obji.setting1&0xFFFF)%t.route.length;
t.variant = (obji.setting2&0xFFFF); //sets design for this car (from nsbtp)
t.variant2 = (obji.setting2>>16); //0 or 1. unknown purpose
t.routePos = (t.routePos+1)%t.route.length;
t.nodes = [
t.route[(t.routePos+t.route.length-2)%t.route.length].pos,
t.route[(t.routePos+t.route.length-1)%t.route.length].pos,
t.route[t.routePos].pos,
t.route[(t.routePos+1)%t.route.length].pos
];
t.nextNode = t.route[t.routePos];
t.prevPos = t.pos;
t.elapsedTime = 0;
var facingNormal = [0, 1, 0];
var curNormal = [0, 1, 0];
var curFloorNormal = [0, 1, 0];
var floorNormal = [0, 1, 0];
//collision stuff
t.collidable = true;
t.colMode = 0;
t.colRad = 512;
t.colFrame = 0;
t.moveWith = moveWith;
t.getCollision = getCollision;
var colRes;
var dirVel = 0;
var prevMat;
var curMat;
var colMat = mat4.create();
prevMat = curMat;
function setMat() {
prevMat = curMat;
var mat = mat4.create();
mat4.translate(mat, mat, t.pos);
mat4.scale(mat, mat, vec3.scale([], t.scale, 16));
mat4.mul(mat, mat, mat4.invert([], mat4.lookAt([], [0, 0, 0], curNormal, curFloorNormal)));
mat4.scale(colMat, mat, [colRes.scale, colRes.scale, colRes.scale]);
t.colFrame++;
curMat = mat;
}
//end collision stuff
function cubic1D(y0, y1, y2, y3, i) {
var a0, a1, a2, a3, i2;
i2 = i*i;
a0 = -0.5*y0 + 1.5*y1 - 1.5*y2 + 0.5*y3;
a1 = y0 - 2.5*y1 + 2*y2 - 0.5*y3;
a2 = -0.5*y0 + 0.5*y2;
a3 = y1;
return(a0 * i * i2 + a1 * i2 + a2 * i + a3);
}
function cubic3D(points, i) { //note: i is 0-1 between point 1 and 2. (0 and 3 are used to better define the curve)
var p0 = points[0];
var p1 = points[1];
var p2 = points[2];
var p3 = points[3];
return [
cubic1D(p0[0], p1[0], p2[0], p3[0], i),
cubic1D(p0[1], p1[1], p2[1], p3[1], i),
cubic1D(p0[2], p1[2], p2[2], p3[2], i)
];
}
function update(scene) {
//simple behaviour, just follow the path! piece of cake.
//recalculate our route speed using a target real world speed.
var nextTime = t.elapsedTime + t.routeSpeed;
for (var i=0; i<((t.elapsedTime == 0)?3:1); i++) {
if (nextTime < 1) {
var targSpeed = 2;
var estimate = cubic3D(t.nodes, nextTime);
var estDistance = vec3.dist(estimate, t.pos);
t.routeSpeed *= targSpeed/estDistance; //correct
if (t.routeSpeed > 0.2) t.routeSpeed = 0.2;
}
}
if (t.routeSpeed <= 0) t.routeSpeed = 0.01;
t.elapsedTime += t.routeSpeed;
t.pos = vec3.lerp([], t.prevPos, t.nextNode.pos, t.elapsedTime/t.nextNode.duration);
if (t.elapsedTime >= t.nextNode.duration) {
t.elapsedTime = 0;
t.prevPos = t.nextNode.pos;
var i = t.elapsedTime;
var newPos = cubic3D(t.nodes, i); //vec3.lerp([], t.prevPos, t.nextNode.pos, i);
vec3.sub(t.vel, newPos, t.pos);
t.pos = newPos;
if (t.elapsedTime >= 1) {
t.elapsedTime -= 1;
t.routePos = (t.routePos+1)%t.route.length;
t.nextNode = t.route[t.routePos];
t.nodes.splice(0, 1);
t.nodes.push(t.route[(t.routePos+1)%t.route.length].pos);
t.routeSpeed = 0.25;
}
facingNormal = vec3.sub([], t.prevPos, t.nextNode.pos)
vec3.normalize(facingNormal, facingNormal);
var rate = 0.025
curNormal[0] += (facingNormal[0]-curNormal[0])*rate;
curNormal[1] += (facingNormal[1]-curNormal[1])*rate;
curNormal[2] += (facingNormal[2]-curNormal[2])*rate;
curNormal = vec3.sub([], t.prevPos, t.pos)
t.prevPos = vec3.clone(t.pos);
vec3.normalize(curNormal, curNormal);
if (isNaN(curNormal[0])) curNormal = [0, 0, 1];
var spos = vec3.clone(t.pos);
spos[1] += 32;
var result = lsc.raycast(spos, [0, -100, 0], scene.kcl, 0.05, []);
var result = lsc.raycast(spos, [0, -100, 0], scene, 0.05, []);
if (result != null) {
floorNormal = result.normal;
} else {
floorNormal = [0,1,0];
}
var rate = 0.025;
curFloorNormal[0] += (floorNormal[0]-curFloorNormal[0])*rate;
curFloorNormal[1] += (floorNormal[1]-curFloorNormal[1])*rate;
curFloorNormal[2] += (floorNormal[2]-curFloorNormal[2])*rate;
vec3.normalize(curFloorNormal, curFloorNormal);
setMat();
}
function draw(view, pMatrix) {
@@ -70,23 +164,44 @@ window.ObjTruck = function(obji, scene) {
mat4.scale(mat, mat, vec3.scale([], t.scale, 16));
mat4.mul(mat, mat, mat4.invert([], mat4.lookAt([], [0, 0, 0], curNormal, floorNormal)));
mat4.mul(mat, mat, mat4.invert([], mat4.lookAt([], [0, 0, 0], curNormal, curFloorNormal)));
res.mdl[0].setFrame(t.variant);
res.mdl[0].draw(mat, pMatrix);
}
function requireRes() { //scene asks what resources to load
switch (obji.ID) {
case 0x019A:
return {mdl:[{nsbmd:"car_a.nsbmd"}]}; //one model, car
return {mdl:[{nsbmd:"car_a.nsbmd"}], other:["car_a.nsbtp"]}; //one model, car
case 0x019C:
return {mdl:[{nsbmd:"truck_a.nsbmd"}]}; //one model, truck
return {mdl:[{nsbmd:"truck_a.nsbmd"}], other:["truck_a.nsbtp"]}; //one model, truck
case 0x0195:
return {mdl:[{nsbmd:"bus_a.nsbmd"}]}; //one model, bus
}
}
function moveWith(obj) { //used for collidable objects that move.
//the most general way to move something with an object is to multiply its position by the inverse mv matrix of that object, and then the new mv matrix.
vec3.transformMat4(obj.pos, obj.pos, mat4.invert([], prevMat))
vec3.transformMat4(obj.pos, obj.pos, curMat);
}
function getCollision() {
return { tris: colRes.dat, mat: colMat, frame: t.colFrame };
}
function provideRes(r) {
res = r; //...and gives them to us. :)
if (r.other != null) {
if (r.other.length > 0 && r.other[0] != null) {
res.mdl[0].loadTexPAnim(r.other[0]);
}
}
colRes = res.mdl[0].getBoundingCollisionModel(0, 0);
for (var i=0; i<colRes.dat.length; i++) {
colRes.dat[i].CollisionType = MKDS_COLTYPE.KNOCKBACK_DAMAGE << 8;
}
}
}
+19 -12
View File
@@ -23,6 +23,10 @@ window.ObjWater = function(obji, scene) {
t.update = update;
t.draw = draw;
var frame = 0;
var wheight = 6.144;
var wosc = 12.288;
var wstay = 5*60;
var wchange = 4*60;
function draw(view, pMatrix) {
if (nitroRender.flagShadow) return;
@@ -34,34 +38,35 @@ window.ObjWater = function(obji, scene) {
gl.stencilFunc(gl.ALWAYS, 1, 0xFF);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE); //when depth test passes for water lower layer, pixel is already drawn, do not cover it with the white overlay (set stencil bit)
var height = (t.pos[1])+6.144+Math.sin(frame/150)*12.288 //0.106
var height = (t.pos[1])+wheight+Math.sin(frame/150)*wosc //0.106
mat4.translate(waterM, view, [Math.sin(frame/180)*96, height-3.072, Math.cos(frame/146)*96])
nitroRender.setAlpha(0x0A/31);
mat4.translate(waterM, view, [Math.sin(frame/180)*96, height, Math.cos(frame/146)*96])
nitroRender.setColMult([1, 1, 1, 0x0A/31]);
res.mdl[0].drawPoly(mat4.scale([], waterM, [16, 16, 16]), pMatrix, 0, 0); //water
if (res.mdl[1] != null) {
mat4.translate(waterM, view, [-Math.sin((frame+30)/180)*96, height-3, Math.cos((frame+100)/146)*96])
nitroRender.setAlpha(0x02/31);
res.mdl[1].draw(mat4.scale([], waterM, [16, 16, 16]), pMatrix); //water white detail part. stencil should do nothing here, since it's in the same position as the above.
}
gl.stencilFunc(gl.EQUAL, 0, 0xFF);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
if (!obji.ID == 9) {
if (obji.ID != 9) {
mat4.translate(waterM, view, [0, height, 0])
nitroRender.setAlpha(0x10/31);
nitroRender.setColMult([1, 1, 1, 0x10/31]);
res.mdl[0].drawPoly(mat4.scale([], waterM, [16, 16, 16]), pMatrix, 0, 1); //white shore wash part, water is stencil masked out
}
gl.disable(gl.STENCIL_TEST);
nitroRender.setAlpha(1);
if (res.mdl[1] != null) {
mat4.translate(waterM, view, [-Math.sin((frame+30)/180)*96, height, Math.cos((frame+100)/146)*96])
nitroRender.setColMult([1, 1, 1, 0x04/31]);
res.mdl[1].draw(mat4.scale([], waterM, [16, 16, 16]), pMatrix); //water white detail part. stencil should do nothing here, since it's in the same position as the above.
}
nitroRender.setColMult([1, 1, 1, 1]);
}
function update() {
frame = (frame+1)%197100; //it's a big number but yolo... we have the technology...
//TODO: physics and void-out for karts
}
function requireRes() { //scene asks what resources to load
@@ -75,6 +80,8 @@ window.ObjWater = function(obji, scene) {
case 0x0009:
return {mdl:[{nsbmd:"hyudoro_waterC.nsbmd"}, {nsbmd:"hyudoro_waterA.nsbmd"}]};
case 0x000C:
wheight = 38;
wosc = 16;
return {mdl:[{nsbmd:"mini_stage3_waterC.nsbmd"}, {nsbmd:"mini_stage3_waterA.nsbmd"}]};
}
}