1444 lines
38 KiB
HolyC
1444 lines
38 KiB
HolyC
Cd(__DIR__);;
|
|
|
|
//#define DEBUG
|
|
|
|
#exe {
|
|
#ifdef DEBUG
|
|
Option(OPTf_WARN_UNUSED_VAR, ON);
|
|
Option(OPTf_WARN_PAREN, ON);
|
|
#endif
|
|
}
|
|
|
|
#include "Controls"
|
|
Controls gCtrl;
|
|
|
|
#include "UI"
|
|
#include "GameInput"
|
|
#include "Title"
|
|
#include "Draw"
|
|
#include "Noise"
|
|
|
|
#ifdef DEBUG
|
|
#include "CrunkComm"
|
|
#endif
|
|
|
|
// Globals
|
|
World gW;
|
|
UI gUI;
|
|
I8 noiseMap[640*640];
|
|
U8 noiseMapLevel[640*640];
|
|
U8 tex1[640*480];
|
|
|
|
F64 gDebugF640=0;
|
|
F64 gDebugF641=0;
|
|
I64 gDebugI640=0;
|
|
I64 gDebugI641=0;
|
|
|
|
Anim carAnim;
|
|
|
|
TextData txtInstructions;
|
|
txtInstructions.timer = 0;
|
|
txtInstructions.speed = 48.0;
|
|
txtInstructions.str = "-INSTRUCTIONS-
|
|
* GET TO THE END STAGE DOOR
|
|
* USE LASER GUN TO DESTROY
|
|
ENEMIES AND DIRT BLOCKS
|
|
* USE GRAPPLE HOOK TO
|
|
SWING OFF MOST BLOCKS
|
|
* HOLD JUMP MID-AIR,
|
|
RELEASE WHILE HOLDING
|
|
DESIRED DIRECTION
|
|
|
|
-CONTROLS-
|
|
LEFT MOUSE: USE ITEM
|
|
WASD: MOVEMENT
|
|
SPACE: (DOUBLE) JUMP
|
|
#: TOOLBAR
|
|
I: INVENTORY
|
|
M: KILL SOUND
|
|
ESC: CLOSE MENU
|
|
SHIFT+ESC: QUIT";
|
|
|
|
TextData txtDead;
|
|
txtDead.timer = 0;
|
|
txtDead.speed = 32.0;
|
|
txtDead.str = "DEAD";
|
|
|
|
TextData txtDeadPressSpace;
|
|
txtDeadPressSpace.timer = 0;
|
|
txtDeadPressSpace.speed = 32.0;
|
|
txtDeadPressSpace.str = "PRESS SPACE TO RESTART";
|
|
|
|
U0 QuitGame() {
|
|
gW.quitGame = TRUE;
|
|
}
|
|
|
|
U0 PlayerKill() {
|
|
if (gW.player.state != STATE_DEAD) {
|
|
txtDead.timer = 0;
|
|
txtDeadPressSpace.timer = 0;
|
|
}
|
|
gW.player.state = STATE_DEAD;
|
|
DebrisAddRand(&gW.debris, gW.player.pos.x+gW.player.size.x>>1,
|
|
gW.player.pos.y+gW.player.size.y>>1, 128, 8);
|
|
}
|
|
|
|
U0 ChangeLevel(I64 i) {
|
|
gW.activeLvl = Levels[i];
|
|
InitLevel(&gW, gW.activeLvl, noiseMapLevel);
|
|
gW.player.health = 100;
|
|
gW.player.pos.x = gW.level.spawn.x;
|
|
gW.player.pos.y = gW.level.spawn.y;
|
|
gW.player.vel.x = 0;
|
|
gW.player.vel.y = 0;
|
|
gW.player.dJumpAvail = FALSE;
|
|
gW.player.dJumpSpent = FALSE;
|
|
gW.player.state = STATE_STANDING;
|
|
gW.grapple.active = FALSE;
|
|
gW.grapple.hooked = FALSE;
|
|
StrPrint(gW.levelStr, "LEVEL: %d", gW.currentLevel);
|
|
|
|
gW.cam.x = gW.player.pos.x+gW.player.size.x>>1;
|
|
gW.cam.y = gW.player.pos.y+gW.player.size.y>>1;
|
|
UpdatePxUse(&gW.player);
|
|
}
|
|
|
|
U0 TriggerLevelEnd() {
|
|
SetSnd(SND_LVL_END);
|
|
gW.currentLevel++;
|
|
if (gW.currentLevel == LEVELS_TOTAL) {
|
|
InitEndScreen();
|
|
} else {
|
|
ChangeLevel(gW.currentLevel);
|
|
}
|
|
}
|
|
|
|
U0 DmgPlayer(F64 dmg) {
|
|
DebrisAddRand(&gW.debris, gW.player.pos.x+gW.player.size.x>>1,
|
|
gW.player.pos.y+gW.player.size.y>>1, 128, 8);
|
|
gW.player.health -= dmg;
|
|
if (gW.player.health <= 0)
|
|
PlayerKill();
|
|
}
|
|
|
|
U0 ApplyPlayerGravity(F64 delta) {
|
|
CD2 playerOffset;
|
|
playerOffset.x = gW.player.pos.x+8;
|
|
playerOffset.y = gW.player.pos.y+16;
|
|
CD2 length2;
|
|
length2.x = playerOffset.x-gW.grapple.pos.x;
|
|
length2.y = playerOffset.y-gW.grapple.pos.y;
|
|
F64 length = CD2Magnitude(&length2);
|
|
if (length >= gW.grapple.length && gW.grapple.hooked) {
|
|
// if (gW.grapple.hooked) {
|
|
CD2 gravity;
|
|
gravity.x = 0;
|
|
gravity.y = 350 * delta;
|
|
CD2 perp;
|
|
CD2Perpendicular(&gW.grapple.pos, &playerOffset, &perp);
|
|
CD2DotDirection(&gravity, &perp);
|
|
gW.player.vel.x += perp.x;
|
|
gW.player.vel.y += perp.y;
|
|
#ifdef DEBUG
|
|
//CommPrint("gravx: %.2f %.2f\n", gravity.x, gravity.y);
|
|
#endif
|
|
} else {
|
|
gW.player.vel.y += 350 * delta;
|
|
}
|
|
}
|
|
|
|
U0 MouseToTile(CD2I32 *tile) {
|
|
CD2I32 camI32;
|
|
camI32.x = gW.cam.x;
|
|
camI32.y = gW.cam.y;
|
|
tile->x = (ms.pos.x+camI32.x-320)/16;
|
|
tile->y = (ms.pos.y-8+camI32.y-240)/16;
|
|
}
|
|
|
|
Bool TileCheckBounds(CD2I32 pos) {
|
|
if (pos.x >= 0 && pos.y >= 0 &&
|
|
pos.x < gW.level.width &&
|
|
pos.y < gW.level.height) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
I64 TileToIndex(CD2I32 pos) {
|
|
return pos.y*gW.level.width+pos.x;
|
|
}
|
|
|
|
Bool DestroyBlock(I64 ti, CD2I32 tilePos) {
|
|
if (gW.level.tileType[ti] == TILE_COOLER1) {
|
|
I64 i;
|
|
Cooler *coolers = gW.coolers.d;
|
|
for (i=0; i<gW.coolers.len; i++) {
|
|
if (coolers[i].pos.x == tilePos.x && coolers[i].pos.y == tilePos.y) {
|
|
VectorDel(&gW.coolers, i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
gW.level.px[ti] = NULL;
|
|
gW.level.flags[ti] = TFLAG_NONE;
|
|
gW.level.tileType[ti] = TILE_NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
U0 MineBlock(I64 ti, CD2I32 tilePos) {
|
|
SetSnd(SND_MINE);
|
|
DebrisAddRand(&gW.debrisEarth, tilePos.x*16+8, tilePos.y*16, 64, 8);
|
|
I64 tileType = gW.level.tileType[ti];
|
|
U32 dmg = 8;
|
|
if (dmg >= gW.level.hp[ti]) {
|
|
/* Spawn Drop */
|
|
U64 rng = RandU64%100+1;
|
|
if (rng <= TILES[tileType].dropChance) {
|
|
F64 dir = RandI64%pi;
|
|
ItemAdd(&gW.items, TILES[tileType].drop, 1,
|
|
tilePos.x*16+8, tilePos.y*16+8,
|
|
Cos(dir)*128, Sin(dir)*128);
|
|
}
|
|
DestroyBlock(ti, tilePos);
|
|
} else {
|
|
gW.level.hp[ti] -= dmg;
|
|
I64 px = 4 - Ceil(ToF64(gW.level.hp[ti])/(TILES[tileType].hp/4)));
|
|
if (TILES[tileType].dmgPx[px]) {
|
|
gW.level.px[ti] = TILES[tileType].dmgPx[px];
|
|
}
|
|
}
|
|
}
|
|
|
|
U0 Shop() {
|
|
TradeOpen(&gUI);
|
|
}
|
|
|
|
Bool CheckTileFlagOverlap(CD2 *pos, CD2I32 size, U8 flag) {
|
|
I32 x, y;
|
|
I32 xStart = pos->x/16;
|
|
I32 xEnd = Ceil((pos->x+size.x)/16);
|
|
I32 yStart = pos->y/16;
|
|
I32 yEnd = Ceil((pos->y+size.y)/16);
|
|
for (y=yStart; y<yEnd; y++) {
|
|
if (y >= 0 && y <gW.level.height) {
|
|
for (x=xStart; x<xEnd; x++) {
|
|
if (x >= 0 && x < gW.level.width &&
|
|
gW.level.flags[y*gW.level.width+x] & flag) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
Bool CheckTileFlagOverlapPoint(CD2I32 pos, U8 flag) {
|
|
pos.x /= 16;
|
|
pos.y /= 16;
|
|
if (pos.x >= 0 && pos.y >= 0 &&
|
|
pos.x < gW.level.width &&
|
|
pos.y < gW.level.height &&
|
|
gW.level.flags[pos.y*gW.level.width+pos.x] & flag) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
U0 SetStateClimb() {
|
|
if (gW.player.state != STATE_CLIMB) {
|
|
gW.player.vel.x = 0;
|
|
gW.player.vel.y = 0;
|
|
gW.player.state = STATE_CLIMB;
|
|
}
|
|
}
|
|
|
|
U0 HandleLadder() {
|
|
if (gCtrl.cVel.y != 0) {
|
|
if (CheckTileFlagOverlap(&gW.player.pos, gW.player.size, TFLAG_LADDER))
|
|
SetStateClimb();
|
|
}
|
|
}
|
|
|
|
U0 HandleMouse() {
|
|
gUI.cursor = &CursorReg;
|
|
if (gUI.mouseConsumed)
|
|
return;
|
|
CD2I32 tile;
|
|
MouseToTile(&tile);
|
|
Bool inMap=FALSE;
|
|
if (TileCheckBounds(tile))
|
|
inMap=TRUE;
|
|
// Distance Limited Actions
|
|
Bool inRange=FALSE;
|
|
if (Abs(gW.player.pos.x+gW.player.size.x>>1-(tile.x*16+8)) < 24 &&
|
|
Abs(gW.player.pos.y+gW.player.size.y>>1-(tile.y*16+8)) < 32) {
|
|
inRange=TRUE;
|
|
}
|
|
I64 ti = TileToIndex(tile);
|
|
if (inMap && inRange && gW.level.flags[ti] & TFLAG_SHOP) {
|
|
if (gCtrl.mLDown) {
|
|
Shop();
|
|
} else {
|
|
gUI.cursor = &CursorBuy;
|
|
}
|
|
} else {
|
|
if (gCtrl.mLUp) {
|
|
if (gW.grapple.active) {
|
|
gW.grapple.active = FALSE;
|
|
gW.grapple.hooked = FALSE;
|
|
}
|
|
} else if (ms.lb) {
|
|
U8 itemType = gW.player.inv.items[gW.player.selItemSlot].id;
|
|
if (itemType == ITEM_PICKAXE && inMap && inRange && gW.level.flags[ti] & TFLAG_MINABLE) {
|
|
if (gW.player.cooldown > 0)
|
|
return;
|
|
gW.player.cooldown = 0.3;
|
|
gW.player.pxUseRot = 0.3;
|
|
MineBlock(ti, tile);
|
|
} else if (itemType == ITEM_GUN) {
|
|
// Fire Gun
|
|
SetSnd(SND_LASER);
|
|
Laser newLaser;
|
|
newLaser.vel.x = Cos(gUI.lookRot)*600;
|
|
newLaser.vel.y = Sin(gUI.lookRot)*600;
|
|
newLaser.pos.x = gW.player.pos.x+8;
|
|
newLaser.pos.y = gW.player.pos.y+16;
|
|
VectorAdd(&gW.lasers, &newLaser);
|
|
} else if (itemType == ITEM_GRAPPLE_GUN) {
|
|
// Fire Grapple Gun
|
|
if (gW.grapple.active == FALSE) {
|
|
SetSnd(SND_GRAPPLE_FIRE);
|
|
gW.grapple.active = TRUE;
|
|
gW.grapple.hooked = FALSE;
|
|
gW.grapple.vel.x = Cos(gUI.lookRot)*512;
|
|
gW.grapple.vel.y = Sin(gUI.lookRot)*512;
|
|
gW.grapple.pos.x = gW.player.pos.x+8;
|
|
gW.grapple.pos.y = gW.player.pos.y+16;
|
|
}
|
|
} else if (itemType == ITEM_GRENADE) {
|
|
Grenade newGrenade;
|
|
newGrenade.vel.x = Cos(gUI.lookRot)*256;
|
|
newGrenade.vel.y = Sin(gUI.lookRot)*256;
|
|
newGrenade.pos.x = gW.player.pos.x+8;
|
|
newGrenade.pos.y = gW.player.pos.y+16;
|
|
newGrenade.rot = 0;
|
|
newGrenade.ttl = 3;
|
|
VectorAdd(&gW.grenades, &newGrenade);
|
|
} else if (inMap && inRange && gItems[itemType].placeTile != TILE_NULL && gW.level.tileType[ti] == TILE_NULL) {
|
|
// Place Block
|
|
gW.player.pxUseRot = 1.0;
|
|
SetTile(&gW.level, ti, gItems[itemType].placeTile);
|
|
if (itemType == ITEM_COOLER) {
|
|
Cooler newCooler;
|
|
newCooler.pos.x = tile.x;
|
|
newCooler.pos.y = tile.y;
|
|
VectorAdd(&gW.coolers, &newCooler);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
U0 CloseMenu() {
|
|
if (gUI.flags&UI_INSTRUCTIONS_ENABLED)
|
|
gUI.flags = 0;
|
|
else if (gUI.flags&UI_INV_ENABLED)
|
|
InventoryClose(&gUI, &gW);
|
|
else if (gUI.flags&UI_TRADE_ENABLED)
|
|
TradeClose(&gUI);
|
|
else if (gUI.flags&UI_ESCMENU_ENABLED)
|
|
gUI.flags = 0;
|
|
else
|
|
gUI.flags |= UI_ESCMENU_ENABLED;
|
|
}
|
|
|
|
U0 GameUpdate(F64 delta) {
|
|
I64 i, x, y;
|
|
|
|
gUI.mouse.x = ms.pos.x;
|
|
gUI.mouse.y = ms.pos.y - 8;
|
|
|
|
/* Face Direction */
|
|
if (ms.pos.x >= 320) {
|
|
gW.player.flags &= PFLAG_ALL^PFLAG_FACE_LEFT;
|
|
gW.player.pxUseX = 7 + gW.player.pxUseOffset.x;
|
|
} else {
|
|
gW.player.flags |= PFLAG_FACE_LEFT;
|
|
gW.player.pxUseX = 8 - gW.player.pxUseOffset.x;
|
|
}
|
|
|
|
gUI.lookRot = Arg(gUI.mouse.x-320, gUI.mouse.y-240);
|
|
|
|
if (gCtrl.cEsc) {
|
|
CloseMenu();
|
|
gCtrl.cEsc = FALSE;
|
|
}
|
|
|
|
if (gCtrl.cTest0 == TRUE) {
|
|
gCtrl.cTest0 = FALSE;
|
|
OpenSimplex2S(Rand);
|
|
for (i=0; i<640*480; i++) {
|
|
x = i%640;
|
|
y = i/640;
|
|
noiseMap[i] = noise2_XBeforeY(ToF64(x)/gCtrl.cTest1, ToF64(y)/gCtrl.cTest1)*gCtrl.cTest2;
|
|
}
|
|
}
|
|
|
|
if (gCtrl.cInv) {
|
|
InventoryOpen(&gUI);
|
|
gCtrl.cInv = FALSE;
|
|
}
|
|
|
|
if (gUI.flags&UI_INSTRUCTIONS_ENABLED) {
|
|
txtInstructions.timer += delta;
|
|
return;
|
|
} else if (gUI.flags&UI_ESCMENU_ENABLED) {
|
|
HandleEscMenu(&gUI.escMenu, &gCtrl);
|
|
if (gUI.escMenu.buttonMainMenu.state == BUTTON_CLICKED) {
|
|
InitTitle();
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (gW.player.state == STATE_DEAD) {
|
|
txtDead.timer += delta;
|
|
txtDeadPressSpace.timer += delta;
|
|
}
|
|
|
|
gW.player.cooldown -= delta;
|
|
if (gW.player.cooldown < 0)
|
|
gW.player.cooldown = 0;
|
|
|
|
gW.player.pxUseRot -= delta;
|
|
if (gW.player.pxUseRot < 0)
|
|
gW.player.pxUseRot = 0;
|
|
|
|
// Handle Item Slot
|
|
if (gCtrl.cNum >= 0) {
|
|
gW.player.selItemSlot = gCtrl.cNum;
|
|
UpdatePxUse(&gW.player);
|
|
gCtrl.cNum = -1;
|
|
}
|
|
gUI.mouseConsumed = FALSE;
|
|
|
|
ToolbarHandle(&gUI, &gCtrl, &gW);
|
|
if (gUI.flags&UI_INV_ENABLED)
|
|
InventoryHandle(&gUI, &gW.player.inv, &gCtrl, &gW);
|
|
else if (gUI.flags&UI_TRADE_ENABLED)
|
|
TradeHandle(&gUI, &gCtrl, &gW);
|
|
else if (gUI.flags&UI_INSTRUCTIONS_ENABLED)
|
|
gUI.mouseConsumed = TRUE;
|
|
|
|
F64 vec;
|
|
switch (gW.player.state) {
|
|
case STATE_STANDING:
|
|
gW.player.dJumpAvail = FALSE;
|
|
gW.player.dJumpSpent = FALSE;
|
|
if (gCtrl.cJump) {
|
|
gW.player.state = STATE_JUMPING;
|
|
if (gW.player.vel.y > -300)
|
|
gW.player.vel.y = -300;
|
|
SetAnimNManJump(&gW.player.anim);
|
|
} else if (gCtrl.cVel.x != 0) {
|
|
gW.player.state = STATE_WALKING;
|
|
SetAnimNManWalkR(&gW.player.anim);
|
|
}
|
|
HandleMouse();
|
|
HandleLadder();
|
|
ApplyPlayerGravity(delta);
|
|
break;
|
|
case STATE_WALKING:
|
|
gW.player.dJumpAvail = FALSE;
|
|
gW.player.dJumpSpent = FALSE;
|
|
// gW.player.flags &= PFLAG_NONE; // add extra flags here
|
|
if (gCtrl.cJump) {
|
|
gW.player.state = STATE_JUMPING;
|
|
gW.player.vel.y -= 300;
|
|
SetAnimNManJump(&gW.player.anim);
|
|
} else if (gCtrl.cVel.x == 0) {
|
|
if (gW.player.vel.x == 0) {
|
|
gW.player.state = STATE_STANDING;
|
|
SetAnimNManStand(&gW.player.anim);
|
|
} else {
|
|
// gW.player.state = STATE_STANDING;
|
|
// SetAnimNManStand(&gW.player.anim);
|
|
}
|
|
}
|
|
HandleMouse();
|
|
HandleLadder();
|
|
ApplyPlayerGravity(delta);
|
|
break;
|
|
case STATE_JUMPING:
|
|
HandleMouse();
|
|
if (gCtrl.cJump == FALSE) {
|
|
gW.player.dJumpAvail = TRUE;
|
|
} else if (gCtrl.cJump && !gW.player.dJumpSpent && gW.player.dJumpAvail) {
|
|
gW.player.dJumpAvail = FALSE;
|
|
gW.player.dJumpSpent = TRUE;
|
|
gW.player.state = STATE_DJUMP_CHARGE;
|
|
gW.player.vel.x = 0;
|
|
gW.player.vel.y = 0;
|
|
break;
|
|
}
|
|
if (gW.player.vel.y >= 0) {
|
|
gW.player.state = STATE_FALLING;
|
|
SetAnimNManFall(&gW.player.anim);
|
|
}
|
|
HandleLadder();
|
|
ApplyPlayerGravity(delta);
|
|
break;
|
|
case STATE_FALLING:
|
|
HandleMouse();
|
|
if (gCtrl.cJump == FALSE) {
|
|
gW.player.dJumpAvail = TRUE;
|
|
} else if (gCtrl.cJump && !gW.player.dJumpSpent && gW.player.dJumpAvail) {
|
|
gW.player.dJumpAvail = FALSE;
|
|
gW.player.dJumpSpent = TRUE;
|
|
gW.player.state = STATE_DJUMP_CHARGE;
|
|
gW.player.vel.x = 0;
|
|
gW.player.vel.y = 0;
|
|
break;
|
|
}
|
|
// gW.player.flags &= PFLAG_NONE; // add extra flags here
|
|
if (gW.player.vel.y <= 0) {
|
|
gW.player.state = STATE_STANDING;
|
|
SetAnimNManStand(&gW.player.anim);
|
|
}
|
|
HandleLadder();
|
|
ApplyPlayerGravity(delta);
|
|
break;
|
|
case STATE_DJUMP_CHARGE:
|
|
if (gCtrl.cJump == FALSE) {
|
|
gW.player.state = STATE_DJUMP;
|
|
if (gCtrl.cVel.x == 0 && gCtrl.cVel.y == 0)
|
|
vec = Arg(0, -1);
|
|
else
|
|
vec = Arg(gCtrl.cVel.x, gCtrl.cVel.y);
|
|
gW.player.vel.x = Cos(vec)*400;
|
|
gW.player.vel.y = Sin(vec)*400;
|
|
}
|
|
break;
|
|
case STATE_DJUMP:
|
|
HandleMouse();
|
|
if (gW.player.vel.y >= 0) {
|
|
gW.player.state = STATE_FALLING;
|
|
SetAnimNManFall(&gW.player.anim);
|
|
}
|
|
HandleLadder();
|
|
ApplyPlayerGravity(delta);
|
|
break;
|
|
case STATE_CLIMB:
|
|
HandleMouse();
|
|
HandleLadder();
|
|
ApplyDrag(&gW.player.vel.x, 256, delta);
|
|
ApplyDrag(&gW.player.vel.y, 256, delta);
|
|
if (Abs(gW.player.vel.y) < 128) {
|
|
gW.player.vel.y += gCtrl.cVel.y * 512 * delta;
|
|
}
|
|
if (!CheckTileFlagOverlap(&gW.player.pos, gW.player.size, TFLAG_LADDER)) {
|
|
gW.player.state = STATE_FALLING;
|
|
}
|
|
break;
|
|
case STATE_DEAD:
|
|
ApplyPlayerGravity(delta);
|
|
if (gCtrl.cJump) {
|
|
if (gW.currentLevel >= 0)
|
|
ChangeLevel(gW.currentLevel);
|
|
else
|
|
InitSandbox();
|
|
}
|
|
break;
|
|
default:
|
|
}
|
|
|
|
if (gW.player.state != STATE_DEAD) {
|
|
if (gW.grapple.hooked) {
|
|
if (Abs(gW.player.vel.x) < 300) {
|
|
gW.player.vel.x += gCtrl.cVel.x * 1024 * delta;
|
|
}
|
|
} else if (gW.player.state != STATE_DJUMP_CHARGE) {
|
|
// Apply Player Controls
|
|
if (Abs(gW.player.vel.x) < 128) {
|
|
gW.player.vel.x += gCtrl.cVel.x * 512 * delta;
|
|
}
|
|
// if (Abs(gW.player.vel.y) < 128) {
|
|
// gW.player.vel.y += gCtrl.cVel.y * 512 * delta;
|
|
// }
|
|
}
|
|
}
|
|
|
|
// Apply Grapple Constraint
|
|
CD2 length2;
|
|
I64 ti;
|
|
F64 dist;
|
|
if (gW.grapple.active && gW.grapple.hooked) {
|
|
CD2 playerOffset;
|
|
playerOffset.x = gW.player.pos.x+8;
|
|
playerOffset.y = gW.player.pos.y+16;
|
|
length2.x = playerOffset.x-gW.grapple.pos.x;
|
|
length2.y = playerOffset.y-gW.grapple.pos.y;
|
|
F64 length = CD2Magnitude(&length2);
|
|
if (length >= gW.grapple.length) {
|
|
/* Get Perpendicular Direction */
|
|
CD2 perp;
|
|
CD2Perpendicular(&gW.grapple.pos, &playerOffset, &perp);
|
|
CD2DotDirection(&gW.player.vel, &perp);
|
|
CD2Normalize(&perp);
|
|
dist = CD2Magnitude(&gW.player.vel);
|
|
gW.player.vel.x = perp.x * dist;
|
|
gW.player.vel.y = perp.y * dist;
|
|
#ifdef DEBUG
|
|
CommPrint("perpx %.2f perpy %.2f dist: %.2f pvel: %.2f %.2f\n", perp.x, perp.y, dist, gW.player.vel.x, gW.player.vel.y);
|
|
#endif
|
|
/*
|
|
CD2 diff;
|
|
diff.x = gW.grapple.pos.x - gW.player.pos.x+8;
|
|
diff.y = gW.grapple.pos.y - gW.player.pos.y+16;
|
|
dist = CD2Magnitude(&diff);
|
|
*/
|
|
|
|
// if (length >= gW.grapple.length) {
|
|
F64 moveDist = length - gW.grapple.length;
|
|
CD2Normalize(&length2);
|
|
length2.x *= moveDist;
|
|
length2.y *= moveDist;
|
|
#ifdef DEBUG
|
|
//CommPrint(MFA_COM, "dist %f | moveDist: %f | diffy: %f\n", dist, moveDist, diff.y);
|
|
#endif
|
|
gW.player.pos.x -= length2.x;
|
|
gW.player.pos.y -= length2.y;
|
|
// }
|
|
}
|
|
}
|
|
|
|
// Update Spawners
|
|
UpdateAnim(&carAnim, delta);
|
|
Spawner *spawners = gW.spawners.d;
|
|
for (i=0; i<gW.spawners.len; i++) {
|
|
spawners[i].ttl -= delta;
|
|
if (spawners[i].ttl <= 0) {
|
|
spawners[i].ttl = SPAWNER_TTL;
|
|
AddMob(&gW.mobs, &gW.cMobs, spawners[i].pos.x, spawners[i].pos.y);
|
|
}
|
|
}
|
|
|
|
// Apply Player Velocity/Collision
|
|
ApplyVelCollideTile(&gW.level, delta, &gW.player.pos, &gW.player.vel, gW.player.size.x, gW.player.size.y);
|
|
|
|
// Mob AI
|
|
MobAI(&gW, delta);
|
|
|
|
Mob *mobs = gW.mobs.d;
|
|
I64 ii;
|
|
// Apply Mob Velocity/Collision
|
|
for (i=0; i<gW.mobs.len; i++) {
|
|
ApplyDrag(&mobs[i].vel.x, 48, delta);
|
|
ApplyDrag(&mobs[i].vel.y, 48, delta);
|
|
mobs[i].vel.y += 350 * delta; // Apply Gravity
|
|
ApplyVelCollideTile(&gW.level, delta, &mobs[i].pos, &mobs[i].vel, mobs[i].size.x, mobs[i].size.y);
|
|
}
|
|
GenCMobs(gW.mobs.d, gW.mobs.len, gW.cMobs.d);
|
|
|
|
// Process Player I-Frames
|
|
gW.player.inv_ttl -= delta;
|
|
if (gW.player.inv_ttl < 0)
|
|
gW.player.inv_ttl=0;
|
|
|
|
// Player Mob Collision
|
|
F64 rot;
|
|
Vec4 aabb1;
|
|
if (gW.player.inv_ttl <= 0) {
|
|
aabb1.x1 = gW.player.pos.x;
|
|
aabb1.x2 = gW.player.pos.x + gW.player.size.x;
|
|
aabb1.y1 = gW.player.pos.y;
|
|
aabb1.y2 = gW.player.pos.y + gW.player.size.y;
|
|
mobs = gW.mobs.d;
|
|
Vec4 *cMobs = gW.cMobs.d;
|
|
for (i=0; i<gW.cMobs.len; i++) {
|
|
if (CheckCollisionAABB(&aabb1, &cMobs[i])) {
|
|
SetSnd(SND_PLAYER_DMG);
|
|
DmgPlayer(10);
|
|
rot = Arg(gW.player.pos.x+gW.player.size.x>>1 - (mobs[i].pos.x+mobs[i].size.x>>1),
|
|
gW.player.pos.y+gW.player.size.y>>1 - (mobs[i].pos.y+mobs[i].size.y>>1));
|
|
gW.player.vel.x = Cos(rot) * 256;
|
|
gW.player.vel.y = Sin(rot) * 256;
|
|
gW.player.inv_ttl = 3;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// Laser Collision
|
|
Laser *lasers = gW.lasers.d;
|
|
mobs = gW.mobs.d;
|
|
cMobs = gW.cMobs.d;
|
|
for (i=0; i<gW.lasers.len;) {
|
|
for (ii=0; ii<gW.cMobs.len; ii++) {
|
|
if (CheckCollisionPoint(&cMobs[ii], &lasers[i].pos)) {
|
|
SetSnd(SND_MOB_HIT);
|
|
F64 angle = Arg(lasers[i].vel.x, lasers[i].vel.y);
|
|
mobs[ii].vel.x += Cos(angle)*64;
|
|
mobs[ii].vel.y += Sin(angle)*64;
|
|
MobDmg(&gW, ii, 1);
|
|
VectorDel(&gW.lasers, i);
|
|
goto nextLaserCollision;
|
|
}
|
|
}
|
|
i++;
|
|
nextLaserCollision:
|
|
}
|
|
|
|
for (i=0; i<gW.mobs.len;) {
|
|
if (mobs[i].health <= 0) {
|
|
VectorDel(&gW.mobs, i);
|
|
VectorDel(&gW.cMobs, i);
|
|
// TODO Create Gibs
|
|
goto nextMobDeath;
|
|
}
|
|
i++;
|
|
nextMobDeath:
|
|
}
|
|
|
|
lasers = gW.lasers.d;
|
|
spawners = gW.spawners.d;
|
|
for (i=0; i<gW.lasers.len;) {
|
|
for (ii=0; ii<gW.spawners.len; ii++) {
|
|
Vec4 vec4;
|
|
vec4.x1 = spawners[ii].pos.x;
|
|
vec4.y1 = spawners[ii].pos.y;
|
|
vec4.x2 = vec4.x+SPAWNER_W;
|
|
vec4.y2 = vec4.y+SPAWNER_H;
|
|
if (CheckCollisionPoint(&vec4, &lasers[i].pos)) {
|
|
SetSnd(SND_MOB_HIT);
|
|
SpawnerDmg(&gW, ii, 1);
|
|
VectorDel(&gW.lasers, i);
|
|
goto nextLaserCollisionSpawners;
|
|
}
|
|
}
|
|
i++;
|
|
nextLaserCollisionSpawners:
|
|
}
|
|
|
|
// Update Camera
|
|
gW.cam.x = gW.player.pos.x+gW.player.size.x>>1;
|
|
gW.cam.y = gW.player.pos.y+gW.player.size.y>>1;
|
|
|
|
ItemDrop *items = gW.items.d;
|
|
CD2I32 tile;
|
|
for (i=0; i<gW.items.len; i++, items++) {
|
|
items->ttl += delta;
|
|
ApplyDrag(&items->vel.x, 48, delta);
|
|
items->vel.y += 350 * delta; // Apply Gravity
|
|
ApplyVelCollideTileBounce(&gW.level, delta, &items->pos, &items->vel, 8, 8);
|
|
}
|
|
|
|
// Update Gibs
|
|
Gib *gibs = gW.gibs.d;
|
|
for (i=0; i<gW.gibs.len;) {
|
|
gibs->ttl -= delta;
|
|
if (gibs->ttl <= 0) {
|
|
VectorDel(&gW.gibs, i);
|
|
goto nextGib;
|
|
}
|
|
gibs->rot += gibs->vel.x/16 * delta;
|
|
ApplyDrag(&gibs->vel.x, 48, delta);
|
|
gibs->vel.y += 350 * delta; // Apply Gravity
|
|
ApplyVelCollidePointTileBounce(&gW.level, delta, &gibs->pos, &gibs->vel);
|
|
gibs++;
|
|
i++;
|
|
nextGib:
|
|
}
|
|
|
|
// Update Grenades
|
|
items = gW.items.d;
|
|
Grenade *grenades = gW.grenades.d;
|
|
for (i=0; i<gW.grenades.len;) {
|
|
grenades->ttl -= delta;
|
|
if (grenades->ttl <= 0) {
|
|
SetSnd(SND_EXPLOSION);
|
|
// Apply Explosion Damage
|
|
for (ii=0; ii<gW.items.len; ii++) {
|
|
dist = Abs(grenades->pos.x-items[ii].pos.x)+Abs(grenades->pos.y-items[ii].pos.y);
|
|
if (dist < 128) {
|
|
rot = Arg(items[ii].pos.x-grenades->pos.x, items[ii].pos.y-grenades->pos.y);
|
|
items[ii].vel.x += Cos(rot)*100;
|
|
items[ii].vel.y += Sin(rot)*100;
|
|
}
|
|
}
|
|
for (tile.y=MaxI64(ToI64(grenades->pos.y/16)-4, 0); tile.y<MinI64(ToI64(grenades->pos.y)/16+4, gW.level.height); tile.y++) {
|
|
for (tile.x=MaxI64(ToI64(grenades->pos.x)/16-4, 0); tile.x<MinI64(ToI64(grenades->pos.x)/16+4, gW.level.width); tile.x++) {
|
|
ti = tile.y*gW.level.width + tile.x;
|
|
if (gW.level.flags[ti] & TFLAG_BLOCK) {
|
|
if (gW.level.flags[ti] & TFLAG_MINABLE)
|
|
MineBlock(ti, tile);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add Explosion Animation
|
|
Explosion newExp;
|
|
newExp.pos.x = grenades->pos.x;
|
|
newExp.pos.y = grenades->pos.y;
|
|
newExp.ttl = 1;
|
|
VectorAdd(&gW.explosions, &newExp);
|
|
VectorDel(&gW.grenades, i);
|
|
goto nextGrenade;
|
|
}
|
|
grenades->rot += grenades->vel.x/16 * delta;
|
|
ApplyDrag(&grenades->vel.x, 48, delta);
|
|
grenades->vel.y += 350 * delta; // Apply Gravity
|
|
ApplyVelCollidePointTileBounce(&gW.level, delta, &grenades->pos, &grenades->vel);
|
|
i++;
|
|
grenades++;
|
|
nextGrenade:
|
|
}
|
|
|
|
// Handle Explosions
|
|
Explosion *exps = gW.explosions.d;
|
|
for (i=0; i<gW.explosions.len;) {
|
|
exps[i].ttl -= delta;
|
|
if (exps[i].ttl <= 0) {
|
|
VectorDel(&gW.explosions, i);
|
|
goto nextExp;
|
|
}
|
|
i++;
|
|
nextExp:
|
|
}
|
|
|
|
// Pickup Items
|
|
items = gW.items.d;
|
|
aabb1.x1 = gW.player.pos.x;
|
|
aabb1.x2 = gW.player.pos.x + gW.player.size.x;
|
|
aabb1.y1 = gW.player.pos.y;
|
|
aabb1.y2 = gW.player.pos.y + gW.player.size.y;
|
|
for (i=0; i<gW.items.len;) {
|
|
Vec4 aabb2;
|
|
aabb2.x1 = items->pos.x;
|
|
aabb2.x2 = items->pos.x + 8;
|
|
aabb2.y1 = items->pos.y;
|
|
aabb2.y2 = items->pos.y + 8;
|
|
if (CheckCollisionAABB(&aabb1, &aabb2)) {
|
|
InvAdd(&gW.player.inv, items->type, items->qty);
|
|
ToolbarUpdate(&gUI.toolbar, &gW.player);
|
|
VectorDel(&gW.items, i);
|
|
goto nextItemPickup;
|
|
}
|
|
i++;
|
|
items++;
|
|
nextItemPickup:
|
|
}
|
|
|
|
// Check for status tiles
|
|
I64 tmpX = ToI64(gW.player.pos.x)/16;
|
|
I64 tmpY = ToI64(gW.player.pos.y)/16;
|
|
I64 tw = Ceil((gW.player.pos.x+gW.player.size.x)/16);
|
|
I64 th = Ceil((gW.player.pos.y+gW.player.size.y)/16);
|
|
for (y=tmpY; y<th; y++) {
|
|
if (y >= 0 && y < gW.level.height) {
|
|
for (x=tmpX; x<tw; x++) {
|
|
if (x >= 0 && x < gW.level.width) {
|
|
U8 flag = gW.level.flags[y*gW.level.width+x];
|
|
if (flag & TFLAG_KILL) {
|
|
PlayerKill();
|
|
} else if (flag & TFLAG_END) {
|
|
TriggerLevelEnd();
|
|
return;
|
|
}
|
|
} else { // out of bounds
|
|
PlayerKill();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Apply Laser Velocity
|
|
lasers = gW.lasers.d;
|
|
for (i=0; i<gW.lasers.len; i++) {
|
|
lasers[i].pos.x += lasers[i].vel.x * delta;
|
|
lasers[i].pos.y += lasers[i].vel.y * delta;
|
|
}
|
|
|
|
// Handle Lasers
|
|
for (i=0; i<gW.lasers.len; i++) {
|
|
IVec4 line;
|
|
line.x1 = gW.lasers.d(Laser*)[i].pos.x;
|
|
line.y1 = gW.lasers.d(Laser*)[i].pos.y;
|
|
line.x2 = line.x1 + gW.lasers.d(Laser*)[i].vel.x/32;
|
|
line.y2 = line.y1 + gW.lasers.d(Laser*)[i].vel.y/32;
|
|
|
|
if (line.x1 < 0 || line.y1 < 0 || line.x2 < 0 || line.y2 < 0 ||
|
|
line.x1 >= gW.level.widthPx || line.x2 >= gW.level.widthPx ||
|
|
line.y1 >= gW.level.heightPx || line.y2 >= gW.level.heightPx) {
|
|
VectorDel(&gW.lasers, i--);
|
|
goto nextHandleLaser;
|
|
}
|
|
|
|
// Find Relevant Tiles
|
|
// Bresenham's Line Algo
|
|
I32 dx, dy;
|
|
if (line.x2 >= line.x1) {
|
|
dx = line.x2 - line.x1;
|
|
} else {
|
|
dx = line.x1 - line.x2;
|
|
}
|
|
if (line.y2 >= line.y1) {
|
|
dy = line.y1 - line.y2;
|
|
} else {
|
|
dy = line.y2 - line.y1;
|
|
}
|
|
|
|
CD2I32 slope;
|
|
if (line.x1 < line.x2) {
|
|
slope.x = 1;
|
|
} else {
|
|
slope.x = -1;
|
|
}
|
|
if (line.y1 < line.y2) {
|
|
slope.y = 1;
|
|
} else {
|
|
slope.y = -1;
|
|
}
|
|
|
|
I32 err=dx+dy, e2;
|
|
while (TRUE) {
|
|
CD2I32 laserPxPos;
|
|
tile.x = line.x1/16;
|
|
tile.y = line.y1/16;
|
|
ti = tile.y*gW.level.width + tile.x;
|
|
if (gW.level.flags[ti] & TFLAG_BLOCK) {
|
|
if (gW.level.flags[ti] & TFLAG_MINABLE)
|
|
MineBlock(ti, tile);
|
|
VectorDel(&gW.lasers, i--);
|
|
break;
|
|
}
|
|
|
|
laserPxPos.x = line.x1 + 320;
|
|
laserPxPos.y = line.y1 + 240;
|
|
VectorAdd(&gW.laserPixels, &laserPxPos);
|
|
if (line.x1==line.x2 && line.y1==line.y2)
|
|
break;
|
|
e2 = 2 * err;
|
|
if (e2 >= dy) {
|
|
err += dy;
|
|
line.x1 += slope.x;
|
|
}
|
|
if (e2 <= dx) {
|
|
err += dx;
|
|
line.y1 += slope.y;
|
|
}
|
|
}
|
|
nextHandleLaser:
|
|
}
|
|
|
|
// Apply Grapple Velocity
|
|
if (gW.grapple.active && !gW.grapple.hooked) {
|
|
gW.grapple.pos.x += gW.grapple.vel.x * delta;
|
|
gW.grapple.pos.y += gW.grapple.vel.y * delta;
|
|
|
|
if (gW.grapple.pos.x >= 0 && gW.grapple.pos.y >= 0) {
|
|
x = gW.grapple.pos.x/16;
|
|
y = gW.grapple.pos.y/16;
|
|
if (x < gW.level.width && y < gW.level.height) {
|
|
ti = y*gW.level.width + x;
|
|
if (gW.level.flags[ti] & TFLAG_NOHOOK) {
|
|
gW.grapple.active = FALSE;
|
|
} else if (gW.level.flags[ti] & TFLAG_BLOCK) {
|
|
SetSnd(SND_GRAPPLE_HIT);
|
|
gW.player.dJumpAvail = FALSE;
|
|
gW.player.dJumpSpent = FALSE;
|
|
if (gW.player.state != STATE_DEAD)
|
|
gW.player.state = STATE_FALLING;
|
|
gW.grapple.hooked = TRUE;
|
|
playerOffset.x = gW.player.pos.x+8;
|
|
playerOffset.y = gW.player.pos.y+16;
|
|
CD2Perpendicular(&gW.grapple.pos, &playerOffset, &perp);
|
|
CD2DotDirection(&gW.player.vel, &perp);
|
|
gW.player.vel.x = perp.x;
|
|
gW.player.vel.y = perp.y;
|
|
length2.x = gW.player.pos.x+8-gW.grapple.pos.x;
|
|
length2.y = gW.player.pos.y+16-gW.grapple.pos.y;
|
|
gW.grapple.length = CD2Magnitude(&length2);
|
|
}
|
|
} else {
|
|
gW.grapple.active = FALSE;
|
|
}
|
|
} else {
|
|
gW.grapple.active = FALSE;
|
|
}
|
|
}
|
|
|
|
// Update Heat
|
|
F64 temp = tmpY-32;
|
|
gW.player.heat += temp * delta / 4;
|
|
Cooler *coolers = gW.coolers.d;
|
|
for (i=0; i<gW.coolers.len; i++) {
|
|
if (Abs(gW.player.pos.x-(coolers[i].pos.x*16+8))+Abs(gW.player.pos.y-(coolers[i].pos.y*16+8)) < 64) {
|
|
gW.player.heat -= 10 * delta;
|
|
break;
|
|
}
|
|
}
|
|
if (gW.player.heat < 0)
|
|
gW.player.heat = 0;
|
|
|
|
// Velocity Drag
|
|
if (gW.grapple.hooked)
|
|
ApplyDrag(&gW.player.vel.x, 64, delta);
|
|
else
|
|
ApplyDrag(&gW.player.vel.x, 128, delta);
|
|
|
|
// Update Animations
|
|
UpdateAnim(&gW.player.anim, delta);
|
|
|
|
// Update Mob Animations
|
|
mobs = gW.mobs.d;
|
|
for (i=0; i<gW.mobs.len; i++) {
|
|
UpdateAnim(&mobs[i].anim, delta);
|
|
}
|
|
|
|
// Update Debris
|
|
Debris *debris = gW.debris.d;
|
|
for (i=0; i<gW.debris.len; i++) {
|
|
debris[i].vel.y += 128.0 * delta;
|
|
debris[i].pos.x += debris[i].vel.x * delta;
|
|
debris[i].pos.y += debris[i].vel.y * delta;
|
|
if (debris[i].pos.x+320 <= gW.cam.x ||
|
|
debris[i].pos.x-320 >= gW.cam.x ||
|
|
debris[i].pos.y+240 <= gW.cam.y ||
|
|
debris[i].pos.y-240 >= gW.cam.y ) {
|
|
VectorDel(&gW.debris, i--);
|
|
}
|
|
}
|
|
|
|
debris = gW.debrisEarth.d;
|
|
for (i=0; i<gW.debrisEarth.len; i++) {
|
|
debris[i].vel.y += 128.0 * delta;
|
|
debris[i].pos.x += debris[i].vel.x * delta;
|
|
debris[i].pos.y += debris[i].vel.y * delta;
|
|
if (debris[i].pos.x+320 <= gW.cam.x ||
|
|
debris[i].pos.x-320 >= gW.cam.x ||
|
|
debris[i].pos.y+240 <= gW.cam.y ||
|
|
debris[i].pos.y-240 >= gW.cam.y ) {
|
|
VectorDel(&gW.debrisEarth, i--);
|
|
}
|
|
}
|
|
|
|
// Update Cursor
|
|
/*
|
|
CD2I32 mSel;
|
|
mSel.x = ms.pos.x+gW.cam.x-319;
|
|
mSel.y = ms.pos.y-8+gW.cam.y-239;
|
|
if (CheckTileFlagOverlapPoint(mSel, TFLAG_SHOP)) {
|
|
gUI.cursor = &CursorBuy;
|
|
} else {
|
|
gUI.cursor = &CursorReg;
|
|
}
|
|
*/
|
|
}
|
|
|
|
U0 DrawGame(CTask*, CDC *dc) {
|
|
// Draw Background Fluff
|
|
I64 i;
|
|
CD2I32 cam;
|
|
cam.x = ToI64(gW.cam.x);
|
|
cam.y = ToI64(gW.cam.y);
|
|
|
|
// Draw Background
|
|
DrawBackground(dc->body, cam);
|
|
// MemSet(tex1, TRANSPARENT, 640*480);
|
|
DrawTiles(dc->body, &gW.cam, &gW.level);
|
|
|
|
// Draw Cooling Circles
|
|
Cooler *coolers = gW.coolers.d;
|
|
dc->color = SWEET_BLUE_LT;
|
|
for (i=0; i<gW.coolers.len; i++) {
|
|
GrCircle(dc, coolers[i].pos.x*16+8-gW.cam.x+320, coolers[i].pos.y*16+8-gW.cam.y+240, 64);
|
|
}
|
|
|
|
// Draw Spawners
|
|
Spawner *spawners = gW.spawners.d;
|
|
for (i=0; i<gW.spawners.len; i++) {
|
|
//PxBlot(dc->body, &Car1, spawners[i].pos.x-cam.x+320, spawners[i].pos.y-cam.y+240);
|
|
DrawAnim(dc, &carAnim, spawners[i].pos.x-cam.x+320, spawners[i].pos.y-cam.y+240, 0);
|
|
}
|
|
|
|
// Draw Mobs
|
|
Mob *mobs = gW.mobs.d;
|
|
for (i=0; i<gW.mobs.len; i++)
|
|
DrawAnim(dc, &mobs[i].anim, ToI64(mobs[i].pos.x-gW.cam.x)+mobs[i].drawOffset.x+320, ToI64(mobs[i].pos.y-gW.cam.y)+mobs[i].drawOffset.y+240, mobs[i].flags&PFLAG_FACE_LEFT);
|
|
|
|
// Draw Player
|
|
I64 playerX = ToI64(gW.player.pos.x-gW.cam.x)+320;
|
|
I64 playerY = ToI64(gW.player.pos.y-gW.cam.y)+240;
|
|
if (ToI64(gW.player.inv_ttl*8)%2 == 0)
|
|
DrawAnim(dc, &gW.player.anim, playerX, playerY, gW.player.flags&PFLAG_FACE_LEFT);
|
|
|
|
// Draw Player Equipment
|
|
if (gW.player.pxUse) {
|
|
//GrLine(dc, 320, 240, Cos(gUI.lookRot)*32+320, Sin(gUI.lookRot)*32+240);
|
|
PxBlotRotZ(dc, gW.player.pxUse, playerX+gW.player.pxUseX,
|
|
playerY+gW.player.pxUseOffset.y, gUI.lookRot,
|
|
gW.player.pxUseRot*3%(pi/2), gW.player.flags&PFLAG_FACE_LEFT,
|
|
gW.player.pxUseStyle);
|
|
}
|
|
|
|
// Draw Items
|
|
// MemSet(tex1, TRANSPARENT, 640*480);
|
|
ItemDrop *items = gW.items.d;
|
|
for (i=0; i<gW.items.len; i++) {
|
|
PxBlot(dc->body, items[i].px, ToI64(items[i].pos.x-gW.cam.x)+320,
|
|
ToI64(items[i].pos.y-gW.cam.y)+240 + Sin(items[i].ttl*3)*3);
|
|
// PxBlot(tex1, items[i].px, ToI64(items[i].pos.x-gW.cam.x)+320,
|
|
// ToI64(items[i].pos.y-gW.cam.y)+240 + Sin(items[i].ttl*3)*3);
|
|
}
|
|
/*
|
|
ts = tS*60;
|
|
for (y=0; y<480; y++) {
|
|
for (x=0; x<640; x++) {
|
|
I64 xx = (x + ts);//%640;
|
|
tx = (xx + gW.cam.x + 320)%640;
|
|
ty = (y + gW.cam.y + 240)%480;
|
|
xx = x + noiseMap[ty*640+tx];
|
|
if (xx >= 640)
|
|
xx = 640;
|
|
else if (xx < 0)
|
|
xx = 0;
|
|
if (tex1[y*640+xx] != TRANSPARENT)
|
|
dc->body[y*640+x] = tex1[y*640+xx];
|
|
}
|
|
}
|
|
*/
|
|
|
|
// Draw Debris
|
|
Debris *debris = gW.debris.d;
|
|
for (i=0; i<gW.debris.len; i++) {
|
|
dc->color = SWEET_GREEN;
|
|
GrRect(dc, debris[i].pos.x-gW.cam.x+320, debris[i].pos.y-gW.cam.y+240, 4, 4);
|
|
}
|
|
|
|
// Draw Earth Debris
|
|
debris = gW.debrisEarth.d;
|
|
for (i=0; i<gW.debrisEarth.len; i++) {
|
|
PxBlot(dc->body, &tEarthDebris, debris[i].pos.x-gW.cam.x+320, debris[i].pos.y-gW.cam.y+240);
|
|
}
|
|
|
|
if (gW.player.state == STATE_DEAD) {
|
|
DrawTextBounce(dc->body, &fontBig, &txtDead, 290, 240);
|
|
DrawTextBounce(dc->body, &fontBig, &txtDeadPressSpace, 160, 260);
|
|
}
|
|
|
|
// Draw Gibs
|
|
DrawGibs(dc, gW.gibs.d, gW.gibs.len, cam);
|
|
|
|
// Draw Grenades
|
|
Grenade *grenades = gW.grenades.d;
|
|
for (i=0; i<gW.grenades.len; i++) {
|
|
PxBlotRotZ(dc, &ItemGrenade, ToI64(grenades[i].pos.x-gW.cam.x)+320,
|
|
ToI64(grenades[i].pos.y-gW.cam.y)+240+Sin(grenades[i].ttl*3)*3,
|
|
grenades[i].rot, 0, 0, 0);
|
|
}
|
|
|
|
// Draw Lasers
|
|
dc->color = SWEET_GREEN;
|
|
CD2I32 *laserPx = gW.laserPixels.d;
|
|
for (i=0; i<gW.laserPixels.len; i++)
|
|
GrPlot1(dc, laserPx[i].x-gW.cam.x, laserPx[i].y-gW.cam.y);
|
|
gW.laserPixels.len = 0;
|
|
|
|
// Draw Explosions
|
|
Explosion *exps = gW.explosions.d;
|
|
for (i=0; i<gW.explosions.len; i++)
|
|
PxBlot(dc->body, ExplosionFrames[exps[i].ttl*6], exps[i].pos.x-gW.cam.x+320-16, exps[i].pos.y-gW.cam.y+240-16);
|
|
|
|
if (gCtrl.cTest3) {
|
|
for (i=8*dc->width_internal; i<dc->width_internal*dc->height; i++) {
|
|
dc->body[i] = noiseMapLevel[i]%16;
|
|
}
|
|
}
|
|
|
|
// Draw Grapple
|
|
if (gW.grapple.active) {
|
|
GrLine(dc, gW.grapple.pos.x-gW.cam.x+320, gW.grapple.pos.y-gW.cam.y+240, playerX+8, playerY+16);
|
|
PxBlot(dc->body, &GrappleGunHook, gW.grapple.pos.x-gW.cam.x+320-4, gW.grapple.pos.y-gW.cam.y+240-6);
|
|
}
|
|
|
|
// Draw Shader
|
|
/*
|
|
U8 *backbuffer = MAlloc(640*480);
|
|
U8 color;
|
|
MemCpy(backbuffer, dc->body, 640*480);
|
|
// MemSet(dc->body, 0, 640*480);
|
|
|
|
I64 yy;
|
|
ts = tS*20;
|
|
// ts = 0;
|
|
I64 tts = Abs((tS*20%64)-32);
|
|
//tts = (Sin(tS*4)+1)*15.5;
|
|
//tts = tS*30%32;
|
|
for (i=8*dc->width_internal; i<dc->width_internal*dc->height; i++) {
|
|
x = i%640;
|
|
xx = x;
|
|
y = i/640;
|
|
yy = y;
|
|
xx += ts;
|
|
xx = xx%640;
|
|
|
|
// x += noiseMap[xx+yy*640+(tts*640*480)];
|
|
// x += noiseMap[xx+yy*640];
|
|
if (x >= 640)
|
|
x = 639;
|
|
else if (x < 0)
|
|
x = 0;
|
|
// y += noiseMap[i+(tts*640*480)];
|
|
// y += noiseMap[i];
|
|
if (y >= 480)
|
|
y = 479;
|
|
else if (y < 0)
|
|
y = 0;
|
|
dc->body[i] = backbuffer[x+y*640];
|
|
}
|
|
|
|
//ts %= 32;
|
|
//ts = (Sin(tS)+1)*15.5;
|
|
//ts = Abs(Sin(tS))*32;
|
|
*/
|
|
|
|
/*
|
|
for (y=8; y<480; y++) {
|
|
for (x=0; x<640; x++) {
|
|
OpenSimplex2S(tS);
|
|
dc->body[x+y*640] = noise2(ToF64(x)/32, ToF64(y)/32)*16;
|
|
}
|
|
}
|
|
*/
|
|
|
|
/*
|
|
for (i=8*dc->width_internal; i<dc->width_internal*dc->height; i++) {
|
|
dc->body[i] -= ii;
|
|
}
|
|
*/
|
|
// Free(backbuffer);
|
|
|
|
// Draw Status
|
|
ToolbarDraw(dc, &gUI, gW.player.health, gW.player.selItemSlot);
|
|
|
|
// Draw Tile Highlight
|
|
if (!gUI.mouseConsumed) {
|
|
CD2I32 mSel, tSel, tmpCam;
|
|
tmpCam.x = gW.cam.x;
|
|
tmpCam.y = gW.cam.y;
|
|
mSel.x = (ms.pos.x+tmpCam.x-320)/16;
|
|
mSel.y = (ms.pos.y-8+tmpCam.y-240)/16;
|
|
tSel.x = mSel.x*16-tmpCam.x+320;
|
|
tSel.y = mSel.y*16-tmpCam.y+240;
|
|
RecBorderClip(dc, tSel.x, tSel.y, 16, 16, SWEET_BLUE_LT);
|
|
}
|
|
|
|
// Draw UI Windows
|
|
if (gUI.flags&UI_INV_ENABLED)
|
|
InventoryDraw(dc, &gUI, &gW.player.inv);
|
|
else if (gUI.flags&UI_TRADE_ENABLED)
|
|
TradeDraw(dc, &gUI, &gW.player.inv);
|
|
else if (gUI.flags&UI_ESCMENU_ENABLED)
|
|
DrawEscMenu(dc->body, &gUI.escMenu);
|
|
else if (gUI.flags&UI_INSTRUCTIONS_ENABLED)
|
|
DrawInstructions(dc->body, &txtInstructions);
|
|
|
|
// Draw Level Number
|
|
if (gW.currentLevel >= 0)
|
|
DrawText(dc->body, &fontSmall, gW.levelStr, 4, 4);
|
|
|
|
#ifdef DEBUG
|
|
// Draw Debug
|
|
dc->color = SWEET_BLACK;
|
|
GrPrint(dc, 8, 8, "Cam: %f %f
|
|
cVel: %f %f
|
|
Player: %.1f %.1f
|
|
Heat: %.1f
|
|
State: %d
|
|
Debris: %d
|
|
Mouse: %d %d
|
|
tSel: %d %d
|
|
Items: %d
|
|
Lasers: %d
|
|
Coolers: %d
|
|
DebugF64: %f %f
|
|
DebugI64: %d %d
|
|
cTest1: %d
|
|
cTest2: %d",
|
|
gW.cam.x, gW.cam.y,
|
|
gCtrl.cVel.x, gCtrl.cVel.y,
|
|
gW.player.pos.x, gW.player.pos.y,
|
|
gW.player.heat,
|
|
gW.player.state,
|
|
gW.debris.len,
|
|
ms.pos.x, ms.pos.y,
|
|
tSel.x, tSel.y,
|
|
gW.items.len,
|
|
gW.lasers.len,
|
|
gW.coolers.len,
|
|
gDebugF640, gDebugF641, gDebugI640, gDebugI641,
|
|
gCtrl.cTest1, gCtrl.cTest2);
|
|
#endif
|
|
|
|
// Draw Cursor
|
|
if (gUI.inv.mouseItem.id >= 0)
|
|
PxBlot(dc->body, gItems[gUI.inv.mouseItem.id].px, gUI.mouse.x, gUI.mouse.y);
|
|
else
|
|
PxBlot(dc->body, gUI.cursor, gUI.mouse.x, gUI.mouse.y);
|
|
}
|
|
U0 Init() {
|
|
#ifdef DEBUG
|
|
InitComm();
|
|
#endif
|
|
gr.fp_draw_ms = NULL; // disable TempleOS cursor
|
|
InitSnd;
|
|
gW.quitGame = FALSE;
|
|
gW.level.px = NULL;
|
|
gW.level.flags = NULL;
|
|
gW.level.tileType = NULL;
|
|
gW.level.hp = NULL;
|
|
VectorInit(&gW.mobs, sizeof(Mob));
|
|
VectorInit(&gW.cMobs, sizeof(Vec4));
|
|
VectorInit(&gW.items, sizeof(ItemDrop));
|
|
VectorInit(&gW.debris, sizeof(Debris));
|
|
VectorInit(&gW.debrisEarth, sizeof(Debris));
|
|
VectorInit(&gW.coolers, sizeof(Cooler));
|
|
VectorInit(&gW.lasers, sizeof(Laser));
|
|
VectorInit(&gW.laserPixels, sizeof(CD2I32));
|
|
VectorInit(&gW.grenades, sizeof(Grenade));
|
|
VectorInit(&gW.explosions, sizeof(Explosion));
|
|
VectorInit(&gW.gibs, sizeof(Gib));
|
|
VectorInit(&gW.spawners, sizeof(Spawner));
|
|
|
|
InitEscMenu(&gUI.escMenu);
|
|
InitTitleButtons();
|
|
|
|
MemSet(&gCtrl, 0, sizeof(Controls));
|
|
|
|
Seed(tS+ToF64(mem_physical_space)/0.3333);
|
|
OpenSimplex2SInit();
|
|
OpenSimplex2S(Rand);
|
|
|
|
GenNoiseMapSigned(noiseMap, 640, 200, 10, 8);
|
|
GenNoiseMap(noiseMapLevel, 640, 640, 30, 20);
|
|
|
|
SetAnim(&carAnim, &CarAnim, NULL);
|
|
}
|
|
|
|
U0 InitGame() {
|
|
gCtrl.cVel.x = 0;
|
|
gCtrl.cVel.y = 0;
|
|
gCtrl.cNum = 0;
|
|
gCtrl.cJump = FALSE;
|
|
gCtrl.cEsc = FALSE;
|
|
|
|
// Setup Level
|
|
gW.coins = 0;
|
|
NewPlayer(&gW.player, 320, 240);
|
|
gW.currentLevel = 0;
|
|
ChangeLevel(gW.currentLevel);
|
|
|
|
// Setup UI
|
|
UIInit(&gUI, &gW.player);
|
|
gUI.flags = UI_INSTRUCTIONS_ENABLED;
|
|
|
|
gCtrl.cTest3 = 0;
|
|
|
|
// Init Engine
|
|
gW.ActiveUpdate = &GameUpdate;
|
|
gW.ActiveInput = &GameInput;
|
|
Fs->draw_it = &DrawGame;
|
|
}
|
|
|
|
U0 InitSandbox() {
|
|
// Setup Camera
|
|
gCtrl.cVel.x = 0;
|
|
gCtrl.cVel.y = 0;
|
|
gCtrl.cNum = 0;
|
|
gCtrl.cJump = FALSE;
|
|
gCtrl.cEsc = FALSE;
|
|
|
|
// Setup Level
|
|
gW.currentLevel = -1;
|
|
gW.activeLvl = &Sandbox;
|
|
InitLevel(&gW, gW.activeLvl, noiseMapLevel);
|
|
|
|
// Setup Player
|
|
NewPlayer(&gW.player, gW.level.spawn.x, gW.level.spawn.y);
|
|
gW.player.dJumpAvail = FALSE;
|
|
gW.player.dJumpSpent = FALSE;
|
|
gW.coins = 0;
|
|
gW.grapple.active = FALSE;
|
|
gW.grapple.hooked = FALSE;
|
|
UpdatePxUse(&gW.player);
|
|
|
|
gW.cam.x = gW.player.pos.x+gW.player.size.x>>1;
|
|
gW.cam.y = gW.player.pos.y+gW.player.size.y>>1;
|
|
|
|
// Setup UI
|
|
UIInit(&gUI, &gW.player);
|
|
gUI.flags = UI_INSTRUCTIONS_ENABLED;
|
|
|
|
gCtrl.cTest3 = 0;
|
|
|
|
// Init Engine
|
|
gW.ActiveUpdate = &GameUpdate;
|
|
gW.ActiveInput = &GameInput;
|
|
Fs->draw_it = &DrawGame;
|
|
}
|
|
|
|
#ifndef DEBUG
|
|
DocClear;
|
|
#endif
|
|
SettingsPush;
|
|
MenuPush(
|
|
"File {"
|
|
" Abort(,CH_SHIFT_ESC);"
|
|
" Exit(,CH_ESC);"
|
|
"}"
|
|
"Play {"
|
|
" Up(,'w');"
|
|
" Down(,'s');"
|
|
" Left(,'a');"
|
|
" Right(,'d');"
|
|
" Weapon1(,'1');"
|
|
" Weapon2(,'2');"
|
|
" KillSnd(,'m');"
|
|
"}"
|
|
);
|
|
AutoComplete;
|
|
WinBorder;
|
|
WinMax;
|
|
DocCursor;
|
|
Fs->text_attr=SWEET_BLUE<<4+WHITE;
|
|
GrPaletteSet(gr_palette_sweetie16);
|
|
Fs->win_inhibit=WIG_TASK_DFT-WIF_SELF_FOCUS-WIF_SELF_BORDER-WIF_FOCUS_TASK_MENU;
|
|
|
|
F64 t_last, t_now, t_delta, t_sleep;
|
|
Init();
|
|
InitTitle();
|
|
t_last = tS;
|
|
#ifdef DEBUG
|
|
Prof;
|
|
#endif
|
|
CJob *sndJob = *Spawn(&SndTask,NULL,"Sound",mp_cnt-1,Fs);
|
|
while (!gW.quitGame) {
|
|
t_now = tS;
|
|
t_delta = t_now - t_last;
|
|
t_last = t_now;
|
|
(gW.ActiveInput)();
|
|
(gW.ActiveUpdate)(t_delta);
|
|
Refresh(1, FALSE);
|
|
}
|
|
SetSnd(SND_QUIT);
|
|
#ifdef DEBUG
|
|
ProfRep;
|
|
#endif
|
|
Snd;
|
|
MenuPop;
|
|
SettingsPop;
|
|
gr.fp_draw_ms=&DrawStdMs;
|
|
DCFill;
|
|
#ifndef DEBUG
|
|
Exit;
|
|
#endif
|