void Sheep::doStuff(const EventHandler&, const std::vector< std::vector<TileSprite*> >& tiles, std::map< std::string, Entity* >& entities, sf::Time animate) { //Compute the gravity computeGravity(animate); //Check the collisions, set the new distances and do the move Collide collideTiles = collideWithTiles(tiles, animate.asSeconds()); setDistance(collideTiles); move(animate.asSeconds()*(speed.x), animate.asSeconds()*speed.y); sprite->update(animate); doAttack(entities); if (damageCD) { --damageCD; } }
////////////////////////////////////////////////////////////////////////// // tickBehaviour void GaGameUnit::tickBehaviour( BcFixed Delta ) { #if PSY_DEBUG static BcU32 BreakID = BcErrorCode; if( ID_ == BreakID ) { BcBreakpoint; } #endif switch( Behaviour_ ) { case BEHAVIOUR_IDLE: { CurrState_.Velocity_ = BcFixedVec2d( 0.0f, 0.0f ); BcU32 NearestUnit = pSimulator_->findNearestUnit( CurrState_.Position_, ID_, 1 << ( 1 - TeamID_ ) ); if( NearestUnit != BcErrorCode ) { doAttack( NearestUnit ); } } break; case BEHAVIOUR_GUARD: { CurrState_.Velocity_ = BcFixedVec2d( 0.0f, 0.0f ); BcU32 NearestUnit = pSimulator_->findNearestUnit( CurrState_.Position_, ID_, 1 << ( 1 - TeamID_ ) ); if( NearestUnit != BcErrorCode ) { doAttack( NearestUnit ); } } break; case BEHAVIOUR_MOVE: { BcU32 NearestUnit = pSimulator_->findNearestUnit( CurrState_.Position_, ID_, 1 << ( 1 - TeamID_ ) ); if( IsAttackMove_ && inRangeForAttack( NearestUnit ) == RANGE_IN ) { CurrState_.Velocity_ = BcFixedVec2d( 0.0f, 0.0f ); doAttack( NearestUnit ); } else { // Reset attack timer. AttackTimer_ = BcMax( AttackTimer_, BcFixed( Desc_.CoolDownMultiplier_ ) / Desc_.RateOfAttack_ ); // Make longer whe moving. AttackTimer_ = BcMin( BcFixed( 1.0f ) / Desc_.RateOfAttack_, AttackTimer_ + ( BcFixed( 1.0f ) / Desc_.RateOfAttack_ ) * ( Delta * 0.05f ) ); // Calculate velocity vector. CurrState_.Velocity_ = BcFixedVec2d( MoveTargetPosition_ - CurrState_.Position_ ).normal() * Desc_.MoveSpeed_; BcFixed MoveDistance = Desc_.MoveSpeed_ * Delta; if( ( CurrState_.Position_ - MoveTargetPosition_ ).magnitudeSquared() < ( MoveDistance * MoveDistance ) ) { CurrState_.Position_ = MoveTargetPosition_; setBehaviourIdle(); } } } break; case BEHAVIOUR_ATTACK: { TRange Range = inRangeForAttack( TargetUnitID_ ); if( Range == RANGE_IN ) { doAttack( TargetUnitID_ ); } else { // Reset attack timer. AttackTimer_ = BcMax( AttackTimer_, BcFixed( Desc_.CoolDownMultiplier_ ) / ( Desc_.RateOfAttack_ ) ); // Make longer whe moving. AttackTimer_ = BcMin( BcFixed( 1.0f ) / Desc_.RateOfAttack_, AttackTimer_ + ( BcFixed( 1.0f ) / Desc_.RateOfAttack_ ) * ( Delta * 0.05f ) ); // Get unit position. GaGameUnit* pUnit = pSimulator_->getUnit( TargetUnitID_ ); if( pUnit != NULL ) { BcFixedVec2d Direction = ( getPosition() - pUnit->getPosition() ).normal() * ( ( Desc_.MinRange_ + Desc_.Range_ ) * 0.5f ); MoveTargetPosition_ = pUnit->getPosition() + Direction; } else { // Attack move to previous target. IsAttackMove_ = BcTrue; Behaviour_ = BEHAVIOUR_MOVE; } // Calculate velocity vector. CurrState_.Velocity_ = BcFixedVec2d( MoveTargetPosition_ - CurrState_.Position_ ).normal() * Desc_.MoveSpeed_; // If we moved further away, then stop and set target. BcFixed CurrMagnitudeSquared = ( CurrState_.Position_ - MoveTargetPosition_ ).magnitudeSquared(); BcFixed PrevMagnitudeSquared = ( PrevState_.Position_ - MoveTargetPosition_ ).magnitudeSquared(); if( CurrMagnitudeSquared > PrevMagnitudeSquared ) { setBehaviourIdle(); } } } break; case BEHAVIOUR_DAMAGE: { // Calculate velocity vector. CurrState_.Velocity_ = BcFixedVec2d( MoveTargetPosition_ - CurrState_.Position_ ).normal() * Desc_.MoveSpeed_; BcFixed MoveDistance = Desc_.MoveSpeed_ * Delta; if( ( CurrState_.Position_ - MoveTargetPosition_ ).magnitudeSquared() < ( MoveDistance * MoveDistance ) ) { CurrState_.Position_ = MoveTargetPosition_; // Cause damage. pSimulator_->applyDamage( MoveTargetPosition_, Desc_.Range_, Desc_.Health_ ); // Debug point! pSimulator_->addDebugPoint( getPosition(), Desc_.Range_, RsColour::YELLOW ); if( Desc_.pHitSound_ != NULL ) { GaTopState::pImpl()->playSound( Desc_.pHitSound_, MoveTargetPosition_ ); } // Set as dead. setBehaviourDead(); } } break; } // Attack timer. if( AttackTimer_ > 0.0f ) { AttackTimer_ -= Delta; } else if( AttackTimer_ < 0.0f ) { AttackTimer_ = 0.0f; } // Death. if( Health_ <= 0.0f ) { Health_ = 0.0f; Behaviour_ = BEHAVIOUR_DEAD; } }
//returns ms elapsed, -2 if the monster dies int shMonster::doPet () { int i, n; shCoord coord[9]; int info[9]; int best = -1; int score, bestscore = -9999; int flags = kLinedUp | kTrap; int res = -1; int dist; int scrubbot = isA (kMonScrubbot); int val_linedup; int val_adjacent; int val_dist; int val_track; int val_monst; shMonster *c; int elapsed; /* first priority is always to drink any beer in our square! */ res = drinkBeer (); if (-1 != res) return res; if (mHP > mMaxHP / 4) { flags |= kMonster; } if (canSee (&Hero)) { findPetGoal (); val_linedup = -10; val_dist = -2; val_track = -5; val_adjacent = RNG (3) ? -5 : 10; val_monst = 10; } else { mDestX = Hero.mX; mDestY = Hero.mY; val_linedup = 0; val_dist = -1; val_track = -10; val_adjacent = 5; val_monst = 5; } if (isSessile ()) { val_monst += 50; } if (scrubbot) flags |= kFreeWreck; n = findSquares (flags, coord, info); for (i = 0; i < n; i++) { score = 0; if (info[i] & kTrap and RNG (30)) /* small chance that a pet will walk on a trap*/ { score -= 30; } if (info[i] & kFreeWreck) score += 50; if (info[i] & kLinedUp) score += val_linedup; if (info[i] & kMonster) { c = (shMonster *) mLevel->getCreature (coord[i].mX, coord[i].mY); if (c and !c->isHero () and !c->isPet () and c->isHostile () and /* Smart bombs and missiles should be ready to sacrifice themselves on any hostile target. isExplosive checks this. */ (c->mCLevel <= mCLevel + 1 or isExplosive ())) { score += c->isHostile () ? val_monst : val_monst / 2; } else if (c != this) { score -= 30; } } if (coord[i].mX == mX and coord[i].mY == mY) { score -= 10; } if (areAdjacent (coord[i].mX, coord[i].mY, Hero.mX, Hero.mY)) score += val_adjacent; dist = distance (coord[i].mX, coord[i].mY, mDestX, mDestY); if (dist > 50 and val_dist > 0) { dist = 50; } score += val_dist * dist; int ti; for (ti = 0 ; ti < TRACKLEN; ti++) { if (mTrack[ti].mX == coord[i].mX and mTrack[ti].mY == coord[i].mY) { score += val_track; } } if (score > bestscore) { bestscore = score; best = i; } } if (-1 == best) { /* nothing to do but stay where we are for now */ return 500; } if (coord[best].mX == mX and coord[best].mY == mY) { if (info[best] & kFreeWreck) { shObjectVector *v = mLevel->getObjects (mX, mY); shObject *obj; for (int i = 0; i < v->count (); ++i) { obj = v->get (i); if (obj->isA (kObjWreck)) { v->remove (obj); if (0 == v->count ()) { delete v; mLevel->setObjects (mX, mY, NULL); } return utilizeWreck (obj); } } } return 250; } else { if (info[best] & kMonster) { c = (shMonster *) mLevel->getCreature (coord[best].mX, coord[best].mY); doAttack (c, &elapsed); return elapsed; } if (!isSessile ()) return doMove (vectorDirection (mX, mY, coord[best].mX, coord[best].mY)); } return 250; }