// Copyright (c) 2014 Alex Diener. All rights reserved. #include "watertowerclassic/AudioManager.h" #include "watertowerclassic/PhysicsFunctions.h" #include "watertowerclassic/PlayerModel.h" #include #include #define SUPERCLASS StemObject PlayerModel * PlayerModel_create(LevelModel * levelModel) { stemobject_create_implementation(PlayerModel, init, levelModel) } bool PlayerModel_init(PlayerModel * self, LevelModel * levelModel) { call_super(init, self); self->dispose = PlayerModel_dispose; self->update = PlayerModel_update; self->startMovingLeft = PlayerModel_startMovingLeft; self->startMovingRight = PlayerModel_startMovingRight; self->startMovingDown = PlayerModel_startMovingDown; self->startMovingUp = PlayerModel_startMovingUp; self->stopMovingLeft = PlayerModel_stopMovingLeft; self->stopMovingRight = PlayerModel_stopMovingRight; self->stopMovingDown = PlayerModel_stopMovingDown; self->stopMovingUp = PlayerModel_stopMovingUp; self->jump = PlayerModel_jump; self->action = PlayerModel_action; self->setAnimationState = PlayerModel_setAnimationState; self->getSpriteName = PlayerModel_getSpriteName; self->tileLocation = levelModel->playerStartPosition; self->pixelLocation.x = self->tileLocation.x * LEVEL_BLOCK_SIZE + LEVEL_BLOCK_SIZE / 2; self->pixelLocation.y = self->tileLocation.y * LEVEL_BLOCK_SIZE + LEVEL_BLOCK_SIZE / 2; self->hVel = 0.0f; self->vVel = 0.0f; self->standingOn = NULL; self->underwater = false; self->ladderIntention = 0; self->jumpIntention = 0; self->onLadder = false; self->airLeft = PLAYER_BREATH_DURATION; self->numberOfKeys = 0; self->numberOfPoints = 0; self->totalPoints = 0; self->numberOfLives = PLAYER_INITIAL_LIVES; self->animationState = animStateStandFront; self->animationCounter = 0; self->opacity = 0; self->fadingIn = true; self->levelModel = levelModel; return true; } void PlayerModel_dispose(PlayerModel * self) { call_super(dispose, self); } #define ANIMATION_FRAME_INTERVAL 5 void PlayerModel_update(PlayerModel * self) { if (self->jumpIntention > 0) { if (self->onLadder) { self->jumpIntention = 0; AudioManager_play("land"); self->onLadder = 0; self->vVel = PLAYER_JUMP_VELOCITY; self->standingOn = NULL; self->setAnimationState(self, abstAnimJump); } else if (self->standingOn != NULL) { self->jumpIntention = 0; if (self->standingOn->type != BLOCK_TYPE_SAND) { AudioManager_play("land"); if (self->standingOn->type == BLOCK_TYPE_STICKY) { self->vVel = PLAYER_JUMP_VELOCITY * 0.75; } else { self->vVel = PLAYER_JUMP_VELOCITY; } leaveBlock(self->standingOn); self->standingOn = NULL; self->setAnimationState(self, abstAnimJump); } } self->jumpIntention--; } if (self->animationCounter >= (self->underwater ? (ANIMATION_FRAME_INTERVAL * 2) : ANIMATION_FRAME_INTERVAL)) { switch (self->animationState) { case animStateRunLeft1: self->animationState = animStateRunLeft2; break; case animStateRunLeft2: self->animationState = animStateRunLeft3; break; case animStateRunLeft3: self->animationState = animStateRunLeft4; break; case animStateRunLeft4: self->animationState = animStateRunLeft1; break; case animStateRunRight1: self->animationState = animStateRunRight2; break; case animStateRunRight2: self->animationState = animStateRunRight3; break; case animStateRunRight3: self->animationState = animStateRunRight4; break; case animStateRunRight4: self->animationState = animStateRunRight1; break; case animStateClimb1: if (self->vVel != 0.0) self->animationState = animStateClimb2; break; case animStateClimb2: if (self->vVel != 0.0) self->animationState = animStateClimb3; break; case animStateClimb3: if (self->vVel != 0.0) self->animationState = animStateClimb4; break; case animStateClimb4: if (self->vVel != 0.0) self->animationState = animStateClimb1; break; } self->animationCounter = 0; } } void PlayerModel_startMovingLeft(PlayerModel * self) { if (self->onLadder) { self->onLadder = false; } self->hVel = -PLAYER_MAX_WALK_SPEED; } void PlayerModel_startMovingRight(PlayerModel * self) { if (self->onLadder) { self->onLadder = false; } self->hVel = PLAYER_MAX_WALK_SPEED; } void PlayerModel_startMovingDown(PlayerModel * self) { if (self->onLadder) { self->vVel = PLAYER_MAX_WALK_SPEED; } else { if (self->hVel == 0.0f && self->vVel == 0.0f) { self->setAnimationState(self, abstAnimStandFront); } self->ladderIntention = 1; } } void PlayerModel_startMovingUp(PlayerModel * self) { if (self->onLadder) { self->vVel = -PLAYER_MAX_WALK_SPEED; } else { if (self->hVel == 0.0f && self->vVel == 0.0f) { self->setAnimationState(self, abstAnimStandBack); } self->ladderIntention = -1; } } void PlayerModel_stopMovingLeft(PlayerModel * self) { if (self->hVel < 0.0f) { self->hVel = 0.0f; } } void PlayerModel_stopMovingRight(PlayerModel * self) { if (self->hVel > 0.0f) { self->hVel = 0.0f; } } void PlayerModel_stopMovingDown(PlayerModel * self) { self->ladderIntention = 0; if (self->onLadder) { self->vVel = 0; } } void PlayerModel_stopMovingUp(PlayerModel * self) { self->ladderIntention = 0; if (self->onLadder) { self->vVel = 0; } } void PlayerModel_jump(PlayerModel * self) { self->jumpIntention = 5; } static void teleport(PlayerModel * self, unsigned int startX, unsigned int startY, unsigned int id) { unsigned int blockCount, blockIndex; blockIndex = startY * LEVEL_BLOCK_COUNT_X + startX; for (blockCount = 1; blockCount < LEVEL_BLOCK_COUNT_X * LEVEL_BLOCK_COUNT_Y; blockCount++) { blockIndex++; blockIndex %= LEVEL_BLOCK_COUNT_X * LEVEL_BLOCK_COUNT_Y; if (self->levelModel->blocks[blockIndex].type == BLOCK_TYPE_TELEPORT && self->levelModel->blocks[blockIndex].properties.teleport.id == id) { self->tileLocation.x = blockIndex % LEVEL_BLOCK_COUNT_X; self->tileLocation.y = blockIndex / LEVEL_BLOCK_COUNT_X; self->pixelLocation.x = self->tileLocation.x * LEVEL_BLOCK_SIZE + LEVEL_BLOCK_SIZE / 2; self->pixelLocation.y = self->tileLocation.y * LEVEL_BLOCK_SIZE + LEVEL_BLOCK_SIZE / 2; } } } void PlayerModel_action(PlayerModel * self) { if (self->levelModel->blocks[((LEVEL_BLOCK_COUNT_X * self->tileLocation.y) + self->tileLocation.x)].type == BLOCK_TYPE_LEVER) { LevelModel_switchBlocks(self->levelModel, self->levelModel->blocks[((LEVEL_BLOCK_COUNT_X * self->tileLocation.y) + self->tileLocation.x)].properties.lever.id); AudioManager_play("switch"); } else if (self->levelModel->blocks[((LEVEL_BLOCK_COUNT_X * self->tileLocation.y) + self->tileLocation.x)].type == BLOCK_TYPE_TELEPORT) { teleport(self, self->tileLocation.x, self->tileLocation.y, self->levelModel->blocks[((LEVEL_BLOCK_COUNT_X * self->tileLocation.y) + self->tileLocation.x)].properties.teleport.id); AudioManager_play("teleport"); } } void PlayerModel_setAnimationState(PlayerModel * self, enum PlayerAbstractAnimationState abstractState) { switch (abstractState) { case abstAnimStand: switch (self->animationState) { case animStateRunLeft1: case animStateRunLeft2: case animStateRunLeft3: case animStateRunLeft4: case animStateJumpLeft: self->animationState = animStateStandLeft; self->animationCounter = 0; break; case animStateRunRight1: case animStateRunRight2: case animStateRunRight3: case animStateRunRight4: case animStateJumpRight: self->animationState = animStateStandRight; self->animationCounter = 0; break; case animStateClimb1: case animStateClimb2: case animStateClimb3: case animStateClimb4: case animStateJumpBack: self->animationState = animStateStandBack; self->animationCounter = 0; break; case animStateJumpFront: self->animationState = animStateStandFront; self->animationCounter = 0; break; } break; case abstAnimJump: switch (self->animationState) { case animStateRunLeft1: case animStateRunLeft2: case animStateRunLeft3: case animStateRunLeft4: case animStateStandLeft: self->animationState = animStateJumpLeft; self->animationCounter = 0; break; case animStateRunRight1: case animStateRunRight2: case animStateRunRight3: case animStateRunRight4: case animStateStandRight: self->animationState = animStateJumpRight; self->animationCounter = 0; break; case animStateClimb1: case animStateClimb2: case animStateClimb3: case animStateClimb4: case animStateStandBack: self->animationState = animStateJumpBack; self->animationCounter = 0; break; case animStateStandFront: self->animationState = animStateJumpFront; self->animationCounter = 0; break; } break; case abstAnimRunLeft: switch (self->animationState) { case animStateRunLeft1: case animStateRunLeft2: case animStateRunLeft3: case animStateRunLeft4: break; default: self->animationState = animStateRunLeft1; self->animationCounter = 0; break; } break; case abstAnimRunRight: switch (self->animationState) { case animStateRunRight1: case animStateRunRight2: case animStateRunRight3: case animStateRunRight4: break; default: self->animationState = animStateRunRight1; self->animationCounter = 0; break; } break; case abstAnimClimb: switch (self->animationState) { case animStateClimb1: case animStateClimb2: case animStateClimb3: case animStateClimb4: break; default: self->animationState = animStateClimb1; self->animationCounter = 0; break; } break; case abstAnimStandFront: self->animationState = animStateStandFront; self->animationCounter = 0; break; case abstAnimStandBack: self->animationState = animStateStandBack; self->animationCounter = 0; break; } } const char * PlayerModel_getSpriteName(PlayerModel * self) { switch (self->animationState) { case animStateStandFront: return "player_front"; case animStateStandBack: return "player_back"; case animStateStandLeft: return "player_left"; case animStateStandRight: return "player_right"; case animStateClimb1: return "player_climb_1"; case animStateClimb2: return "player_climb_2"; case animStateClimb3: return "player_climb_3"; case animStateClimb4: return "player_climb_2"; case animStateRunLeft1: return "player_walk_left_1"; case animStateRunLeft2: return "player_walk_left_2"; case animStateRunLeft3: return "player_walk_left_3"; case animStateRunLeft4: return "player_walk_left_2"; case animStateRunRight1: return "player_walk_right_1"; case animStateRunRight2: return "player_walk_right_2"; case animStateRunRight3: return "player_walk_right_3"; case animStateRunRight4: return "player_walk_right_2"; case animStateJumpLeft: return "player_jump_left"; case animStateJumpRight: return "player_jump_right"; case animStateJumpFront: return "player_jump_front"; case animStateJumpBack: return "player_jump_back"; } return "player_front"; }