Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "brutal.h"
- #include <centauri/damages/damage_zone_base.h>
- #include <centauri/damages/damage_digits.h>
- #include <centauri/assets_api/monster.h>
- #include <centauri/bullet/base.h>
- #include <centauri/bullet/attribute.h>
- #include <centauri/bullet/motion/directional.h>
- #include <centauri/monsters/sfx.h>
- #include <centauri/sfx/global.h>
- #include <centauri/random.h>
- #include <centauri/tools.h>
- #include <centauri/input/keybinding.h>
- #include <centauri/world/context.h>
- #include <centauri/deco/decoration.h>
- #include <centauri/game/interact.h>
- #include <onidev.h>
- #include <onidev/make_unique.h>
- #include <cmath>
- #include <cstdio>
- #include <cassert>
- #include <iostream>
- #include <fstream>
- #include <centauri/monsters/brain/land_ai.h>
- // /spawn pc_monster_alien_brutal
- namespace
- {
- struct BrainAI:
- public GenericLandAIBrain<AlienBrutal>
- {
- float cooldown_laser = 0;
- float cooldown_shoot = 0;
- int shoot_counter = 0;
- BrainAI(const AlienBrutal& ins):
- GenericLandAIBrain<AlienBrutal>(ins.sizeInBlocks()) {}
- void update(const AlienBrutal& ins, Input& inputs, float dt) override {
- cooldown_laser -= dt;
- cooldown_shoot -= dt;
- updateAI(ins, inputs, dt);
- }
- bool tryToAttack(const AlienBrutal& ins, const Focus& focus, Input& inputs) override
- {
- bool ret = false;
- od::Rect box1 = ins.boundingBox();
- od::Rect box2 = focus.box;
- bool facing = false;
- if(ins.facingx() > 0.f)
- facing = box1.x2 <= box2.x1;
- else
- facing = box1.x1 >= box2.x2;
- float dist = focus.distanceTo(ins);
- float hsep = std::abs(box1.center().x - box2.center().x);
- float scale = ins.size() + 1;
- if(dist < 64 * scale
- && (hsep < 64 || facing))
- {
- inputs.simulateCheck(Input::Action1); // punch
- return true;
- }
- else if(cooldown_shoot <= 0)
- {
- if(ins.state() != ins.Shoot
- && ins.state() != ins.ShootFast
- && ins.state() != ins.ShootUp)
- {
- if(tryShoot(ins, inputs, focus)) {
- shoot_counter++;
- ret = true;
- }
- float coef = ins.lifeCoeff();
- bool low_life = coef < 0.5f;
- if(low_life)
- {
- if(shoot_counter >= 5)
- {
- cooldown_shoot = 3*60;
- }
- }
- else
- {
- if(shoot_counter >= 3)
- {
- cooldown_shoot = 10*60;
- }
- }
- }
- }
- else
- {
- shoot_counter = 0;
- }
- return ret;
- }
- bool tryShoot(const AlienBrutal& ins, Input& inputs, const Focus& focus)
- {
- if(!focus) {
- return false;
- }
- float dist_sep = focus.distanceTo(ins);
- const od::Rect& box1 = ins.boundingBox();
- od::Rect box2 = focus.box;
- float vsep = std::abs(box1.center().y - box2.center().y);
- // shoot fast offset
- /// @todo use also beam offset
- Vec2 w = ins.boundingBox().center();
- w += Vec2(0, -14);
- // shoot only if the player is accessible
- // - on the good range (angle, distance)
- // - not behind a wall
- // big horizontal laser shoot
- if(cooldown_laser <= 0.f
- && shoot_counter >= 2
- && vsep < 48)
- {
- bool raycast = false;
- float dist = std::max(0.f, dist_sep - 16);
- raycastTest(ins.getWorld(), w, w + od::Vec2(dist * ins.facingx(), 0.f), 2, raycast, false);
- if(raycast)
- raycastTest(ins.getWorld(), w, box2.center(), 2, raycast, false);
- if(!raycast)
- {
- inputs.simulateCheck(Input::MouseLeft);
- inputs.simulateCheck(Input::Down);
- cooldown_laser = Rand()(160, 200);
- return true;
- }
- }
- float angle;
- bool on_range;
- std::tie(angle, on_range) = ins.getShootAngle(w, box2.center());
- // fast small bullet shoot
- if(on_range)
- {
- bool raycast = false;
- raycastTest(ins.getWorld(), w, box2.center(), 2, raycast, false);
- if(!raycast)
- {
- inputs.simulateCheck(Input::MouseLeft);
- return true;
- }
- }
- return false;
- }
- };
- }
- // /spawn pc_monster_alien_brutal 40
- od::Rect AlienBrutal::rect[3] =
- {
- od::Rect(0, 0, 44, 60),
- od::Rect(0, 0, 44*2, 60*2),
- od::Rect(0, 0, 44*3, 60*3)
- };
- AlienBrutal::AlienBrutal(WorldContext& context, const MonsterAttributes& attribs,
- const od::Vec2& pos, const MonsterSpawnParam& param):
- Object(context, pos),
- DynamicObject(context, pos),
- TextureLifeManagerCRTP<AlienBrutal>("assets/Monsters/alien_brutal.xml"),
- SetIndexVirtual<Object, AlienBrutal, 120>(context, pos),
- LandMonster(context, attribs, pos, param)
- {
- _state = Idle;
- _scalex = param.reversed?-1:1;
- if(const Suffix* s = findSuffix(SuffixType::Giant))
- {
- _size = int(s->value() - 1);
- Assert(_size <= 2);
- }
- if(param.preview) {
- _brain = std::make_unique<MonsterBrainPreview<AlienBrutal>>();
- }
- }
- AlienBrutal::~AlienBrutal()
- {
- }
- void AlienBrutal::evSend(od::StreamData& s)
- {
- s << pos.x << pos.y
- << vel.x << vel.y
- << _inputs1
- << _inputs2;
- _inputs1 = _inputs2 = 0;
- }
- void AlienBrutal::evReceive(od::StreamData& s)
- {
- uint16_t inputs, old_inputs;
- multiplayerSmoothMovement(s);
- s >> inputs >> old_inputs;
- _inputs.set(inputs, old_inputs);
- }
- const od::Shape* AlienBrutal::collisionMask(int p) const
- {
- return &rect[_size];
- }
- void AlienBrutal::instanceDraw() const
- {
- od::metatextureUse("alien_brutal_monster");
- const float scale = _size + 1;
- int wx = rect[_size].width() / 2;
- int wy = rect[_size].height();
- shaderIndexedStartAuto(rarity());
- if(_state == Idle)
- od::drawSpriteScaled("idle", frame, pos.x + wx, pos.y + wy, _scalex * scale, scale);
- else if(_state == Walk)
- od::drawSpriteScaled("move", frame, pos.x + wx, pos.y + wy, _scalex * scale, scale);
- else if(_state == JumpStart || _state == Jumping || _state == JumpEnd)
- od::drawSpriteScaled("jump", frame, pos.x + wx, pos.y + wy, _scalex * scale, scale);
- else if(_state == Punch)
- od::drawSpriteScaled("punch", frame, pos.x + wx, pos.y + wy, _scalex * scale, scale);
- else if(_state == ShootFast)
- od::drawSpriteScaled("shoot", frame, pos.x + wx, pos.y + wy, _scalex * scale, scale);
- else if(_state == Shoot)
- od::drawSpriteScaled("shoot_charge_f", frame, pos.x + wx, pos.y + wy, _scalex * scale, scale);
- else if(_state == ShootUp)
- od::drawSpriteScaled("shoot_charge_u", frame, pos.x + wx, pos.y + wy, _scalex * scale, scale);
- else
- od::drawSpriteScaled("die", frame, pos.x + wx, pos.y + wy, _scalex * scale, scale);
- shaderIndexedEnd();
- //od::drawRectangle(pos.x + rect[size].x1, pos.y + rect[size].y1, pos.x + rect[size].x2, pos.y + rect[size].y2, true);
- }
- void AlienBrutal::setState(State state, bool reset_frame)
- {
- _state = state;
- if(_state == Jumping)
- frame = 6.f;
- else if(reset_frame)
- frame = 0.f;
- if(state == Shoot || state == ShootUp) {
- //playSound(MonstersSfx::ins().alien_brutal_laser, pos);
- _attack_prepare = 5.f;
- od::instanceCreate<DamageDigits>(
- worldContext(), boundingBox().center()
- + Vec2(0.f, -8.f),
- DamageDigits::Attack, 0);
- }
- else if(state == ShootFast)
- playSound(MonstersSfx::ins().alien_brutal_shoot, pos);
- else if(state == Punch)
- playSound(MonstersSfx::ins().alien_brutal_punch, pos);
- bullet_launched = false;
- }
- void AlienBrutal::monsterStep(float dt)
- {
- constexpr float JumpTimerMax = 8.f;
- constexpr float gravity = 0.2f;
- const float BulletShootSpeed = 5.f;
- if(!alive())
- {
- frame += 0.2f * dt;
- if(frame >= 14)
- instanceDestroy();
- else
- updatePhysics(dt, 0.34f, 0, 0, 0.05f, 0.1f, 4, true);
- return;
- }
- if(isPetrified()) {
- updatePhysics(dt, 0.34f, 0, 0, 0.05f, 0.1f, 4, true);
- return;
- }
- // /spawn pc_monster_alien_brutal 30
- if(!_brain)
- {
- //_brain = std::make_unique<MonsterBrainKeyboard<AlienBrutal>>(false, false);
- _brain = std::make_unique<BrainAI>(*this);
- }
- auto checkInputs = [this]() {
- if(_inputs.check(Input::Space))
- {
- setState(JumpStart);
- }
- else if(canAttack() && _inputs.check(Input::MouseLeft))
- {
- if(_inputs.check(Input::Up))
- setState(ShootUp);
- else if(_inputs.check(Input::Down))
- setState(Shoot);
- else
- setState(ShootFast);
- }
- else if(canAttack() && _inputs.check(Input::Action1))
- {
- setState(Punch);
- }
- else if(_inputs.check(Input::Left) ^ _inputs.check(Input::Right))
- {
- _scalex = _inputs.check(Input::Left) ? -1.f : 1.f;
- if(_state != Walk)
- setState(Walk);
- }
- else
- return false;
- return true;
- };
- auto getShootAngle = [this](Vec2 w, AliveObject* target, float range)
- {
- return std::get<0>( this->getShootAngle(w, target, range) );
- };
- // /spawn pc_monster_alien_brutal 10
- _brain->update(*this, _inputs, dt);
- _inputs1 |= _inputs.state();
- _inputs2 |= _inputs.ostate();
- bool on_ground = onGround();
- if(on_ground) {
- _ground_timer = 3.f;
- }
- else if(_ground_timer > 0.f) {
- _ground_timer -= dt;
- if(_ground_timer > 0.f)
- on_ground = true;
- }
- // Server
- float force_x = 0;
- if(_attack_prepare > 0.f) {
- _attack_prepare -= dt;
- if(_attack_prepare <= 0.f
- && (_state == Shoot || _state == ShootUp)) {
- playSound(MonstersSfx::ins().alien_brutal_laser, pos);
- }
- }
- else if(_state == Idle)
- {
- frame += 0.2f * dt;
- if(on_ground)
- {
- checkInputs();
- }
- else
- setState(Jumping);
- }
- else if(_state == Walk)
- {
- frame += 0.2f * dt;
- if(on_ground)
- {
- if(!checkInputs())
- {
- setState(Idle);
- }
- force_x = (2 + _size/2.f) * _scalex;
- }
- else
- setState(Jumping);
- }
- // else if(_state == JumpStart)
- // {
- // frame += 0.2f * dt;
- // _jump_timer = 0.f;
- // if(frame >= 2.f)
- // {
- // if(_inputs.check(Input::Shift) || _inputs.released(Input::Shift))
- // {
- // vel = Vec2(4*_scalex, -5);
- // }
- // else if( (_inputs.check(Input::Action1) || _inputs.check(Input::Action2))
- // && wall(rect[_size], _scalex))
- // {
- // int height = wallHeight(rect[_size], _scalex, 6);
- // vel = Vec2((2 + height/2)*_scalex, -4.5 - height*1.2);
- // }
- // else
- // {
- // vel.y = -6.f;
- // _jump_timer = JumpTimerMax;
- // }
- // _state = Jumping;
- // }
- // }
- else if(_state == JumpStart)
- {
- if(frame == 0.f) {
- _long_jump = _inputs.check(Input::Shift) || _inputs.released(Input::Shift);
- }
- frame += 0.2f * dt;
- if(frame >= 2.f || !onGround())
- {
- _jump_timer = 0.f;
- if(_long_jump)
- {
- vel = Vec2(4*_scalex, -4);
- }
- else if( (_inputs.check(Input::Action1) || _inputs.check(Input::Action2))
- && wall(rect[_size], _scalex))
- {
- int height = wallHeight(rect[_size], _scalex, 6);
- vel = Vec2((2.5f + height/2)*_scalex, -4.f - height*1.2f);
- }
- else
- {
- float h = 2.f;
- vel.y = -std::sqrt(h * 2 * 16 * gravity);
- _jump_timer = JumpTimerMax;
- }
- _state = Jumping;
- }
- }
- else if(_state == Jumping)
- {
- frame += 0.2f * dt;
- if(vel.y < 0 && frame > 6)
- frame = 6.f;
- else if(vel.y > 0 && frame < 6)
- frame = 6.f;
- if(frame > 9.f)
- frame = 9.f;
- if(_inputs.check(Input::Space) && _jump_timer > 0.f)
- {
- if(_jump_timer > 0.f) {
- vel.y -= 0.25f * dt;
- _jump_timer -= dt;
- }
- }
- else {
- _jump_timer = 0.f;
- }
- if(onGround())
- {
- setState(Idle);
- }
- else if(_inputs.check(Input::Left) ^ _inputs.check(Input::Right))
- {
- _scalex = _inputs.check(Input::Left) ? -1.f : 1.f;
- force_x = (4.f + _size/2.f) * _scalex;
- }
- }
- else if(_state == JumpEnd)
- {
- frame += 0.2f * dt;
- if(_inputs.check(Input::Left) ^ _inputs.check(Input::Right)) {
- setState(Walk);
- }
- else if(frame >= 14) {
- setState(Idle);
- }
- }
- else if(_state == ShootFast)
- {
- if(frame >= 2 && frame < 3) {
- frame += 0.1f * dt;
- } else {
- frame += 0.2f * dt;
- }
- if(!bullet_launched && frame >= 3.f) {
- bullet_launched = true;
- Vec2 w = boundingBox().center();
- w += Vec2(facingx() * 60, -14);
- float a = getShootAngle(w, findNearTarget(1200.f), 45);
- std::weak_ptr<AliveObject> this_weak( std::dynamic_pointer_cast<AliveObject>(shared()) );
- auto& ctx = worldContext();
- auto attr = std::make_unique<BulletAttributes>(
- ctx, itemIndexFromEntry("pc_beam_alien"),
- //std::make_unique<od::Rect>(-9, -9, 9, 9),
- std::make_unique<BulletDirectional>(a, BulletShootSpeed),
- this_weak, creatureTypeTarget());
- attr->setDamageCoef(attackDamages(1).fire());
- od::instanceCreate<BulletObject>(ctx, w, std::move(attr));
- }
- if(frame >= 9)
- setState(Idle);
- }
- else if(_state == Shoot) // big laser
- {
- frame += 0.2f * dt;
- if(!bullet_launched && frame >= 13.f) {
- bullet_launched = true;
- Vec2 w = boundingBox().center();
- w += Vec2(1 + facingx() * 62, -14);
- float a = facingx() < 0.f? 180:0;
- std::weak_ptr<AliveObject> this_weak( std::dynamic_pointer_cast<AliveObject>(shared()) );
- ItemIndex bullet = itemIndexFromEntry("pc_bullet_laser_alien");
- BulletObject* ins = od::instanceCreate<BulletObject>(
- worldContext(),
- std::make_unique<BulletDirectional>(a, 4),
- bullet,
- w,
- creatureTypeTarget(),
- std::make_unique<od::Rect>(-15, -15, 15, 15),
- this_weak);
- ins->setDamageCoef(attackDamages(2).fire());
- }
- if(frame >= 22)
- setState(Idle);
- }
- else if(_state == ShootUp)
- {
- frame += 0.2f * dt;
- if(!bullet_launched && frame >= 13.f) {
- bullet_launched = true;
- Vec2 w = boundingBox().center();
- w += Vec2(facingx() * 52, -43);
- float a = facingx() < 0.f ? 145:35;
- std::weak_ptr<AliveObject> this_weak( std::dynamic_pointer_cast<AliveObject>(shared()) );
- ItemIndex bullet = itemIndexFromEntry("pc_bullet_laser_alien");
- BulletObject* ins = od::instanceCreate<BulletObject>(
- worldContext(),
- std::make_unique<BulletDirectional>(a, 4),
- bullet,
- w,
- creatureTypeTarget(),
- std::make_unique<od::Rect>(-15, -15, 15, 15),
- this_weak);
- ins->setDamageCoef(attackDamages(2).fire());
- }
- if(frame >= 25)
- setState(Idle);
- }
- else if(_state == Punch)
- {
- if(frame >= 1 && frame < 2) {
- frame += 0.06f * dt;
- } else {
- frame += 0.2f * dt;
- }
- if(frame >= 2.f && frame <= 4.f)
- {
- if(!bullet_launched) {
- vel.x += 4.f * facingx();
- bullet_launched = true;
- }
- od::Rect hitbox = boundingBoxRelative();
- hitbox.scale(1.5f, 1, facingx()>0?hitbox.Left:hitbox.Right, hitbox.Bottom);
- hitbox.translate(-16*facingx(), 0);
- Damage d = attackDamages(0);
- d.vel.x *= facingx();
- DamageZoneBase dz(d, creatureTypeTarget(), boundingBox().center(), true);
- dz.hurt(worldContext(), hitbox, pos, this, true);
- }
- if(frame >= 10.f)
- {
- setState(Idle);
- }
- }
- bool platforms_solid = !_inputs.check(Input::Control);
- enablePlatforms(platforms_solid);
- updatePhysics(dt, gravity, force_x, 0, 0.05f, 0.0f, 4, true);
- if(collisionTop () || collisionBottom()) vel.y = 0;
- if(collisionLeft() || collisionRight ()) vel.x = 0;
- enablePlatforms(false);
- /*
- // /spawn pc_monster_alien_brutal 10
- updatePhysics(dt, 0.34, force_x, 0, 0.05, 0.1, 4, true);
- if(collisionTop() || collisionBottom()) vel.y = 0;
- if(collisionLeft() || collisionRight()) vel.x = 0;*/
- }
- std::tuple<float, bool> AlienBrutal::getShootAngle(Vec2 w, AliveObject* target, float range) const
- {
- float a = facingx() < 0.f? 180:0;
- if(!target)
- return std::make_tuple(a, false);
- return getShootAngle(w, target->boundingBox().center(), range);
- }
- std::tuple<float, bool> AlienBrutal::getShootAngle(Vec2 w, Vec2 target, float range) const
- {
- float a = facingx() < 0.f? 180:0;
- float dir = od::pointDirection(w.x, w.y, target.x, target.y);
- if(facingx() < 0.f)
- {
- if( (dir > 0 && dir < 180-range) || (dir > 180+range))
- a = 180;
- else
- a = dir;
- }
- else
- {
- if( (dir > range && dir <= 180) || (dir > 180 && dir < 270+range) )
- a = 0;
- else
- a = dir;
- }
- return std::make_tuple(a, a == dir);
- }
- void AlienBrutal::evGetHit(AliveObject* owner, float damages)
- {
- Monster::evGetHit(owner, damages);
- if(alive()) {
- playSound(MonstersSfx::ins().alien_brutal_hurt, pos);
- }
- }
- void AlienBrutal::evDie(AliveObject* owner)
- {
- Monster::evDie(owner);
- playSound(MonstersSfx::ins().alien_brutal_die, pos);
- frame = 0;
- _state = Die;
- }
- bool AlienBrutal::haveRecoil() const
- {
- if(!isChocked() /*&& (_state == Attack)*/)
- return false;
- return true;
- }
- void AlienBrutal::setControlable(bool enabled, bool remote)
- {
- setPlayerControlable(enabled);
- if(enabled) {
- _brain = std::make_unique<MonsterBrainKeyboard<AlienBrutal>>(remote, false);
- }
- else {
- _brain = std::make_unique<BrainAI>(*this);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment