| 124 | {} |
| 125 | |
| 126 | void Monster::Tick( |
| 127 | Map& map, |
| 128 | const EntityId monster_id, |
| 129 | const Time current_time, |
| 130 | const Time last_tick_delta ) |
| 131 | { |
| 132 | const GameResources::MonsterDescription& description= game_resources_->monsters_description[ monster_id_ ]; |
| 133 | const Model& model= game_resources_->monsters_models[ monster_id_ ]; |
| 134 | |
| 135 | PC_ASSERT( current_animation_ < model.animations.size() ); |
| 136 | PC_ASSERT( model.animations[ current_animation_ ].frame_count > 0u ); |
| 137 | |
| 138 | const float time_delta_s= ( current_time - current_animation_start_time_ ).ToSeconds(); |
| 139 | const float frame= time_delta_s * GameConstants::animations_frames_per_second; |
| 140 | |
| 141 | const unsigned int animation_frame_unwrapped= static_cast<unsigned int>( std::round(frame) ); |
| 142 | const unsigned int frame_count= model.animations[ current_animation_ ].frame_count; |
| 143 | const Time animation_duration= Time::FromSeconds( float(frame_count) / GameConstants::animations_frames_per_second ); |
| 144 | |
| 145 | // Update target position if target moves. |
| 146 | const MonsterBasePtr target= target_.monster.lock(); |
| 147 | float distance_for_melee_attack= Constants::max_float; |
| 148 | bool target_is_alive= false; |
| 149 | if( target != nullptr ) |
| 150 | { |
| 151 | target_is_alive= target->Health() > 0; |
| 152 | |
| 153 | if( CanSee( map, target->Position() ) ) |
| 154 | { |
| 155 | target_.position= target->Position(); |
| 156 | target_.have_position= true; |
| 157 | |
| 158 | distance_for_melee_attack= |
| 159 | ( pos_ - target_.position ).xy().Length() - game_resources_->monsters_description[ target->MonsterId() ].w_radius; |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | const float last_tick_delta_s= last_tick_delta.ToSeconds(); |
| 164 | |
| 165 | FallDown( last_tick_delta_s ); |
| 166 | |
| 167 | switch( state_ ) |
| 168 | { |
| 169 | case State::Idle: |
| 170 | if( SelectTarget( map ) ) |
| 171 | { |
| 172 | map.PlayMonsterSound( monster_id, Sound::MonsterSoundId::Alarmed ); |
| 173 | state_= State::MoveToTarget; |
| 174 | current_animation_= GetAnimation( AnimationId::Run ); |
| 175 | current_animation_start_time_ = current_time; |
| 176 | } |
| 177 | else if( animation_frame_unwrapped >= frame_count ) |
| 178 | { |
| 179 | const int idle_animation = GetIdleAnimation(); |
| 180 | // Try play boring animation, sometimes. Doubled borng animations is disabled. |
| 181 | if( random_generator_->RandBool( 8u ) ) |
| 182 | { |
| 183 | const int boring_animation= GetAnimation( AnimationId::Boring ); |