Tweak physics, cannons, nsbtp support, prepare to add items.
parent
e1dc8603d1
commit
e010627b5d
|
@ -1,4 +1,5 @@
|
||||||
*.nds
|
*.nds
|
||||||
*.exe
|
*.exe
|
||||||
|
*.sdat
|
||||||
mongoose.conf
|
mongoose.conf
|
||||||
Code/Engine/col.lua
|
Code/Engine/col.lua
|
|
@ -13,13 +13,13 @@
|
||||||
fileQuota = 1;
|
fileQuota = 1;
|
||||||
filesLoaded = 0;
|
filesLoaded = 0;
|
||||||
window.onload = function(argument) {
|
window.onload = function(argument) {
|
||||||
loadFile("sound_data.sdat");
|
loadFile("SD_BBP2p.sdat");
|
||||||
}
|
}
|
||||||
|
|
||||||
var i=0;
|
var i=0;
|
||||||
var last = null;
|
var last = null;
|
||||||
function init() {
|
function init() {
|
||||||
nitroAudio.init(new sdat(files["sound_data.sdat"])); //89
|
nitroAudio.init(new sdat(files["SD_BBP2p.sdat"])); //89
|
||||||
//you need to extract this one yourself!
|
//you need to extract this one yourself!
|
||||||
|
|
||||||
play.addEventListener('click', function() {
|
play.addEventListener('click', function() {
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
})
|
})
|
||||||
/*
|
/*
|
||||||
var ctx = new AudioContext();
|
var ctx = new AudioContext();
|
||||||
test = new sdat(files["sound_data.sdat"]);
|
test = new sdat(files["SD_BBP2p.sdat"]);
|
||||||
testAud = new SSEQPlayer(test.sections["$INFO"][0][5], test, ctx);
|
testAud = new SSEQPlayer(test.sections["$INFO"][0][5], test, ctx);
|
||||||
|
|
||||||
var elem = document.getElementById('play'),
|
var elem = document.getElementById('play'),
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
play.addEventListener('click', function() {
|
play.addEventListener('click', function() {
|
||||||
if (last != null) nitroAudio.instaKill(last);
|
if (last != null) nitroAudio.instaKill(last);
|
||||||
document.getElementById('seq').innerText = "Current SSEQ: "+i;
|
document.getElementById('seq').innerText = "Current SSEQ: "+i;
|
||||||
last = nitroAudio.playSound(i++, {}, 0);
|
last = nitroAudio.playSound(i++, {}, 2);
|
||||||
})
|
})
|
||||||
/*
|
/*
|
||||||
var ctx = new AudioContext();
|
var ctx = new AudioContext();
|
||||||
|
|
|
@ -20,35 +20,48 @@ window.cameraIngame = function(kart) {
|
||||||
var lookAtOffset = [0, 16, 0]
|
var lookAtOffset = [0, 16, 0]
|
||||||
|
|
||||||
var camNormal = [0, 1, 0];
|
var camNormal = [0, 1, 0];
|
||||||
|
var forwardNormal = null;
|
||||||
var camAngle = 0;
|
var camAngle = 0;
|
||||||
var boostOff = 0;
|
var boostOff = 0;
|
||||||
|
|
||||||
|
function tweenVec3(from, to) {
|
||||||
|
from[0] += (to[0]-from[0])*0.075;
|
||||||
|
from[1] += (to[1]-from[1])*0.075;
|
||||||
|
from[2] += (to[2]-from[2])*0.075;
|
||||||
|
}
|
||||||
|
|
||||||
function getView(scene) {
|
function getView(scene) {
|
||||||
|
var loop = kart.physBasis != null && kart.physBasis.loop;
|
||||||
var basis = buildBasis();
|
var basis = buildBasis();
|
||||||
|
tweenVec3(camOffset, loop ? [0, 12, -57] : [0, 32, -48]);
|
||||||
var camPos = vec3.transformMat4([], camOffset, basis);
|
var camPos = vec3.transformMat4([], camOffset, basis);
|
||||||
var lookAtPos = vec3.transformMat4([], lookAtOffset, basis);
|
var lookAtPos = vec3.transformMat4([], lookAtOffset, basis);
|
||||||
|
|
||||||
vec3.scale(camPos, camPos, 1/1024);
|
vec3.scale(camPos, camPos, 1/1024);
|
||||||
vec3.scale(lookAtPos, lookAtPos, 1/1024);
|
vec3.scale(lookAtPos, lookAtPos, 1/1024);
|
||||||
|
|
||||||
var mat = mat4.lookAt(mat4.create(), camPos, lookAtPos, [0, 1, 0]);
|
var mat = mat4.lookAt(mat4.create(), camPos, lookAtPos, (kart.physBasis) ? camNormal : [0, 1, 0]);
|
||||||
var kpos = vec3.clone(kart.pos);
|
var kpos = vec3.clone(kart.pos);
|
||||||
if (kart.drifting && !kart.driftLanded && kart.ylock>0) kpos[1] -= kart.ylock;
|
if (kart.drifting && !kart.driftLanded && kart.ylock>0) kpos[1] -= kart.ylock;
|
||||||
mat4.translate(mat, mat, vec3.scale([], kpos, -1/1024));
|
mat4.translate(mat, mat, vec3.scale([], kpos, -1/1024));
|
||||||
|
|
||||||
//interpolate visual normal roughly to target
|
//interpolate visual normal roughly to target
|
||||||
camNormal[0] += (kart.kartNormal[0]-camNormal[0])*0.075;
|
tweenVec3(camNormal, kart.kartNormal);
|
||||||
camNormal[1] += (kart.kartNormal[1]-camNormal[1])*0.075;
|
|
||||||
camNormal[2] += (kart.kartNormal[2]-camNormal[2])*0.075;
|
|
||||||
vec3.normalize(camNormal, camNormal);
|
vec3.normalize(camNormal, camNormal);
|
||||||
|
|
||||||
if (kart.physBasis != null) {
|
if (loop) {
|
||||||
var kartA = kart.physicalDir+kart.driftOff/2;
|
var kartA = kart.physicalDir+kart.driftOff/2;
|
||||||
var forward = [Math.sin(kartA), 0, -Math.cos(kartA)];
|
var forward = [Math.sin(kartA), 0, -Math.cos(kartA)];
|
||||||
vec3.transformMat4(forward, forward, kart.physBasis.mat);
|
vec3.transformMat4(forward, forward, kart.physBasis.mat);
|
||||||
camAngle += dirDiff(Math.atan2(forward[0], -forward[2]), camAngle)*0.075;
|
camAngle += dirDiff(Math.atan2(forward[0], -forward[2]), camAngle)*0.075;
|
||||||
|
if (forwardNormal == null) {
|
||||||
|
forwardNormal = [Math.sin(camAngle), 0, -Math.cos(camAngle)];
|
||||||
|
} else {
|
||||||
|
tweenVec3(forwardNormal, forward);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
camAngle += dirDiff(kart.physicalDir+kart.driftOff/2, camAngle)*0.075;
|
camAngle += dirDiff(kart.physicalDir+kart.driftOff/2, camAngle)*0.075;
|
||||||
|
forwardNormal = null;
|
||||||
}
|
}
|
||||||
camAngle = fixDir(camAngle);
|
camAngle = fixDir(camAngle);
|
||||||
|
|
||||||
|
@ -67,8 +80,8 @@ window.cameraIngame = function(kart) {
|
||||||
function buildBasis() {
|
function buildBasis() {
|
||||||
//order y, x, z
|
//order y, x, z
|
||||||
var kart = thisObj.kart;
|
var kart = thisObj.kart;
|
||||||
var forward = [Math.sin(camAngle), 0, -Math.cos(camAngle)];
|
var forward = (forwardNormal != null) ? forwardNormal : [Math.sin(camAngle), 0, -Math.cos(camAngle)];
|
||||||
var side = [Math.cos(camAngle), 0, Math.sin(camAngle)];
|
var side = vec3.cross([], forward, camNormal);
|
||||||
/*
|
/*
|
||||||
if (kart.physBasis != null) {
|
if (kart.physBasis != null) {
|
||||||
vec3.transformMat4(forward, forward, kart.physBasis.mat);
|
vec3.transformMat4(forward, forward, kart.physBasis.mat);
|
||||||
|
|
|
@ -61,6 +61,7 @@ window.IngameRes = function(rom) {
|
||||||
}
|
}
|
||||||
t.blueShell = new nitroModel(new nsbmd(r.MainRace.getFile("/Item/koura_w.nsbmd")));
|
t.blueShell = new nitroModel(new nsbmd(r.MainRace.getFile("/Item/koura_w.nsbmd")));
|
||||||
t.splat = new nitroModel(new nsbmd(r.MainRace.getFile("/Item/geso_sumi.nsbmd")));
|
t.splat = new nitroModel(new nsbmd(r.MainRace.getFile("/Item/geso_sumi.nsbmd")));
|
||||||
|
t.fakeBox = new nitroModel(new nsbmd(r.MainRace.getFile("/MapObj/box.nsbmd")));
|
||||||
r.items = t;
|
r.items = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
|
|
||||||
window.MKDSCONST = new (function() {
|
window.MKDSCONST = new (function() {
|
||||||
|
|
||||||
|
this.DAMAGE_SPIN = 0;
|
||||||
|
this.DAMAGE_FLIP = 0;
|
||||||
|
this.DAMAGE_EXPLODE = 0;
|
||||||
|
|
||||||
this.COURSEDIR = "/data/Course/";
|
this.COURSEDIR = "/data/Course/";
|
||||||
|
|
||||||
this.COURSES = [ //in order of course id, nitro through retro
|
this.COURSES = [ //in order of course id, nitro through retro
|
||||||
|
|
|
@ -56,12 +56,17 @@ window.courseScene = function(mainNarc, texNarc, music, chars, options, gameRes)
|
||||||
|
|
||||||
//load main course
|
//load main course
|
||||||
var courseTx = new nsbtx(texNarc.getFile("/course_model.nsbtx"), false, true);
|
var courseTx = new nsbtx(texNarc.getFile("/course_model.nsbtx"), false, true);
|
||||||
|
|
||||||
var taFile = mainNarc.getFile("/course_model.nsbta");
|
var taFile = mainNarc.getFile("/course_model.nsbta");
|
||||||
if (taFile != null) var courseTa = new nsbta(taFile); //can be null
|
if (taFile != null) var courseTa = new nsbta(taFile); //can be null
|
||||||
|
var tpFile = mainNarc.getFile("/course_model.nsbtp");
|
||||||
|
if (tpFile != null) var courseTp = new nsbtp(tpFile); //can be null
|
||||||
|
|
||||||
var courseMdl = new nsbmd(mainNarc.getFile("/course_model.nsbmd"));
|
var courseMdl = new nsbmd(mainNarc.getFile("/course_model.nsbmd"));
|
||||||
|
|
||||||
var course = new nitroModel(courseMdl, courseTx)
|
var course = new nitroModel(courseMdl, courseTx)
|
||||||
if (taFile != null) course.loadTexAnim(courseTa);
|
if (taFile != null) course.loadTexAnim(courseTa);
|
||||||
|
if (tpFile != null) course.loadTexPAnim(courseTp);
|
||||||
|
|
||||||
//load sky
|
//load sky
|
||||||
var skyTx = new nsbtx(texNarc.getFile("/course_model_V.nsbtx"), false, true);
|
var skyTx = new nsbtx(texNarc.getFile("/course_model_V.nsbtx"), false, true);
|
||||||
|
@ -229,12 +234,25 @@ window.courseScene = function(mainNarc, texNarc, music, chars, options, gameRes)
|
||||||
scn.paths = paths;
|
scn.paths = paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getLightCenter() {
|
||||||
|
var average = vec3.create();
|
||||||
|
var objs = scn.nkm.sections["OBJI"].entries;
|
||||||
|
for (var i=0; i<objs.length; i++) {
|
||||||
|
vec3.add(average, average, objs[i].pos);
|
||||||
|
}
|
||||||
|
vec3.scale(average, average, (1/objs.length) /-1024);
|
||||||
|
return average;
|
||||||
|
}
|
||||||
|
|
||||||
function startCourse() {
|
function startCourse() {
|
||||||
scn.lightMat = mat4.create();
|
scn.lightMat = mat4.create();
|
||||||
|
|
||||||
mat4.rotateX(scn.lightMat, scn.lightMat, Math.PI*(61/180));
|
mat4.rotateX(scn.lightMat, scn.lightMat, Math.PI*(61/180));
|
||||||
mat4.rotateY(scn.lightMat, scn.lightMat, Math.PI*(21/180));
|
mat4.rotateY(scn.lightMat, scn.lightMat, Math.PI*(21/180));
|
||||||
|
scn.farShadMat = mat4.create();
|
||||||
|
mat4.translate(scn.farShadMat, scn.lightMat, getLightCenter());
|
||||||
|
|
||||||
mat4.mul(scn.farShadMat, mat4.ortho(mat4.create(), -5, 5, -5, 5, -5, 5), scn.lightMat);
|
mat4.mul(scn.farShadMat, mat4.ortho(mat4.create(), -5, 5, -5, 5, -5, 5), scn.farShadMat);
|
||||||
|
|
||||||
compilePaths();
|
compilePaths();
|
||||||
|
|
||||||
|
|
|
@ -37,16 +37,16 @@ window.ObjDecor = function(obji, scene) {
|
||||||
if (t.angle[1] != 0) mat4.rotateY(mat, mat, t.angle[1]*(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));
|
if (t.angle[0] != 0) mat4.rotateX(mat, mat, t.angle[0]*(Math.PI/180));
|
||||||
|
|
||||||
if (anim != null) {
|
|
||||||
animMat = anim.setFrame(0, 0, animFrame++);
|
|
||||||
}
|
|
||||||
|
|
||||||
mat4.scale(mat, mat, vec3.scale([], t.scale, 16));
|
mat4.scale(mat, mat, vec3.scale([], t.scale, 16));
|
||||||
res.mdl[0].draw(mat, pMatrix, animMat);
|
res.mdl[0].draw(mat, pMatrix, animMat);
|
||||||
}
|
}
|
||||||
|
|
||||||
function update() {
|
function update() {
|
||||||
|
res.mdl[0].setFrame(animFrame);
|
||||||
|
if (anim != null) {
|
||||||
|
animMat = anim.setFrame(0, 0, animFrame);
|
||||||
|
}
|
||||||
|
animFrame++;
|
||||||
}
|
}
|
||||||
|
|
||||||
function requireRes() { //scene asks what resources to load
|
function requireRes() { //scene asks what resources to load
|
||||||
|
@ -75,7 +75,7 @@ window.ObjDecor = function(obji, scene) {
|
||||||
case 0x0138:
|
case 0x0138:
|
||||||
return {mdl:[{nsbmd:"GardenTree1.nsbmd"}]};
|
return {mdl:[{nsbmd:"GardenTree1.nsbmd"}]};
|
||||||
case 0x0139:
|
case 0x0139:
|
||||||
return {mdl:[{nsbmd:"kamome.nsbmd"}], other:[null, null, "kamone.nsbtp"]}; //animates using nsbtp, and uses route to move
|
return {mdl:[{nsbmd:"kamome.nsbmd"}], other:[null, null, "kamome.nsbtp"]}; //animates using nsbtp, and uses route to move
|
||||||
|
|
||||||
case 0x013A:
|
case 0x013A:
|
||||||
return {mdl:[{nsbmd:"CrossTree1.nsbmd"}]};
|
return {mdl:[{nsbmd:"CrossTree1.nsbmd"}]};
|
||||||
|
@ -265,9 +265,13 @@ window.ObjDecor = function(obji, scene) {
|
||||||
if (r.other.length > 0 && r.other[0] != null) {
|
if (r.other.length > 0 && r.other[0] != null) {
|
||||||
res.mdl[0].loadTexAnim(r.other[0]);
|
res.mdl[0].loadTexAnim(r.other[0]);
|
||||||
}
|
}
|
||||||
if (r.other.length > 1 && r.other[1] != null)
|
if (r.other.length > 1 && r.other[1] != null) {
|
||||||
anim = new nitroAnimator(r.mdl[0].bmd, r.other[1]);
|
anim = new nitroAnimator(r.mdl[0].bmd, r.other[1]);
|
||||||
}
|
}
|
||||||
|
if (r.other.length > 2 && r.other[2] != null) {
|
||||||
|
res.mdl[0].loadTexPAnim(r.other[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,292 @@
|
||||||
|
//
|
||||||
|
// shell.js
|
||||||
|
//--------------------
|
||||||
|
// Entity type for any item. Specific item types in `/item` folder
|
||||||
|
// Has a default collision handler, but can pass control to the specific item code.
|
||||||
|
// by RHY3756547
|
||||||
|
//
|
||||||
|
// includes: gl-matrix.js (glMatrix 2.0)
|
||||||
|
// /formats/kcl.js
|
||||||
|
//
|
||||||
|
var itemTypes = {
|
||||||
|
//physics, holdable
|
||||||
|
'$koura_g': GreenShellC,
|
||||||
|
'$koura_r': RedShellC,
|
||||||
|
'$banana': BananaC,
|
||||||
|
'$bomb': BombC,
|
||||||
|
'$f_box': FakeBoxC,
|
||||||
|
|
||||||
|
//groups
|
||||||
|
'$koura_group': ShellGroupC,
|
||||||
|
'$banana_group': BananaGroupC,
|
||||||
|
|
||||||
|
//one use items
|
||||||
|
'$kinoko': MushroomC,
|
||||||
|
'$kinoko_group': MushroomGroupC,
|
||||||
|
'$kinoko_p': QueenMushroomC,
|
||||||
|
'$star': StarC,
|
||||||
|
'$thunder': ThunderC,
|
||||||
|
'$gesso': BlooperC,
|
||||||
|
'$teresa': BooC,
|
||||||
|
'$killer': KillerC,
|
||||||
|
'$koura_w': BlueShellC
|
||||||
|
}
|
||||||
|
|
||||||
|
window.Item = function(scene, owner, type) {
|
||||||
|
var t = this;
|
||||||
|
var minimumMove = 0.01;
|
||||||
|
|
||||||
|
this.id = 0;
|
||||||
|
|
||||||
|
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.enablePhysics = true;
|
||||||
|
this.floorBounce = 0.5;
|
||||||
|
this.held = true;
|
||||||
|
this.type = type;
|
||||||
|
this.owner = owner;
|
||||||
|
|
||||||
|
this.angle = owner.angle;
|
||||||
|
this.speed = 10;
|
||||||
|
this.yvel = 0;
|
||||||
|
|
||||||
|
this.colRadius = 4;
|
||||||
|
this.holdDist = 16;
|
||||||
|
this.safeKart = owner;
|
||||||
|
|
||||||
|
var deadTimerLength = 20;
|
||||||
|
var throwVelocity = 16;
|
||||||
|
var throwAngle = (Math.PI / 3) * 2;
|
||||||
|
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...
|
||||||
|
// canBeHeld: boolean
|
||||||
|
// canBeDropped: boolean | 'func'
|
||||||
|
// isDestructive: boolean
|
||||||
|
// 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
|
||||||
|
// collide?: (item: Item | Kart)
|
||||||
|
// collideKart?: (item: Kart)
|
||||||
|
var subtypeInd = type.indexOf('-');
|
||||||
|
if (subtypeInd == -1) subtypeInd = type.length;
|
||||||
|
this.controller = new itemTypes["$"+type.substr(0, subtypeInd)](this, scene, type.substr(subtypeInd + 1));
|
||||||
|
|
||||||
|
//functions
|
||||||
|
this.update = update;
|
||||||
|
this.draw = draw;
|
||||||
|
|
||||||
|
this.updateHold = updateHold;
|
||||||
|
this.release = release;
|
||||||
|
this.canBeHeld = canBeHeld;
|
||||||
|
this.canBeDropped = canBeDropped;
|
||||||
|
this.isDestructive = isDestructive;
|
||||||
|
this.isSolid = isSolid;
|
||||||
|
this.finalize = finalize;
|
||||||
|
this.collide = collide;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
//offset the kart's drift offset (on direction)
|
||||||
|
var pos = [Math.sin(dir)*t.holdDist, 0, -Math.cos(dir)*t.holdDist];
|
||||||
|
|
||||||
|
//make relative to the kart's position
|
||||||
|
vec3.transformMat4(pos, pos, kart.mat);
|
||||||
|
|
||||||
|
vec3.sub(t.vel, pos, t.pos); //set the object's velocity to try move it to the hold location. (gravity is disabled)
|
||||||
|
t.enablePhysics = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function release(forward) {
|
||||||
|
//release the item, either forward or back
|
||||||
|
if (t.canBeHeld()) t.updateHold(owner);
|
||||||
|
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);
|
||||||
|
} else {
|
||||||
|
vec3.zero(t.vel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.held = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function canBeHeld() {
|
||||||
|
return t.controller.canBeHeld || false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function canBeDropped() {
|
||||||
|
return t.controller.canBeDropped || true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isDestructive() {
|
||||||
|
return t.controller.isDestructive || false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSolid() {
|
||||||
|
return t.controller.isSolid || true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function finalize() {
|
||||||
|
//kill instantly
|
||||||
|
t.deadTimer = deadTimerLength;
|
||||||
|
scene.items.removeItem(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
function collide(item) {
|
||||||
|
if (t.controller.collide) {
|
||||||
|
t.controller.collide(item);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.type) {
|
||||||
|
//has a type, definitely an item
|
||||||
|
if (item.isDestructive() || t.isDestructive()) {
|
||||||
|
//mutual destruction. other side will deal with how they handle the collision
|
||||||
|
t.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);
|
||||||
|
t.enablePhysics = true;
|
||||||
|
item.enablePhysics = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//is a kart. usually this is where objects differ
|
||||||
|
if (t.controller.collideKart) {
|
||||||
|
t.controller.collideKart(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function update(scene) {
|
||||||
|
if (t.controller.update) t.controller.update(scene);
|
||||||
|
|
||||||
|
if (t.deadTimer > 0) {
|
||||||
|
t.deadTimer++;
|
||||||
|
if (t.deadTimer >= 20) t.finalize();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//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) {
|
||||||
|
//colliding with a kart.
|
||||||
|
//do we need to do something?
|
||||||
|
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.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.pos = posSeg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw(mvMatrix, pMatrix) {
|
||||||
|
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]));
|
||||||
|
|
||||||
|
spritify(mat);
|
||||||
|
mat4.scale(mat, mat, [16, 16, 16]);
|
||||||
|
|
||||||
|
scene.gameRes.items[type].draw(mat, pMatrix);
|
||||||
|
}
|
||||||
|
if (t.deadTimer > 0) nitroRender.setColMult([1, 1, 1, 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var spritify = function(mat, scale) {
|
||||||
|
var scale = (scale == null)?Math.sqrt(mat[0]*mat[0]+mat[1]*mat[1]+mat[2]*mat[2]):scale;
|
||||||
|
|
||||||
|
mat[0]=scale; mat[1]=0; mat[2]=0;
|
||||||
|
mat[4]=0; mat[5]=scale; mat[6]=0;
|
||||||
|
mat[8]=0; mat[9]=0; mat[10]=scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 adjustPos = true;
|
||||||
|
|
||||||
|
if (MKDS_COLTYPE.GROUP_WALL.indexOf(colType) != -1) { //wall
|
||||||
|
//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));
|
||||||
|
|
||||||
|
} else if (MKDS_COLTYPE.GROUP_ROAD.indexOf(colType) != -1) {
|
||||||
|
//sliding plane
|
||||||
|
var proj = vec3.dot(t.vel, n) * (1 + t.floorBounce);
|
||||||
|
vec3.sub(t.vel, t.vel, vec3.scale(vec3.create(), n, proj));
|
||||||
|
|
||||||
|
if (t.floorBounce == 0 || Math.abs(proj) < t.minBounceVel) t.enablePhysics = false;
|
||||||
|
} else {
|
||||||
|
adjustPos = false;
|
||||||
|
ignoreList.push(plane);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adjustPos) { //move back from plane slightly
|
||||||
|
vec3.add(pos, pos, vec3.scale(vec3.create(), n, minimumMove));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -48,6 +48,7 @@ window.ItemBox = function(obji, scene) {
|
||||||
scene.particles.push(new NitroEmitter(scene, ok, 47));
|
scene.particles.push(new NitroEmitter(scene, ok, 47));
|
||||||
t.mode = 1;
|
t.mode = 1;
|
||||||
t.time = 0;
|
t.time = 0;
|
||||||
|
ok.items.getItem(null); //todo: specific item from some
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
window.BananaC = function(item, scene, type) {
|
||||||
|
this.canBeHeld = true;
|
||||||
|
this.canBeDropped = true;
|
||||||
|
this.isDestructive = false;
|
||||||
|
item.minBounceVel = 0;
|
||||||
|
|
||||||
|
this.collideKart = collideKart;
|
||||||
|
|
||||||
|
function collideKart(kart) {
|
||||||
|
item.deadTimerLength = 20;
|
||||||
|
kart.damage(MKDSCONST.DAMAGE_SPIN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.BananaGroupC = function(item, scene, type) {
|
||||||
|
this.canBeHeld = false;
|
||||||
|
this.canBeDropped = 'func';
|
||||||
|
this.rotationPeriod = 45;
|
||||||
|
|
||||||
|
item.colRadius = -Infinity;
|
||||||
|
item.enablePhysics = false;
|
||||||
|
|
||||||
|
this.draw = draw;
|
||||||
|
|
||||||
|
function draw(mvMatrix, pMatrix) {
|
||||||
|
//the group itself is invisible - the bananas draw individually
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.FakeBoxC = function(item, scene, type) {
|
||||||
|
this.canBeHeld = true;
|
||||||
|
this.canBeDropped = true;
|
||||||
|
this.isDestructive = false;
|
||||||
|
this.isSolid = true;
|
||||||
|
var model = scene.gameRes.fakeBox;
|
||||||
|
|
||||||
|
this.draw = draw;
|
||||||
|
|
||||||
|
function draw(view, pMatrix) {
|
||||||
|
mat4.translate(mat, view, t.pos);
|
||||||
|
mat4.translate(mat, view, [0, 16, 0]);
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.BombC = null;
|
|
@ -0,0 +1,10 @@
|
||||||
|
//boost, 3x boost, queen boost, star, ghost
|
||||||
|
|
||||||
|
window.MushroomC = null;
|
||||||
|
window.MushroomGroupC = null;
|
||||||
|
window.QueenMushroomC = null;
|
||||||
|
window.StarC = null;
|
||||||
|
window.ThunderC = null;
|
||||||
|
window.BlooperC = null;
|
||||||
|
window.BooC = null;
|
||||||
|
window.KillerC = null;
|
|
@ -0,0 +1,25 @@
|
||||||
|
window.GreenShellC = function(item, scene) {
|
||||||
|
this.canBeHeld = true;
|
||||||
|
this.canBeDropped = true;
|
||||||
|
this.isDestructive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.RedShellC = function(item, scene) {
|
||||||
|
this.canBeHeld = true;
|
||||||
|
this.canBeDropped = true;
|
||||||
|
this.isDestructive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.ShellGroupC = function(item, scene, type) {
|
||||||
|
this.canBeHeld = false;
|
||||||
|
this.canBeDropped = 'func';
|
||||||
|
this.rotationPeriod = 45;
|
||||||
|
|
||||||
|
this.draw = draw;
|
||||||
|
|
||||||
|
function draw(mvMatrix, pMatrix) {
|
||||||
|
//the group itself is invisible - the shells draw individually
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.BlueShellC = null;
|
|
@ -27,6 +27,9 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
||||||
this.active = true;
|
this.active = true;
|
||||||
this.preboost = true;
|
this.preboost = true;
|
||||||
|
|
||||||
|
//supplimentary controllers
|
||||||
|
this.items = new KartItems(this, scene);
|
||||||
|
|
||||||
this.soundProps = {};
|
this.soundProps = {};
|
||||||
this.pos = pos;
|
this.pos = pos;
|
||||||
this.angle = angle;
|
this.angle = angle;
|
||||||
|
@ -311,6 +314,7 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
||||||
kartAnim = (kartAnim+1)%8;
|
kartAnim = (kartAnim+1)%8;
|
||||||
var input = k.controller.fetchInput();
|
var input = k.controller.fetchInput();
|
||||||
k.lastInput = input;
|
k.lastInput = input;
|
||||||
|
k.items.update(input);
|
||||||
|
|
||||||
if (input.turn > 0.3) {
|
if (input.turn > 0.3) {
|
||||||
if (k.driveAnimF < 28) k.driveAnimF++;
|
if (k.driveAnimF < 28) k.driveAnimF++;
|
||||||
|
@ -386,7 +390,7 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
||||||
} else if (k.cannon != null) { //when cannon is active, we fly forward at max move speed until we get to the cannon point.
|
} else if (k.cannon != null) { //when cannon is active, we fly forward at max move speed until we get to the cannon point.
|
||||||
var c = scene.nkm.sections["KTPC"].entries[k.cannon];
|
var c = scene.nkm.sections["KTPC"].entries[k.cannon];
|
||||||
|
|
||||||
if (c.id2 != 0) {
|
if (c.id1 != -1 && c.id2 != -1) {
|
||||||
var c2 = scene.nkm.sections["KTPC"].entries[c.id2];
|
var c2 = scene.nkm.sections["KTPC"].entries[c.id2];
|
||||||
c = c2;
|
c = c2;
|
||||||
|
|
||||||
|
@ -401,10 +405,18 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
||||||
k.angle = k.physicalDir;
|
k.angle = k.physicalDir;
|
||||||
k.cannon = null;
|
k.cannon = null;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
var mat = mat4.create();
|
var mat = mat4.create();
|
||||||
mat4.rotateY(mat, mat, c.angle[1]*(Math.PI/180));
|
mat4.rotateY(mat, mat, c.angle[1]*(Math.PI/180));
|
||||||
|
if (true) {
|
||||||
|
//vertical angle from position? airship fortress is impossible otherwise
|
||||||
|
//var c2 = scene.nkm.sections["KTPC"].entries[c.id2];
|
||||||
|
var diff = vec3.sub([], c.pos, k.pos);
|
||||||
|
var dAdj = Math.sqrt(diff[0]*diff[0] + diff[2]*diff[2]);
|
||||||
|
var dHyp = Math.sqrt(diff[0]*diff[0] + diff[1]*diff[1] + diff[2]*diff[2]);
|
||||||
|
mat4.rotateX(mat, mat, ((diff[1] > 0) ? -1 : 1) * Math.acos(dAdj/dHyp));
|
||||||
|
} else {
|
||||||
mat4.rotateX(mat, mat, c.angle[0]*(-Math.PI/180));
|
mat4.rotateX(mat, mat, c.angle[0]*(-Math.PI/180));
|
||||||
|
}
|
||||||
|
|
||||||
var forward = [0, 0, 1];
|
var forward = [0, 0, 1];
|
||||||
var up = [0, 1, 0];
|
var up = [0, 1, 0];
|
||||||
|
@ -415,10 +427,15 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
||||||
k.physicalDir = (180-c.angle[1])*(Math.PI/180);
|
k.physicalDir = (180-c.angle[1])*(Math.PI/180);
|
||||||
k.angle = k.physicalDir;
|
k.angle = k.physicalDir;
|
||||||
k.kartTargetNormal = vec3.transformMat4(up, up, mat);
|
k.kartTargetNormal = vec3.transformMat4(up, up, mat);
|
||||||
|
k.airTime = 0;
|
||||||
|
|
||||||
var planeConst = -vec3.dot(c.pos, forward);
|
var planeConst = -vec3.dot(c.pos, forward);
|
||||||
var cannonDist = vec3.dot(k.pos, forward) + planeConst;
|
var cannonDist = vec3.dot(k.pos, forward) + planeConst;
|
||||||
if (cannonDist > 0) k.cannon = null;
|
if (cannonDist > 0) {
|
||||||
|
k.cannon = null; //leaving cannon state
|
||||||
|
k.speed = params.topSpeed;
|
||||||
|
k.vel = vec3.scale([], vec3.transformMat4(forward, forward, mat), k.speed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else { //default kart mode
|
} else { //default kart mode
|
||||||
|
|
||||||
|
@ -611,6 +628,7 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
||||||
k.driftLanded = false;
|
k.driftLanded = false;
|
||||||
k.driftMode = 0;
|
k.driftMode = 0;
|
||||||
k.ylock = 0;
|
k.ylock = 0;
|
||||||
|
onGround = false;
|
||||||
|
|
||||||
var boing = nitroAudio.playSound(207, {transpose: -4}, 0, k);
|
var boing = nitroAudio.playSound(207, {transpose: -4}, 0, k);
|
||||||
boing.gainN.gain.value = 2;
|
boing.gainN.gain.value = 2;
|
||||||
|
@ -655,11 +673,18 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
||||||
vec3.add(k.vel, k.vel, k.kartColVel);
|
vec3.add(k.vel, k.vel, k.kartColVel);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
k.angle += dirDiff(k.physicalDir, k.angle)*effect.handling/2;
|
k.angle += dirDiff(k.physicalDir, k.angle)*effect.handling;
|
||||||
k.angle = fixDir(k.physicalDir);
|
k.angle += dirDiff(k.physicalDir, k.angle)*effect.handling; //applying this twice appears to be identical to the original
|
||||||
|
k.angle = fixDir(k.angle);
|
||||||
|
|
||||||
|
//reduce our forward speed by how much of our velocity is not going forwards
|
||||||
|
var factor = Math.sin(k.physicalDir)*Math.sin(k.angle) + Math.cos(k.physicalDir)*Math.cos(k.angle);
|
||||||
|
k.speed *= 1 - ((1-factor) * (1 - k.params.decel));
|
||||||
|
//var reducedSpeed = k.vel[0]*Math.sin(k.angle) + k.vel[2]*(-Math.cos(k.angle));
|
||||||
|
//reducedSpeed = ((reducedSpeed < 0) ? -1 : 1) * Math.sqrt(Math.abs(reducedSpeed));
|
||||||
k.vel[1] += k.gravity[1];
|
k.vel[1] += k.gravity[1];
|
||||||
k.vel = [Math.sin(k.angle)*k.speed, k.vel[1], -Math.cos(k.angle)*k.speed]
|
k.vel = [Math.sin(k.angle)*k.speed, k.vel[1], -Math.cos(k.angle)*k.speed]
|
||||||
|
//k.speed = reducedSpeed;
|
||||||
|
|
||||||
if (k.kartColTimer > 0) {
|
if (k.kartColTimer > 0) {
|
||||||
vec3.add(k.vel, k.vel, vec3.scale([], k.kartColVel, k.kartColTimer/10))
|
vec3.add(k.vel, k.vel, vec3.scale([], k.kartColVel, k.kartColTimer/10))
|
||||||
|
@ -738,6 +763,24 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
||||||
positionChanged(lastPos, k.pos);
|
positionChanged(lastPos, k.pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function triggerCannon(id) {
|
||||||
|
if (k.cannon != null) return;
|
||||||
|
k.cannon = id;
|
||||||
|
var c = scene.nkm.sections["KTPC"].entries[k.cannon];
|
||||||
|
if (c.id1 != -1 && c.id2 != -1) {
|
||||||
|
nitroAudio.playSound(345, {volume: 2.5}, 0, k);
|
||||||
|
} else {
|
||||||
|
nitroAudio.playSound(347, {volume: 2.5}, 0, k);
|
||||||
|
if (k.local) {
|
||||||
|
if (c.id2 == 0) {
|
||||||
|
nitroAudio.playSound(380, {volume: 2}, 0, null); //airship fortress
|
||||||
|
} else {
|
||||||
|
nitroAudio.playSound(456, {volume: 2}, 0, null); //waluigi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function playCharacterSound(sound, volume) {
|
function playCharacterSound(sound, volume) {
|
||||||
//0 - hit
|
//0 - hit
|
||||||
//1 - hit spin
|
//1 - hit spin
|
||||||
|
@ -856,7 +899,7 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
||||||
if (k != ok) {
|
if (k != ok) {
|
||||||
var dist = vec3.dist(k.pos, ok.pos);
|
var dist = vec3.dist(k.pos, ok.pos);
|
||||||
if (dist < 16) {
|
if (dist < 16) {
|
||||||
|
nitroAudio.playSound(208, { volume: 2 }, 0, k);
|
||||||
kartBounce(ok);
|
kartBounce(ok);
|
||||||
ok.kartBounce(k);
|
ok.kartBounce(k);
|
||||||
}
|
}
|
||||||
|
@ -879,6 +922,8 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
||||||
if (vec3.length(k.vel) < vec3.length(ok.vel)) vec3.add(k.kartColVel, k.kartColVel, vec3.sub([], ok.vel, k.vel));
|
if (vec3.length(k.vel) < vec3.length(ok.vel)) vec3.add(k.kartColVel, k.kartColVel, vec3.sub([], ok.vel, k.vel));
|
||||||
|
|
||||||
k.kartColVel[1] = 0;
|
k.kartColVel[1] = 0;
|
||||||
|
//play this kart's horn
|
||||||
|
nitroAudio.playSound(192 + charRes.sndOff/14, { volume: 2 }, 0, k);
|
||||||
}
|
}
|
||||||
|
|
||||||
function fixDir(dir) {
|
function fixDir(dir) {
|
||||||
|
@ -896,7 +941,7 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
||||||
|
|
||||||
function updateKartSound(mode, input) {
|
function updateKartSound(mode, input) {
|
||||||
var turn = (onGround && !k.drifting)?(1-Math.abs(input.turn)/11):1;
|
var turn = (onGround && !k.drifting)?(1-Math.abs(input.turn)/11):1;
|
||||||
var transpose = (mode == 0)?0:(22*turn*k.speed/params.topSpeed);
|
var transpose = (mode == 0)?0:(22*turn*Math.min(1.3, k.speed/params.topSpeed));
|
||||||
|
|
||||||
sounds.transpose += (transpose-sounds.transpose)/15;
|
sounds.transpose += (transpose-sounds.transpose)/15;
|
||||||
if (mode != soundMode) {
|
if (mode != soundMode) {
|
||||||
|
@ -965,6 +1010,7 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
||||||
k.physBasis = {
|
k.physBasis = {
|
||||||
mat: m4,
|
mat: m4,
|
||||||
inv: mat4.invert([], m4),
|
inv: mat4.invert([], m4),
|
||||||
|
normal: normal,
|
||||||
time: 15,
|
time: 15,
|
||||||
loop: false
|
loop: false
|
||||||
};
|
};
|
||||||
|
@ -1099,7 +1145,7 @@ window.Kart = function(pos, angle, speed, kartN, charN, controller, scene) {
|
||||||
stuckTo = dat.object;
|
stuckTo = dat.object;
|
||||||
} else if (colType == MKDS_COLTYPE.CANNON) {
|
} else if (colType == MKDS_COLTYPE.CANNON) {
|
||||||
//cannon!!
|
//cannon!!
|
||||||
k.cannon = colBE;
|
triggerCannon(colBE);
|
||||||
} else {
|
} else {
|
||||||
adjustPos = false;
|
adjustPos = false;
|
||||||
ignoreList.push(plane);
|
ignoreList.push(plane);
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
//item state for a kart. not an entity, just supplemental to one.
|
||||||
|
|
||||||
|
window.KartItems = function(kart, scene) {
|
||||||
|
var t = this;
|
||||||
|
t.heldItem = null; //of type Item
|
||||||
|
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 hurtFlipDelay = 80; //turn right slightly, bounce twice, forward flip
|
||||||
|
var hurtSpinDelay = 40; //counter clockwise spin
|
||||||
|
|
||||||
|
t.getItem = getItem;
|
||||||
|
t.update = update;
|
||||||
|
|
||||||
|
var specialItems = ["star"];
|
||||||
|
|
||||||
|
function sfx(id) {
|
||||||
|
if (kart.local) {
|
||||||
|
return nitroAudio.playSound(id, {volume: 2}, 0, null);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getItem(specific) {
|
||||||
|
if (!t.empty) return false;
|
||||||
|
else {
|
||||||
|
//begin carousel
|
||||||
|
t.cycleTime = 0;
|
||||||
|
t.totalTime = (specific) ? 60 : maxItemTime;
|
||||||
|
if (specific) t.specificItem = specific;
|
||||||
|
t.empty = false;
|
||||||
|
|
||||||
|
carouselSfx = sfx(62);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function update(input) {
|
||||||
|
var pressed = (input.item && !lastItemState);
|
||||||
|
if (!t.empty) {
|
||||||
|
if (t.currentItem == null) {
|
||||||
|
//carousel
|
||||||
|
t.cycleTime++;
|
||||||
|
if (t.cycleTime >= t.totalTime) {
|
||||||
|
if (carouselSfx != null) nitroAudio.kill(carouselSfx);
|
||||||
|
|
||||||
|
//decide on an item
|
||||||
|
var item = "koura_g";
|
||||||
|
sfx((specialItems.indexOf(item) == -1) ? 63 : 64);
|
||||||
|
t.currentItem = item;
|
||||||
|
} else {
|
||||||
|
//if item button is pressed, we speed up the carousel
|
||||||
|
if (pressed) {
|
||||||
|
t.totalTime = Math.max(minItemTime, t.totalTime - 20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (pressed) {
|
||||||
|
//fire?
|
||||||
|
t.currentItem = null;
|
||||||
|
t.empty = true;
|
||||||
|
kart.playCharacterSound(7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
lastItemState = input.item;
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,6 +36,9 @@ window.nsbtp = function(input) {
|
||||||
}
|
}
|
||||||
this.load = load;
|
this.load = load;
|
||||||
|
|
||||||
|
var texTotal;
|
||||||
|
var palTotal;
|
||||||
|
|
||||||
|
|
||||||
function load(input) {
|
function load(input) {
|
||||||
var view = new DataView(input);
|
var view = new DataView(input);
|
||||||
|
@ -56,7 +59,6 @@ window.nsbtp = function(input) {
|
||||||
if (stamp != "PAT0") throw "NSBTP invalid. Expected PAT0, found "+stamp;
|
if (stamp != "PAT0") throw "NSBTP invalid. Expected PAT0, found "+stamp;
|
||||||
|
|
||||||
animData = nitro.read3dInfo(view, mainOff+8, animInfoHandler);
|
animData = nitro.read3dInfo(view, mainOff+8, animInfoHandler);
|
||||||
debugger;
|
|
||||||
mainObj.animData = animData;
|
mainObj.animData = animData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,15 +94,15 @@ window.nsbtp = function(input) {
|
||||||
//8 bytes here? looks like texinfo
|
//8 bytes here? looks like texinfo
|
||||||
|
|
||||||
var duration = view.getUint16(offset, true);
|
var duration = view.getUint16(offset, true);
|
||||||
var tframes = view.getUint8(offset+2);
|
texTotal = view.getUint8(offset+2);
|
||||||
var pframes = view.getUint8(offset+3);
|
palTotal = view.getUint8(offset+3);
|
||||||
var unknown = view.getUint16(offset+4, true);
|
var unknown = view.getUint16(offset+4, true);
|
||||||
var unknown2 = view.getUint16(offset+6, true);
|
var unknown2 = view.getUint16(offset+6, true);
|
||||||
|
|
||||||
//...then another nitro
|
//...then another nitro
|
||||||
var data = nitro.read3dInfo(view, offset+8, matInfoHandler);
|
var data = nitro.read3dInfo(view, offset+8, matInfoHandler);
|
||||||
|
|
||||||
return {data: data, nextoff: data.nextoff, tframes:tframes, pframes:pframes, unknown:unknown, unknown2:unknown2, duration:duration};
|
return {data: data, nextoff: data.nextoff, texTotal:texTotal, palTotal:palTotal, unknown:unknown, unknown2:unknown2, duration:duration};
|
||||||
}
|
}
|
||||||
|
|
||||||
function matInfoHandler(view, offset, base) {
|
function matInfoHandler(view, offset, base) {
|
||||||
|
@ -141,13 +143,24 @@ window.nsbtp = function(input) {
|
||||||
offset += 4;
|
offset += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
obj.texNames = [];
|
||||||
//read 16char tex names
|
//read 16char tex names
|
||||||
for (var i=0; i<frames; i++) {
|
for (var i=0; i<texTotal; i++) {
|
||||||
|
var name = "";
|
||||||
|
for (var j=0; j<16; j++) {
|
||||||
|
name += readChar(view, offset++)
|
||||||
|
}
|
||||||
|
obj.texNames[i] = name;
|
||||||
}
|
}
|
||||||
//read 16char pal names
|
|
||||||
for (var i=0; i<frames; i++) {
|
|
||||||
|
|
||||||
|
obj.palNames = [];
|
||||||
|
//read 16char pal names
|
||||||
|
for (var i=0; i<palTotal; i++) {
|
||||||
|
var name = "";
|
||||||
|
for (var j=0; j<16; j++) {
|
||||||
|
name += readChar(view, offset++)
|
||||||
|
}
|
||||||
|
obj.palNames[i] = name;
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
|
@ -275,6 +275,26 @@ window.nitroRender = new function() {
|
||||||
this.prepareShader();
|
this.prepareShader();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var paused = false;
|
||||||
|
|
||||||
|
this.pauseShadowMode = function() {
|
||||||
|
this.nitroShader = shaders[0];
|
||||||
|
if (this.nitroShader == shaders[1]) paused = true;
|
||||||
|
gl.useProgram(this.nitroShader);
|
||||||
|
|
||||||
|
this.setColMult([1, 1, 1, 1]);
|
||||||
|
this.prepareShader();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.unpauseShadowMode = function() {
|
||||||
|
if (!paused) return;
|
||||||
|
this.nitroShader = shaders[1];
|
||||||
|
gl.useProgram(this.nitroShader);
|
||||||
|
|
||||||
|
this.setColMult([1, 1, 1, 1]);
|
||||||
|
this.prepareShader();
|
||||||
|
}
|
||||||
|
|
||||||
this.setColMult = function(color) {
|
this.setColMult = function(color) {
|
||||||
gl.useProgram(this.nitroShader);
|
gl.useProgram(this.nitroShader);
|
||||||
gl.uniform4fv(this.nitroShader.colMultUniform, color);
|
gl.uniform4fv(this.nitroShader.colMultUniform, color);
|
||||||
|
@ -360,6 +380,7 @@ function nitroModel(bmd, btx, remap) {
|
||||||
var texCanvas;
|
var texCanvas;
|
||||||
var tex;
|
var tex;
|
||||||
var texAnim;
|
var texAnim;
|
||||||
|
var texPAnim;
|
||||||
var texFrame;
|
var texFrame;
|
||||||
var modelBuffers;
|
var modelBuffers;
|
||||||
var collisionModel = [];
|
var collisionModel = [];
|
||||||
|
@ -470,6 +491,15 @@ function loadWhiteTex(btx) { //examines the materials in the loaded model and ge
|
||||||
var cacheID = truetex+":"+truepal;
|
var cacheID = truetex+":"+truepal;
|
||||||
var cached = btx.cache[cacheID];
|
var cached = btx.cache[cacheID];
|
||||||
|
|
||||||
|
tex.push(cacheTex(btx, truetex, truepal, m));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cacheTex(btx, truetex, truepal, m) {
|
||||||
|
var cacheID = truetex+":"+truepal;
|
||||||
|
var cached = btx.cache[cacheID];
|
||||||
|
|
||||||
if (cached == null) {
|
if (cached == null) {
|
||||||
var canvas = btx.readTexWithPal(truetex, truepal);
|
var canvas = btx.readTexWithPal(truetex, truepal);
|
||||||
if (m.flipX || m.flipY) {
|
if (m.flipX || m.flipY) {
|
||||||
|
@ -497,20 +527,18 @@ function loadWhiteTex(btx) { //examines the materials in the loaded model and ge
|
||||||
var t = loadTex(fC, gl, !m.repeatX, !m.repeatY);
|
var t = loadTex(fC, gl, !m.repeatX, !m.repeatY);
|
||||||
t.realWidth = canvas.width;
|
t.realWidth = canvas.width;
|
||||||
t.realHeight = canvas.height;
|
t.realHeight = canvas.height;
|
||||||
tex.push(t);
|
|
||||||
btx.cache[cacheID] = t;
|
btx.cache[cacheID] = t;
|
||||||
|
return t;
|
||||||
} else {
|
} else {
|
||||||
texCanvas.push(canvas);
|
texCanvas.push(canvas);
|
||||||
var t = loadTex(canvas, gl, !m.repeatX, !m.repeatY);
|
var t = loadTex(canvas, gl, !m.repeatX, !m.repeatY);
|
||||||
t.realWidth = canvas.width;
|
t.realWidth = canvas.width;
|
||||||
t.realHeight = canvas.height;
|
t.realHeight = canvas.height;
|
||||||
tex.push(t);
|
|
||||||
btx.cache[cacheID] = t;
|
btx.cache[cacheID] = t;
|
||||||
|
return t;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tex.push(cached);
|
return cached;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -524,6 +552,10 @@ function loadWhiteTex(btx) { //examines the materials in the loaded model and ge
|
||||||
texFrame = 0;
|
texFrame = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.loadTexPAnim = function(btp) {
|
||||||
|
texPAnim = btp;
|
||||||
|
}
|
||||||
|
|
||||||
this.setFrame = function(frame) {
|
this.setFrame = function(frame) {
|
||||||
texFrame = frame;
|
texFrame = frame;
|
||||||
}
|
}
|
||||||
|
@ -635,17 +667,36 @@ function loadWhiteTex(btx) { //examines the materials in the loaded model and ge
|
||||||
var gl = nitroRender.gl;
|
var gl = nitroRender.gl;
|
||||||
|
|
||||||
//texture 0 SHOULD be bound, assuming the nitrorender program has been prepared
|
//texture 0 SHOULD be bound, assuming the nitrorender program has been prepared
|
||||||
if (nitroRender.last.tex != tex[poly.mat]) {
|
var pmat = poly.mat;
|
||||||
gl.bindTexture(gl.TEXTURE_2D, tex[poly.mat]); //load up material texture
|
var matname = model.materials.names[pmat]; //attach tex anim to mat with same name
|
||||||
nitroRender.last.tex = tex[poly.mat];
|
if (texPAnim != null) {
|
||||||
|
var info = texPAnim.animData.objectData[modelind];
|
||||||
|
var anims = texPAnim.animData.objectData[modelind].data;
|
||||||
|
var animNum = anims.names.indexOf(matname);
|
||||||
|
if (animNum != -1) {
|
||||||
|
var offFrame = texFrame % info.duration;
|
||||||
|
//we got a match! it's wonderful :')
|
||||||
|
var anim = anims.objectData[animNum];
|
||||||
|
//look thru frames for the approprate point in the animation
|
||||||
|
for (var i=0; i<anim.frames.length; i++) {
|
||||||
|
if (offFrame >= anim.frames[i].time) {
|
||||||
|
tex[pmat] = cacheTex(btx == null ? bmd.tex : btx, anim.frames[i].tex, anim.frames[i].mat, model.materials.objectData[pmat]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var material = model.materials.objectData[poly.mat];
|
if (nitroRender.last.tex != tex[pmat]) {
|
||||||
|
gl.bindTexture(gl.TEXTURE_2D, tex[pmat]); //load up material texture
|
||||||
|
nitroRender.last.tex = tex[pmat];
|
||||||
|
}
|
||||||
|
|
||||||
|
var material = model.materials.objectData[pmat];
|
||||||
nitroRender.setAlpha(material.alpha)
|
nitroRender.setAlpha(material.alpha)
|
||||||
|
|
||||||
if (texAnim != null) {
|
if (texAnim != null) {
|
||||||
//generate and send texture matrix from data
|
//generate and send texture matrix from data
|
||||||
var matname = model.materials.names[poly.mat]; //attach tex anim to mat with same name
|
var matname = model.materials.names[pmat]; //attach tex anim to mat with same name
|
||||||
var anims = texAnim.animData.objectData[modelind].data;
|
var anims = texAnim.animData.objectData[modelind].data;
|
||||||
var animNum = anims.names.indexOf(matname);
|
var animNum = anims.names.indexOf(matname);
|
||||||
|
|
||||||
|
@ -733,10 +784,11 @@ function loadTex(img, gl, clampx, clampy) { //general purpose function for loadi
|
||||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
|
||||||
|
|
||||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
||||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||||
if (clampx) gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
if (clampx) gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||||
if (clampy) gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
if (clampy) gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||||
|
gl.generateMipmap(gl.TEXTURE_2D);
|
||||||
|
|
||||||
texture.width = img.width;
|
texture.width = img.width;
|
||||||
texture.height = img.height;
|
texture.height = img.height;
|
||||||
|
|
|
@ -36,11 +36,23 @@ window.Race3DUI = function(scene, type, animStart) {
|
||||||
],
|
],
|
||||||
"start": [ //offset 86 up
|
"start": [ //offset 86 up
|
||||||
-128/1024, 128/1024, -(192+66)/1024, -66/1024
|
-128/1024, 128/1024, -(192+66)/1024, -66/1024
|
||||||
]
|
],
|
||||||
|
"goal": [ //why are these all so different?
|
||||||
|
-128/1024, 128/1024, -(512 + 64)/1024, -(512 - 128)/1024
|
||||||
|
],
|
||||||
|
|
||||||
|
//animations seem completely broken for these two (quickly files off screen after start)
|
||||||
|
//right now the vertical range of the viewport is large to try figure out where the hell it's going?
|
||||||
|
"win": [
|
||||||
|
-128/1024, 128/1024, -(1024)/1024, 1024/1024
|
||||||
|
],
|
||||||
|
"lose": [
|
||||||
|
-128/1024, 128/1024, -(1024)/1024, 1024/1024
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
var param = params[type];
|
var param = params[type];
|
||||||
if (param == null) param = params["count"]
|
if (param == null) param = params["count"];
|
||||||
|
|
||||||
mat4.ortho(proj, param[0], param[1], param[2], param[3], -0.001, 10);
|
mat4.ortho(proj, param[0], param[1], param[2], param[3], -0.001, 10);
|
||||||
buildOrtho(nitroRender.getViewWidth(), nitroRender.getViewHeight());
|
buildOrtho(nitroRender.getViewWidth(), nitroRender.getViewHeight());
|
||||||
|
@ -54,10 +66,13 @@ window.Race3DUI = function(scene, type, animStart) {
|
||||||
bmd = new nsbmd(bmd);
|
bmd = new nsbmd(bmd);
|
||||||
|
|
||||||
var bca = new nsbca(scene.gameRes.Race.getFile(type+".nsbca"));
|
var bca = new nsbca(scene.gameRes.Race.getFile(type+".nsbca"));
|
||||||
|
var btp = scene.gameRes.Race.getFile(type+".nsbtp");
|
||||||
|
if (btp != null) btp = new nsbtp(btp);
|
||||||
anim = new nitroAnimator(bmd, bca);
|
anim = new nitroAnimator(bmd, bca);
|
||||||
length = anim.getLength(0);
|
length = anim.getLength(0);
|
||||||
if (type == "count") length *= 3;
|
if (type == "count") length *= 3;
|
||||||
model = new nitroModel(bmd);
|
model = new nitroModel(bmd);
|
||||||
|
model.loadTexPAnim(btp)
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildOrtho(width, height) {
|
function buildOrtho(width, height) {
|
||||||
|
@ -72,11 +87,14 @@ window.Race3DUI = function(scene, type, animStart) {
|
||||||
var width = nitroRender.getViewWidth();
|
var width = nitroRender.getViewWidth();
|
||||||
if (width != lastWidth) buildOrtho(width, nitroRender.getViewHeight());
|
if (width != lastWidth) buildOrtho(width, nitroRender.getViewHeight());
|
||||||
mat4.translate(mat, view, t.pos);
|
mat4.translate(mat, view, t.pos);
|
||||||
|
nitroRender.pauseShadowMode();
|
||||||
model.draw(mat, proj, animMat);
|
model.draw(mat, proj, animMat);
|
||||||
|
nitroRender.unpauseShadowMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
function update() {
|
function update() {
|
||||||
if (anim != null) {
|
if (anim != null) {
|
||||||
|
model.setFrame(animFrame);
|
||||||
animMat = anim.setFrame(0, 0, Math.max(0, animFrame++));
|
animMat = anim.setFrame(0, 0, Math.max(0, animFrame++));
|
||||||
}
|
}
|
||||||
if (animFrame > length) {
|
if (animFrame > length) {
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue