onilink_

Untitled

Nov 12th, 2019
603
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 20.44 KB | None | 0 0
  1. #include "brutal.h"
  2. #include <centauri/damages/damage_zone_base.h>
  3. #include <centauri/damages/damage_digits.h>
  4. #include <centauri/assets_api/monster.h>
  5. #include <centauri/bullet/base.h>
  6. #include <centauri/bullet/attribute.h>
  7. #include <centauri/bullet/motion/directional.h>
  8. #include <centauri/monsters/sfx.h>
  9. #include <centauri/sfx/global.h>
  10. #include <centauri/random.h>
  11. #include <centauri/tools.h>
  12. #include <centauri/input/keybinding.h>
  13. #include <centauri/world/context.h>
  14. #include <centauri/deco/decoration.h>
  15. #include <centauri/game/interact.h>
  16. #include <onidev.h>
  17. #include <onidev/make_unique.h>
  18. #include <cmath>
  19. #include <cstdio>
  20. #include <cassert>
  21. #include <iostream>
  22. #include <fstream>
  23.  
  24. #include <centauri/monsters/brain/land_ai.h>
  25.  
  26. // /spawn pc_monster_alien_brutal
  27.  
  28. namespace
  29. {
  30.  
  31. struct BrainAI:
  32.     public GenericLandAIBrain<AlienBrutal>
  33. {
  34.     float cooldown_laser = 0;
  35.     float cooldown_shoot = 0;
  36.     int   shoot_counter = 0;
  37.    
  38.     BrainAI(const AlienBrutal& ins):
  39.         GenericLandAIBrain<AlienBrutal>(ins.sizeInBlocks()) {}    
  40.    
  41.     void update(const AlienBrutal& ins, Input& inputs, float dt) override {
  42.         cooldown_laser -= dt;
  43.         cooldown_shoot -= dt;
  44.         updateAI(ins, inputs, dt);
  45.     }
  46.    
  47.     bool tryToAttack(const AlienBrutal& ins, const Focus& focus, Input& inputs) override
  48.     {
  49.         bool ret = false;
  50.        
  51.         od::Rect box1 = ins.boundingBox();
  52.         od::Rect box2 = focus.box;
  53.         bool facing = false;
  54.         if(ins.facingx() > 0.f)
  55.             facing = box1.x2 <= box2.x1;
  56.         else
  57.             facing = box1.x1 >= box2.x2;
  58.        
  59.         float dist = focus.distanceTo(ins);
  60.         float hsep = std::abs(box1.center().x - box2.center().x);
  61.         float scale = ins.size() + 1;
  62.        
  63.         if(dist < 64 * scale
  64.         && (hsep < 64 || facing))
  65.         {
  66.             inputs.simulateCheck(Input::Action1); // punch
  67.             return true;
  68.         }
  69.         else if(cooldown_shoot <= 0)
  70.         {
  71.             if(ins.state() != ins.Shoot
  72.             && ins.state() != ins.ShootFast
  73.             && ins.state() != ins.ShootUp)
  74.             {
  75.                 if(tryShoot(ins, inputs, focus)) {
  76.                     shoot_counter++;
  77.                     ret = true;
  78.                 }
  79.                
  80.                 float coef = ins.lifeCoeff();
  81.                 bool low_life = coef < 0.5f;
  82.                
  83.                 if(low_life)
  84.                 {
  85.                     if(shoot_counter >= 5)
  86.                     {
  87.                         cooldown_shoot = 3*60;
  88.                     }
  89.                 }
  90.                 else
  91.                 {
  92.                     if(shoot_counter >= 3)
  93.                     {
  94.                         cooldown_shoot = 10*60;
  95.                     }
  96.                 }
  97.             }
  98.         }
  99.         else
  100.         {
  101.             shoot_counter = 0;
  102.         }
  103.        
  104.         return ret;
  105.     }
  106.    
  107.    
  108.     bool tryShoot(const AlienBrutal& ins, Input& inputs, const Focus& focus)
  109.     {
  110.         if(!focus) {
  111.             return false;
  112.         }
  113.        
  114.         float dist_sep = focus.distanceTo(ins);
  115.         const od::Rect& box1 = ins.boundingBox();
  116.         od::Rect box2 = focus.box;
  117.        
  118.         float vsep  = std::abs(box1.center().y - box2.center().y);
  119.        
  120.        
  121.         // shoot fast offset
  122.         /// @todo use also beam offset
  123.         Vec2 w = ins.boundingBox().center();
  124.         w += Vec2(0, -14);
  125.        
  126.         // shoot only if the player is accessible
  127.         // - on the good range (angle, distance)
  128.         // - not behind a wall
  129.        
  130.         // big horizontal laser shoot
  131.         if(cooldown_laser <= 0.f
  132.         && shoot_counter >= 2
  133.         && vsep < 48)
  134.         {
  135.             bool raycast = false;
  136.             float dist = std::max(0.f, dist_sep - 16);
  137.             raycastTest(ins.getWorld(), w, w + od::Vec2(dist * ins.facingx(), 0.f), 2, raycast, false);
  138.             if(raycast)
  139.                 raycastTest(ins.getWorld(), w, box2.center(), 2, raycast, false);
  140.            
  141.             if(!raycast)
  142.             {
  143.                 inputs.simulateCheck(Input::MouseLeft);
  144.                 inputs.simulateCheck(Input::Down);
  145.                 cooldown_laser = Rand()(160, 200);
  146.                 return true;
  147.             }
  148.         }
  149.        
  150.         float angle;
  151.         bool  on_range;
  152.         std::tie(angle, on_range) = ins.getShootAngle(w, box2.center());
  153.        
  154.         // fast small bullet shoot
  155.         if(on_range)
  156.         {
  157.             bool raycast = false;
  158.             raycastTest(ins.getWorld(), w, box2.center(), 2, raycast, false);
  159.             if(!raycast)
  160.             {
  161.                 inputs.simulateCheck(Input::MouseLeft);
  162.                 return true;
  163.             }
  164.         }
  165.         return false;
  166.     }
  167. };
  168.  
  169. }
  170.  
  171. // /spawn pc_monster_alien_brutal 40
  172.  
  173. od::Rect AlienBrutal::rect[3] =
  174. {
  175.     od::Rect(0, 0, 44, 60),
  176.     od::Rect(0, 0, 44*2, 60*2),
  177.     od::Rect(0, 0, 44*3, 60*3)
  178. };
  179.  
  180. AlienBrutal::AlienBrutal(WorldContext& context, const MonsterAttributes& attribs,
  181.                          const od::Vec2& pos, const MonsterSpawnParam& param):
  182.     Object(context, pos),
  183.     DynamicObject(context, pos),
  184.     TextureLifeManagerCRTP<AlienBrutal>("assets/Monsters/alien_brutal.xml"),
  185.     SetIndexVirtual<Object, AlienBrutal, 120>(context, pos),
  186.     LandMonster(context, attribs, pos, param)
  187. {
  188.     _state = Idle;
  189.     _scalex = param.reversed?-1:1;
  190.    
  191.     if(const Suffix* s = findSuffix(SuffixType::Giant))
  192.     {
  193.         _size = int(s->value() - 1);
  194.         Assert(_size <= 2);
  195.     }
  196.    
  197.     if(param.preview) {
  198.         _brain = std::make_unique<MonsterBrainPreview<AlienBrutal>>();
  199.     }
  200. }
  201.  
  202. AlienBrutal::~AlienBrutal()
  203. {
  204. }
  205.  
  206. void AlienBrutal::evSend(od::StreamData& s)
  207. {
  208.     s << pos.x << pos.y
  209.       << vel.x << vel.y
  210.       << _inputs1
  211.       << _inputs2;
  212.    
  213.     _inputs1 = _inputs2 = 0;
  214. }
  215.  
  216. void AlienBrutal::evReceive(od::StreamData& s)
  217. {
  218.     uint16_t inputs, old_inputs;
  219.     multiplayerSmoothMovement(s);
  220.     s >> inputs >> old_inputs;
  221.     _inputs.set(inputs, old_inputs);
  222. }
  223.  
  224. const od::Shape* AlienBrutal::collisionMask(int p) const
  225. {
  226.     return &rect[_size];
  227. }
  228.  
  229. void AlienBrutal::instanceDraw() const
  230. {
  231.     od::metatextureUse("alien_brutal_monster");
  232.    
  233.     const float scale = _size + 1;
  234.     int wx = rect[_size].width() / 2;
  235.     int wy = rect[_size].height();
  236.    
  237.     shaderIndexedStartAuto(rarity());
  238.    
  239.     if(_state == Idle)
  240.         od::drawSpriteScaled("idle", frame, pos.x + wx, pos.y + wy, _scalex * scale, scale);
  241.     else if(_state == Walk)
  242.         od::drawSpriteScaled("move", frame, pos.x + wx, pos.y + wy, _scalex * scale, scale);
  243.     else if(_state == JumpStart || _state == Jumping || _state == JumpEnd)
  244.         od::drawSpriteScaled("jump", frame, pos.x + wx, pos.y + wy, _scalex * scale, scale);
  245.     else if(_state == Punch)
  246.         od::drawSpriteScaled("punch", frame, pos.x + wx, pos.y + wy, _scalex * scale, scale);
  247.     else if(_state == ShootFast)
  248.         od::drawSpriteScaled("shoot", frame, pos.x + wx, pos.y + wy, _scalex * scale, scale);
  249.     else if(_state == Shoot)
  250.         od::drawSpriteScaled("shoot_charge_f", frame, pos.x + wx, pos.y + wy, _scalex * scale, scale);
  251.     else if(_state == ShootUp)
  252.         od::drawSpriteScaled("shoot_charge_u", frame, pos.x + wx, pos.y + wy, _scalex * scale, scale);
  253.     else
  254.         od::drawSpriteScaled("die", frame, pos.x + wx, pos.y + wy, _scalex * scale, scale);
  255.    
  256.     shaderIndexedEnd();
  257.    
  258.     //od::drawRectangle(pos.x + rect[size].x1, pos.y + rect[size].y1, pos.x + rect[size].x2, pos.y + rect[size].y2, true);
  259. }
  260.  
  261. void AlienBrutal::setState(State state, bool reset_frame)
  262. {
  263.     _state = state;
  264.     if(_state == Jumping)
  265.         frame = 6.f;
  266.     else if(reset_frame)
  267.         frame = 0.f;
  268.    
  269.     if(state == Shoot || state == ShootUp) {
  270.         //playSound(MonstersSfx::ins().alien_brutal_laser, pos);
  271.         _attack_prepare = 5.f;
  272.         od::instanceCreate<DamageDigits>(
  273.                     worldContext(), boundingBox().center()
  274.                     + Vec2(0.f, -8.f),
  275.                     DamageDigits::Attack, 0);
  276.     }
  277.     else if(state == ShootFast)
  278.         playSound(MonstersSfx::ins().alien_brutal_shoot, pos);
  279.     else if(state == Punch)
  280.         playSound(MonstersSfx::ins().alien_brutal_punch, pos);
  281.    
  282.     bullet_launched = false;
  283. }
  284.  
  285. void AlienBrutal::monsterStep(float dt)
  286. {
  287.     constexpr float JumpTimerMax = 8.f;
  288.     constexpr float gravity = 0.2f;
  289.     const float BulletShootSpeed = 5.f;
  290.    
  291.     if(!alive())
  292.     {
  293.         frame += 0.2f * dt;
  294.         if(frame >= 14)
  295.             instanceDestroy();
  296.         else
  297.             updatePhysics(dt, 0.34f, 0, 0, 0.05f, 0.1f, 4, true);
  298.         return;
  299.     }
  300.    
  301.     if(isPetrified()) {
  302.         updatePhysics(dt, 0.34f, 0, 0, 0.05f, 0.1f, 4, true);
  303.         return;
  304.     }
  305.    
  306.     // /spawn pc_monster_alien_brutal 30
  307.     if(!_brain)
  308.     {
  309.         //_brain = std::make_unique<MonsterBrainKeyboard<AlienBrutal>>(false, false);
  310.         _brain = std::make_unique<BrainAI>(*this);
  311.     }
  312.    
  313.     auto checkInputs = [this]() {
  314.         if(_inputs.check(Input::Space))
  315.         {
  316.             setState(JumpStart);
  317.         }
  318.         else if(canAttack() && _inputs.check(Input::MouseLeft))
  319.         {
  320.             if(_inputs.check(Input::Up))
  321.                 setState(ShootUp);
  322.             else if(_inputs.check(Input::Down))
  323.                 setState(Shoot);
  324.             else
  325.                 setState(ShootFast);
  326.         }
  327.         else if(canAttack() && _inputs.check(Input::Action1))
  328.         {
  329.             setState(Punch);
  330.         }
  331.         else if(_inputs.check(Input::Left) ^ _inputs.check(Input::Right))
  332.         {
  333.             _scalex = _inputs.check(Input::Left) ? -1.f : 1.f;
  334.             if(_state != Walk)
  335.                 setState(Walk);
  336.         }
  337.         else
  338.             return false;
  339.         return true;
  340.     };
  341.    
  342.     auto getShootAngle = [this](Vec2 w, AliveObject* target, float range)
  343.     {
  344.         return std::get<0>( this->getShootAngle(w, target, range) );
  345.     };
  346.    
  347.     // /spawn pc_monster_alien_brutal 10
  348.    
  349.     _brain->update(*this, _inputs, dt);
  350.    
  351.     _inputs1 |= _inputs.state();
  352.     _inputs2 |= _inputs.ostate();
  353.    
  354.     bool on_ground = onGround();
  355.     if(on_ground) {
  356.         _ground_timer = 3.f;
  357.     }
  358.     else if(_ground_timer > 0.f) {
  359.         _ground_timer -= dt;
  360.         if(_ground_timer > 0.f)
  361.             on_ground = true;
  362.     }
  363.    
  364.     // Server
  365.     float force_x = 0;
  366.    
  367.     if(_attack_prepare > 0.f) {
  368.         _attack_prepare -= dt;
  369.        
  370.         if(_attack_prepare <= 0.f
  371.         && (_state == Shoot || _state == ShootUp)) {
  372.             playSound(MonstersSfx::ins().alien_brutal_laser, pos);
  373.         }
  374.     }
  375.     else if(_state == Idle)
  376.     {
  377.         frame += 0.2f * dt;
  378.        
  379.         if(on_ground)
  380.         {
  381.             checkInputs();
  382.         }
  383.         else
  384.             setState(Jumping);
  385.     }
  386.     else if(_state == Walk)
  387.     {
  388.         frame += 0.2f * dt;
  389.        
  390.         if(on_ground)
  391.         {
  392.             if(!checkInputs())
  393.             {
  394.                 setState(Idle);
  395.             }
  396.            
  397.             force_x = (2 + _size/2.f) * _scalex;
  398.         }
  399.         else
  400.             setState(Jumping);
  401.     }
  402. //    else if(_state == JumpStart)
  403. //    {
  404. //        frame += 0.2f * dt;
  405. //        _jump_timer = 0.f;
  406.        
  407. //        if(frame >= 2.f)
  408. //        {
  409. //            if(_inputs.check(Input::Shift) || _inputs.released(Input::Shift))
  410. //            {
  411. //                vel = Vec2(4*_scalex, -5);
  412. //            }
  413. //            else if( (_inputs.check(Input::Action1) || _inputs.check(Input::Action2))
  414. //                     && wall(rect[_size], _scalex))
  415. //            {
  416. //                int height = wallHeight(rect[_size], _scalex, 6);
  417. //                vel = Vec2((2 + height/2)*_scalex, -4.5 - height*1.2);
  418. //            }
  419. //            else
  420. //            {
  421. //                vel.y = -6.f;
  422. //                _jump_timer = JumpTimerMax;
  423. //            }
  424.            
  425. //            _state = Jumping;
  426. //        }
  427. //    }
  428.     else if(_state == JumpStart)
  429.     {
  430.         if(frame == 0.f) {
  431.             _long_jump = _inputs.check(Input::Shift) || _inputs.released(Input::Shift);
  432.         }
  433.         frame += 0.2f * dt;
  434.        
  435.         if(frame >= 2.f || !onGround())
  436.         {
  437.             _jump_timer = 0.f;
  438.            
  439.             if(_long_jump)
  440.             {
  441.                 vel = Vec2(4*_scalex, -4);
  442.             }
  443.             else if( (_inputs.check(Input::Action1) || _inputs.check(Input::Action2))
  444.                      && wall(rect[_size], _scalex))
  445.             {
  446.                 int height = wallHeight(rect[_size], _scalex, 6);
  447.                 vel = Vec2((2.5f + height/2)*_scalex, -4.f - height*1.2f);
  448.             }
  449.             else
  450.             {
  451.                 float h = 2.f;
  452.                 vel.y = -std::sqrt(h * 2 * 16 * gravity);
  453.                 _jump_timer = JumpTimerMax;
  454.             }
  455.            
  456.             _state = Jumping;
  457.         }
  458.     }
  459.     else if(_state == Jumping)
  460.     {
  461.         frame += 0.2f * dt;
  462.         if(vel.y < 0 && frame > 6)
  463.             frame = 6.f;
  464.         else if(vel.y > 0 && frame < 6)
  465.             frame = 6.f;
  466.        
  467.         if(frame > 9.f)
  468.             frame = 9.f;
  469.        
  470.         if(_inputs.check(Input::Space) && _jump_timer > 0.f)
  471.         {
  472.             if(_jump_timer > 0.f) {
  473.                 vel.y -= 0.25f * dt;
  474.                 _jump_timer -= dt;
  475.             }
  476.         }
  477.         else {
  478.             _jump_timer = 0.f;
  479.         }
  480.        
  481.         if(onGround())
  482.         {
  483.             setState(Idle);
  484.         }
  485.         else if(_inputs.check(Input::Left) ^ _inputs.check(Input::Right))
  486.         {
  487.             _scalex = _inputs.check(Input::Left) ? -1.f : 1.f;
  488.             force_x = (4.f + _size/2.f) * _scalex;
  489.         }
  490.     }
  491.     else if(_state == JumpEnd)
  492.     {
  493.         frame += 0.2f * dt;
  494.        
  495.         if(_inputs.check(Input::Left) ^ _inputs.check(Input::Right)) {
  496.             setState(Walk);
  497.         }
  498.         else if(frame >= 14) {
  499.             setState(Idle);
  500.         }
  501.     }
  502.     else if(_state == ShootFast)
  503.     {
  504.         if(frame >= 2 && frame < 3) {
  505.             frame += 0.1f * dt;
  506.         } else {
  507.             frame += 0.2f * dt;
  508.         }
  509.        
  510.         if(!bullet_launched && frame >= 3.f) {
  511.             bullet_launched = true;
  512.            
  513.             Vec2 w = boundingBox().center();
  514.             w += Vec2(facingx() * 60, -14);
  515.            
  516.             float a = getShootAngle(w, findNearTarget(1200.f), 45);
  517.             std::weak_ptr<AliveObject> this_weak( std::dynamic_pointer_cast<AliveObject>(shared()) );
  518.            
  519.             auto& ctx = worldContext();
  520.             auto attr = std::make_unique<BulletAttributes>(
  521.                             ctx, itemIndexFromEntry("pc_beam_alien"),
  522.                             //std::make_unique<od::Rect>(-9, -9, 9, 9),
  523.                             std::make_unique<BulletDirectional>(a, BulletShootSpeed),
  524.                             this_weak, creatureTypeTarget());
  525.             attr->setDamageCoef(attackDamages(1).fire());
  526.             od::instanceCreate<BulletObject>(ctx, w, std::move(attr));
  527.         }
  528.        
  529.         if(frame >= 9)
  530.             setState(Idle);
  531.     }
  532.     else if(_state == Shoot) // big laser
  533.     {
  534.         frame += 0.2f * dt;
  535.        
  536.         if(!bullet_launched && frame >= 13.f) {
  537.             bullet_launched = true;
  538.            
  539.             Vec2 w = boundingBox().center();
  540.             w += Vec2(1 + facingx() * 62, -14);
  541.            
  542.             float a = facingx() < 0.f? 180:0;
  543.             std::weak_ptr<AliveObject> this_weak( std::dynamic_pointer_cast<AliveObject>(shared()) );
  544.            
  545.             ItemIndex bullet = itemIndexFromEntry("pc_bullet_laser_alien");
  546.             BulletObject* ins = od::instanceCreate<BulletObject>(
  547.                         worldContext(),
  548.                         std::make_unique<BulletDirectional>(a, 4),
  549.                         bullet,
  550.                         w,
  551.                         creatureTypeTarget(),
  552.                         std::make_unique<od::Rect>(-15, -15, 15, 15),
  553.                         this_weak);
  554.             ins->setDamageCoef(attackDamages(2).fire());
  555.         }
  556.        
  557.         if(frame >= 22)
  558.             setState(Idle);
  559.     }
  560.     else if(_state == ShootUp)
  561.     {
  562.         frame += 0.2f * dt;
  563.        
  564.         if(!bullet_launched && frame >= 13.f) {
  565.             bullet_launched = true;
  566.            
  567.             Vec2 w = boundingBox().center();
  568.             w += Vec2(facingx() * 52, -43);
  569.            
  570.             float a = facingx() < 0.f ? 145:35;
  571.             std::weak_ptr<AliveObject> this_weak( std::dynamic_pointer_cast<AliveObject>(shared()) );
  572.            
  573.             ItemIndex bullet = itemIndexFromEntry("pc_bullet_laser_alien");
  574.             BulletObject* ins = od::instanceCreate<BulletObject>(
  575.                         worldContext(),
  576.                         std::make_unique<BulletDirectional>(a, 4),
  577.                         bullet,
  578.                         w,
  579.                         creatureTypeTarget(),
  580.                         std::make_unique<od::Rect>(-15, -15, 15, 15),
  581.                         this_weak);
  582.             ins->setDamageCoef(attackDamages(2).fire());
  583.         }
  584.        
  585.         if(frame >= 25)
  586.             setState(Idle);
  587.     }
  588.     else if(_state == Punch)
  589.     {
  590.         if(frame >= 1 && frame < 2) {
  591.             frame += 0.06f * dt;
  592.         } else {
  593.             frame += 0.2f * dt;
  594.         }
  595.        
  596.         if(frame >= 2.f && frame <= 4.f)
  597.         {
  598.             if(!bullet_launched) {
  599.                 vel.x += 4.f * facingx();
  600.                 bullet_launched = true;
  601.             }
  602.            
  603.             od::Rect hitbox = boundingBoxRelative();
  604.             hitbox.scale(1.5f, 1, facingx()>0?hitbox.Left:hitbox.Right, hitbox.Bottom);
  605.             hitbox.translate(-16*facingx(), 0);      
  606.            
  607.             Damage d = attackDamages(0);
  608.             d.vel.x *= facingx();
  609.             DamageZoneBase dz(d, creatureTypeTarget(), boundingBox().center(), true);
  610.             dz.hurt(worldContext(), hitbox, pos, this, true);
  611.         }
  612.        
  613.         if(frame >= 10.f)
  614.         {
  615.             setState(Idle);
  616.         }
  617.     }
  618.    
  619.    
  620.     bool platforms_solid = !_inputs.check(Input::Control);
  621.     enablePlatforms(platforms_solid);
  622.    
  623.     updatePhysics(dt, gravity, force_x, 0, 0.05f, 0.0f, 4, true);
  624.     if(collisionTop () || collisionBottom()) vel.y = 0;
  625.     if(collisionLeft() || collisionRight ()) vel.x = 0;
  626.    
  627.     enablePlatforms(false);    
  628.    
  629.     /*
  630.     // /spawn pc_monster_alien_brutal 10
  631.    
  632.     updatePhysics(dt, 0.34, force_x, 0, 0.05, 0.1, 4, true);
  633.     if(collisionTop() || collisionBottom()) vel.y = 0;
  634.     if(collisionLeft() || collisionRight()) vel.x = 0;*/
  635. }
  636.  
  637. std::tuple<float, bool> AlienBrutal::getShootAngle(Vec2 w, AliveObject* target, float range) const
  638. {
  639.     float a = facingx() < 0.f? 180:0;
  640.     if(!target)
  641.         return std::make_tuple(a, false);
  642.    
  643.     return getShootAngle(w, target->boundingBox().center(), range);
  644. }
  645.  
  646. std::tuple<float, bool> AlienBrutal::getShootAngle(Vec2 w, Vec2 target, float range) const
  647. {
  648.     float a = facingx() < 0.f? 180:0;
  649.    
  650.     float dir = od::pointDirection(w.x, w.y, target.x, target.y);
  651.     if(facingx() < 0.f)
  652.     {
  653.         if( (dir > 0 && dir < 180-range) || (dir > 180+range))
  654.             a = 180;
  655.         else
  656.             a = dir;
  657.     }
  658.     else
  659.     {
  660.         if( (dir > range && dir <= 180) || (dir > 180 && dir < 270+range) )
  661.             a = 0;
  662.         else
  663.             a = dir;
  664.     }
  665.     return std::make_tuple(a, a == dir);
  666. }
  667.  
  668. void AlienBrutal::evGetHit(AliveObject* owner, float damages)
  669. {
  670.     Monster::evGetHit(owner, damages);
  671.     if(alive()) {
  672.         playSound(MonstersSfx::ins().alien_brutal_hurt, pos);
  673.     }
  674. }
  675.  
  676. void AlienBrutal::evDie(AliveObject* owner)
  677. {
  678.     Monster::evDie(owner);
  679.     playSound(MonstersSfx::ins().alien_brutal_die, pos);
  680.     frame = 0;
  681.     _state = Die;
  682. }
  683.  
  684. bool AlienBrutal::haveRecoil() const
  685. {
  686.     if(!isChocked() /*&& (_state == Attack)*/)
  687.         return false;
  688.     return true;
  689. }
  690.  
  691. void AlienBrutal::setControlable(bool enabled, bool remote)
  692. {
  693.     setPlayerControlable(enabled);
  694.     if(enabled) {
  695.         _brain = std::make_unique<MonsterBrainKeyboard<AlienBrutal>>(remote, false);
  696.     }
  697.     else {
  698.         _brain = std::make_unique<BrainAI>(*this);
  699.     }
  700. }
Advertisement
Add Comment
Please, Sign In to add comment