void LumosChitBag::HandleBolt( const Bolt& bolt, const ModelVoxel& mv ) { const ChitContext* context = Context(); Chit* chitShooter = GetChit( bolt.chitID ); // may be null int shooterTeam = -1; if ( chitShooter && chitShooter->GetItemComponent() ) { shooterTeam = chitShooter->GetItemComponent()->GetItem()->Team(); } int explosive = bolt.effect & GameItem::EFFECT_EXPLOSIVE; if ( !explosive ) { if ( mv.Hit() ) { Chit* chitHit = mv.ModelHit() ? mv.model->userData : 0; DamageDesc dd( bolt.damage, bolt.effect ); if ( chitHit ) { GLASSERT( GetChit( chitHit->ID() ) == chitHit ); if ( chitHit->GetItemComponent() && chitHit->GetItemComponent()->GetItem()->Team() == shooterTeam ) { // do nothing. don't shoot own team. } else { ChitDamageInfo info( dd ); info.originID = bolt.chitID; info.awardXP = true; info.isMelee = false; info.isExplosion = false; info.originOfImpact = mv.at; ChitMsg msg( ChitMsg::CHIT_DAMAGE, 0, &info ); chitHit->SendMessage( msg, 0 ); } } else if ( mv.VoxelHit() ) { context->worldMap->VoxelHit( mv.voxel, dd ); } } } else { // How it used to work. Now only uses radius: // Here don't worry about the chit hit. Just ray cast to see // who is in range of the explosion and takes damage. // Back up the origin of the bolt just a bit, so it doesn't keep // intersecting the model it hit. Then do ray checks around to // see what gets hit by the explosion. float rewind = Min( 0.1f, 0.5f*bolt.len ); GLASSERT( Equal( bolt.dir.Length(), 1.f, 0.001f )); Vector3F origin = mv.at - bolt.dir * rewind; DamageDesc dd( bolt.damage, bolt.effect ); BattleMechanics::GenerateExplosion( dd, origin, bolt.chitID, context->engine, this, context->worldMap ); } }
int CoreScript::CorePower() { int power = 0; for (int i = 0; i < citizens.Size(); ++i) { Chit* chit = Context()->chitBag->GetChit(citizens[i]); if (chit && chit->GetItemComponent()) { power += chit->GetItemComponent()->PowerRating(true); } } return power; }
Chit* LumosChitBag::NewBadGuy(const grinliz::Vector2I& pos, const IString& name, const grinliz::IString& type, int team, int level ) { const ChitContext* context = Context(); Chit* chit = NewChit(); const GameItem& root = ItemDefDB::Instance()->Get(type.safe_str()); chit->Add( new RenderComponent(root.ResourceName())); chit->Add( new PathMoveComponent()); AddItem(root.Name(), chit, context->engine, team, level, 0, "human"); ReserveBank::Instance()->WithdrawMonster(chit->GetWallet(), true); chit->GetItem()->GetTraitsMutable()->Roll( random.Rand() ); chit->GetItem()->GetPersonalityMutable()->Roll( random.Rand(), &chit->GetItem()->Traits() ); chit->GetItem()->FullHeal(); chit->GetItem()->SetProperName(name); AIComponent* ai = new AIComponent(); chit->Add( ai ); chit->Add( new HealthComponent()); chit->SetPosition( (float)pos.x+0.5f, 0, (float)pos.y+0.5f ); for (int i = 0; i < ForgeScript::NUM_ITEM_TYPES; ++i) { ForgeScript::ForgeData forgeData; forgeData.type = i; forgeData.subType = 0; forgeData.tech = 3; forgeData.level = level; forgeData.team = team; int seed = random.Rand(); ForgeScript::BestSubItem(&forgeData, seed); TransactAmt cost; TransactAmt freeCreate; static const int CRYSTAL[NUM_CRYSTAL_TYPES] = { 3, 2, 1, 1 }; freeCreate.Set(0, CRYSTAL); GameItem* loot = ForgeScript::ForgeRandomItem(forgeData, freeCreate, &cost, seed, ReserveBank::GetWallet()); if (loot) { chit->GetItemComponent()->AddToInventory(loot); loot->SetSignificant(chit->Context()->chitBag->GetNewsHistory(), ToWorld2F(chit->Position()), NewsEvent::FORGED, NewsEvent::UN_FORGED, chit->GetItem()); } } chit->GetItem()->SetSignificant(GetNewsHistory(), ToWorld2F(pos), NewsEvent::DENIZEN_CREATED, NewsEvent::DENIZEN_KILLED, 0); if (XenoAudio::Instance()) { Vector3F pos3 = ToWorld3F(pos); XenoAudio::Instance()->PlayVariation(ISC::rezWAV, random.Rand(), &pos3); } return chit; }
void CoreScript::DoStrategicTick() { // Look around for someone to attack. They should be: // - someone we have a negative attitude about (accounts for lots of things) // - weaker overall // // We should: // - have a reasonably armed squad bool squadReady[MAX_SQUADS] = { false }; CChitArray squaddies; // Check for ready squads. for (int i = 0; i < MAX_SQUADS; ++i) { this->Squaddies(i, &squaddies); if (squaddies.Size() < SQUAD_SIZE) continue; if (!SquadAtRest(i)) continue; // Do we have enough guns? Seems to be // the best / easiest metric. int nGuns = 0; for (int k = 0; k < squaddies.Size(); ++k) { Chit* chit = squaddies[k]; ItemComponent* ic = chit->GetItemComponent(); if ( chit->GetItem() && chit->GetItem()->HPFraction() > 0.75f && ic && ic->QuerySelectRanged()) { nGuns++; } } squadReady[i] = nGuns >= SQUAD_SIZE - 1; } int nReady = 0; for (int i = 0; i < MAX_SQUADS; ++i) { if (squadReady[i]) ++nReady; } Sim* sim = Context()->chitBag->GetSim(); GLASSERT(sim); if (!sim) return; Vector2I sector = ToSector(ParentChit()->Position()); CCoreArray stateArr; sim->CalcStrategicRelationships(sector, 3, &stateArr); // The strategic relationships need to be calculated, but after that, // there's no point in computing further if we don't have a squad to // send into action. if (nReady == 0) return; int myPower = this->CorePower(); CoreScript* target = 0; for (int i = 0; i < stateArr.Size(); ++i) { CoreScript* cs = stateArr[i]; if (cs->NumTemples() == 0) // Ignore starting out domains so it isn't a complete wasteland out there. continue; if ( Team::Instance()->GetRelationship(cs->ParentChit(), this->ParentChit()) == ERelate::ENEMY // Are we enemies at the diplomatic level && Team::Instance()->Attitude(this, cs) < 0) // Does 'this' have a negative attitude to the other? { int power = cs->CorePower(); if (power < myPower * 0.75f) { // Assuming this is actually so rare that it doesn't matter to select the best. target = cs; break; } } } if (!target) return; // Attack!!! bool first = true; Vector2F targetCorePos2 = ToWorld2F(target->ParentChit()->Position()); Vector2I targetCorePos = ToWorld2I(target->ParentChit()->Position());; Vector2I targetSector = ToSector(targetCorePos); for (int i = 0; i < MAX_SQUADS; ++i) { if (!squadReady[i]) continue; Vector2I pos = { 0, 0 }; pos = targetCorePos; if (first) { first = false; } else { BuildingWithPorchFilter filter; Chit* building = Context()->chitBag->FindBuilding(IString(), targetSector, &targetCorePos2, LumosChitBag::EFindMode::RANDOM_NEAR, 0, &filter); if (building) { pos = ToWorld2I(building->Position()); } } GLASSERT(!pos.IsZero()); this->SetWaypoints(i, pos); } }