128 lines
3.9 KiB
C
128 lines
3.9 KiB
C
#define HUMAN_OFF 16
|
|
|
|
|
|
void spawnHuman(u8 zone){
|
|
s16 i = -1;
|
|
for(s16 j = 0; j < HUMAN_COUNT; j++) if(!humans[j].active) { i = j; break; }
|
|
if(i == -1) return;
|
|
|
|
humans[i].active = TRUE;
|
|
humans[i].state = HUMAN_WALKING;
|
|
humans[i].carriedBy = -1;
|
|
|
|
fix32 zoneStart = FIX32(zone * 512);
|
|
humans[i].pos.x = zoneStart + FIX32(random() % 512);
|
|
humans[i].pos.y = GAME_H_F - FIX32(24);
|
|
|
|
fix32 speeds[] = { FIX32(0.3), FIX32(0.4), FIX32(0.5) };
|
|
humans[i].vel.x = (random() % 2 == 0) ? speeds[random() % 3] : -speeds[random() % 3];
|
|
humans[i].vel.y = (random() % 2 == 0) ? FIX32(0.1) : FIX32(-0.1);
|
|
|
|
humans[i].image = SPR_addSprite(&koaSprite,
|
|
getScreenX(humans[i].pos.x, player.camera) - HUMAN_OFF, fix32ToInt(humans[i].pos.y) - HUMAN_OFF,
|
|
TILE_ATTR(PAL0, 0, 0, 0));
|
|
if(!humans[i].image){
|
|
humans[i].active = FALSE;
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void updateHuman(u8 i){
|
|
switch(humans[i].state){
|
|
case HUMAN_WALKING:
|
|
// Y bounce: bob 4px around ground level
|
|
if(humans[i].pos.y >= GAME_H_F - FIX32(20) || humans[i].pos.y <= GAME_H_F - FIX32(28))
|
|
humans[i].vel.y *= -1;
|
|
|
|
// X wrap
|
|
if(humans[i].pos.x >= GAME_WRAP)
|
|
humans[i].pos.x -= GAME_WRAP;
|
|
if(humans[i].pos.x < 0)
|
|
humans[i].pos.x += GAME_WRAP;
|
|
|
|
humans[i].pos.x += humans[i].vel.x;
|
|
humans[i].pos.y += humans[i].vel.y;
|
|
break;
|
|
|
|
case HUMAN_CARRIED:
|
|
// follow carrier enemy position
|
|
if(humans[i].carriedBy >= 0 && enemies[humans[i].carriedBy].active){
|
|
humans[i].pos.x = enemies[humans[i].carriedBy].pos.x;
|
|
humans[i].pos.y = enemies[humans[i].carriedBy].pos.y + FIX32(16);
|
|
} else {
|
|
// carrier died (shouldn't normally reach here, killEnemy handles it)
|
|
humans[i].state = HUMAN_FALLING;
|
|
humans[i].carriedBy = -1;
|
|
humans[i].vel.x = 0;
|
|
humans[i].vel.y = FIX32(3);
|
|
humanBeingCarried = FALSE;
|
|
}
|
|
break;
|
|
|
|
case HUMAN_FALLING:
|
|
humans[i].pos.y += humans[i].vel.y;
|
|
// land on ground
|
|
if(humans[i].pos.y >= GAME_H_F - FIX32(24)){
|
|
humans[i].pos.y = GAME_H_F - FIX32(24);
|
|
humans[i].state = HUMAN_WALKING;
|
|
fix32 speeds[] = { FIX32(0.3), FIX32(0.4), FIX32(0.5) };
|
|
humans[i].vel.x = (random() % 2 == 0) ? speeds[random() % 3] : -speeds[random() % 3];
|
|
humans[i].vel.y = (random() % 2 == 0) ? FIX32(0.1) : FIX32(-0.1);
|
|
}
|
|
break;
|
|
|
|
case HUMAN_COLLECTED: {
|
|
fix32 targetX, targetY;
|
|
if(humans[i].trailIndex == 0){
|
|
targetX = player.pos.x;
|
|
targetY = player.pos.y + FIX32(24);
|
|
} else {
|
|
// find the human ahead in the chain
|
|
targetX = player.pos.x;
|
|
targetY = player.pos.y + FIX32(24);
|
|
for(s16 j = 0; j < HUMAN_COUNT; j++){
|
|
if(humans[j].active && humans[j].state == HUMAN_COLLECTED
|
|
&& humans[j].trailIndex == humans[i].trailIndex - 1){
|
|
targetX = humans[j].pos.x;
|
|
targetY = humans[j].pos.y + FIX32(8);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
fix32 deltaX = getWrappedDelta(targetX, humans[i].pos.x);
|
|
humans[i].pos.x += deltaX >> 2;
|
|
humans[i].pos.y += (targetY - humans[i].pos.y) >> 2;
|
|
// X wrap
|
|
if(humans[i].pos.x >= GAME_WRAP)
|
|
humans[i].pos.x -= GAME_WRAP;
|
|
if(humans[i].pos.x < 0)
|
|
humans[i].pos.x += GAME_WRAP;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// collect: check overlap with player (walking or falling only)
|
|
fix32 dx = getWrappedDelta(humans[i].pos.x, player.pos.x);
|
|
if(humans[i].state != HUMAN_CARRIED && humans[i].state != HUMAN_COLLECTED){
|
|
fix32 dy = humans[i].pos.y - player.pos.y;
|
|
if(dx >= FIX32(-24) && dx <= FIX32(24) && dy >= FIX32(-24) && dy <= FIX32(24)){
|
|
score += (humans[i].state == HUMAN_FALLING) ? 2000 : 1000;
|
|
sfxPickup();
|
|
humans[i].state = HUMAN_COLLECTED;
|
|
humans[i].trailIndex = collectedCount++;
|
|
return;
|
|
}
|
|
}
|
|
|
|
s16 sx = getScreenX(humans[i].pos.x, player.camera);
|
|
s16 sy = fix32ToInt(humans[i].pos.y);
|
|
bool visible = (dx >= -CULL_LIMIT && dx <= CULL_LIMIT);
|
|
SPR_setVisibility(humans[i].image, visible ? VISIBLE : HIDDEN);
|
|
SPR_setPosition(humans[i].image, sx - HUMAN_OFF, sy - HUMAN_OFF);
|
|
}
|
|
|
|
void updateHumans(){
|
|
for(s16 i = 0; i < HUMAN_COUNT; i++)
|
|
if(humans[i].active)
|
|
updateHuman(i);
|
|
}
|