void Hero::DamagedMobilityState::enter() { hero.isStunned = true; hero.invincibilityTimer = 1.4667f; hero.stopShooting(); hero.chooseAnimation(); // If we're facing left, move right, if right, move left. if(hero.getDirection() == Directions::Left) { horizontalVelocity.setX(NESNumber(0x00, 0x80).toFloat()); } else { horizontalVelocity.setX(-(NESNumber(0x00, 0x80).toFloat())); } // Special case for sliding and climbing: // * If damaged mid-slide there is no knockback // * If damaged while climbing there is no knockback if(hero.isSliding || hero.isClimbing) { horizontalVelocity.setX(0.0f); } // Ensure we get knocked back hero.body.setGravitated(true); hero.body.setApplyHorizontalVelocity(true); // Make sure we start falling immediately hero.setVelocityY(0.0f); // Make sure animations will play (like when you're on a ladder) hero.getAnimatedSprite()->unpause(); if(auto events = hero.getEventBus().lock()) { events->triggerEvent(EventDataPtr(new EntityDamageEventData(hero.getId(), 0.0f))); } }
NESNumber NESNumber::fromFloat(const float& f) { int high = static_cast<int>(f); float frac = std::abs(f - high); unsigned char low = static_cast<unsigned char>(frac * 256.0f); return NESNumber(high, low); }
NESNumber NESNumber::fromInt(const int& i) { return NESNumber(i, 0); }
NESNumber NESNumber::operator-() const { return NESNumber(-getHigh(), getLow()); }
Hero::Hero(int id, std::shared_ptr<Room> room) : Entity(id, room) , isDecelerating(false) , isStanding(false) , isWalking(false) , isSliding(false) , isInTunnel(false) , isJumping(false) , isFalling(false) , isAirborn(false) , isClimbing(false) , isTouchingLadderTop(false) , isFullyAccelerated(false) , isShooting(false) , isTeleporting(false) , isMorphing(false) , isStunned(false) , isInvincible(false) , isUnderWater(false) , wasUnderWaterLastFrame(false) , climbableRegion(0, 0, 0, 0) , actionController(nullptr) , mobilityState(nullptr) , nextMobilityState(nullptr) , temporaryMobilityState(nullptr) , shootingState(nullptr) , nextShootingState(nullptr) { setDeathType(EntityDeathType::Hero); body.setGravitated(true); body.setHasWorldCollision(true); body.setCollisionCallback(std::bind(&Entity::handleCollision, this, std::placeholders::_1, std::placeholders::_2)); body.setLandingCallback([this](Movable& movable, CollisionInfo& collisionInfo) { if(actionController->shouldMoveRight() || actionController->shouldMoveLeft()) { this->isFullyAccelerated = true; } this->isJumping = false; this->isFalling = false; this->isAirborn = false; if(auto events = this->getEventBus().lock()) { events->triggerEvent(EventDataPtr(new EntityStateChangeEventData(getId(), "landed"))); } #ifdef HIKARI_DEBUG_HERO_PHYSICS this->countAscendingFrames = 0; this->countDecendingFrames = 0; #endif // HIKARI_DEBUG_HERO_PHYSICS }); invincibilityTimer = 0; blinkTimer = 0; isBlinking = false; isVisible = true; walkVelocity = Vector2<float>(NESNumber(0x01, 0x4C).toFloat(), 0.0f); climbVelocity = Vector2<float>(walkVelocity.getY(), walkVelocity.getX()); // Climbs at same speed as he walks jumpVelocity = Vector2<float>(0.0f, -(NESNumber(0x04, 0xA5) + NESNumber(0, 0x40) + NESNumber(0, 0x40)).toFloat()); suddenFallVelocity = Vector2<float>(0.0f, NESNumber(0, 0x80).toFloat()); slideVelocity = Vector2<float>(NESNumber(0x02, 0x80).toFloat(), 0.0f); hurtVelocity = Vector2<float>(); accelerationDelay = 0; accelerationDelayThreshold = 6; #ifdef HIKARI_DEBUG_HERO_PHYSICS this->countAscendingFrames = 0; this->countDecendingFrames = 0; #endif // HIKARI_DEBUG_HERO_PHYSICS isFullyAccelerated = false; setFaction(Factions::Hero); changeMobilityState(std::unique_ptr<MobilityState>(new IdleMobilityState(*this))); changeShootingState(std::unique_ptr<ShootingState>(new NotShootingState(*this))); getAnimatedSprite()->setUsePalette(true); getAnimatedSprite()->setUseSharedPalette(true); }