void CoreScript::SetWaypoints(int squadID, const grinliz::Vector2I& dest) { GLASSERT(squadID >= 0 && squadID < MAX_SQUADS); waypoints[squadID].Clear(); if (dest.IsZero()) { return; } // Use the first chit to choose the starting location: bool startInSameSector = true; Vector2I startSector = { 0, 0 }; CChitArray chitArr; Squaddies(squadID, &chitArr); if (chitArr.Empty()) return; for (int i = 0; i<chitArr.Size(); ++i) { Chit* chit = chitArr[i]; if (startSector.IsZero()) startSector = ToSector(chit->Position()); else if (startSector != ToSector(chit->Position())) startInSameSector = false; } Vector2I destSector = ToSector(dest); // - Current port // - grid travel (implies both sector and target port) // - dest port (regroup) // - destination GLOUTPUT(("SetWaypoints: #chits=%d squadID=%d:", chitArr.Size(), squadID)); if (startSector != destSector) { Chit* chit = chitArr[0]; SectorPort sectorPort; if (startInSameSector) { // All together, so meet at the STARTING port. sectorPort = Context()->worldMap->NearestPort(ToWorld2F(chit->Position()), &ToWorld2F(dest)); } else { // Dispersed; meet at the DESTINATION port. sectorPort = Context()->worldMap->NearestPort(ToWorld2F(dest), &ToWorld2F(chit->Position())); } if (!sectorPort.IsValid()) { GLOUTPUT(("SetWaypoints: no path.\n")); return; } SectorData sectorData = Context()->worldMap->GetSectorData(sectorPort.sector); Vector2I p0 = sectorData.GetPortLoc(sectorPort.port).Center(); waypoints[squadID].Push(p0); GLOUTPUT(("%d,%d [s%c%d] ", p0.x, p0.y, 'A' + p0.x / SECTOR_SIZE, 1 + p0.y / SECTOR_SIZE)); } GLOUTPUT(("%d,%d [s%c%d]\n", dest.x, dest.y, 'A' + dest.x/SECTOR_SIZE, 1 + dest.y/SECTOR_SIZE)); waypoints[squadID].Push(dest); NewWaypointChits(squadID); }
void CameraRotationHandler::onMove(const G3MEventContext *eventContext, const TouchEvent& touchEvent, CameraContext *cameraContext) { const IMathUtils* mu = IMathUtils::instance(); //_currentGesture = getGesture(touchEvent); if (cameraContext->getCurrentGesture() != Rotate) return; // current middle pixel in 2D const Vector2I c0 = touchEvent.getTouch(0)->getPos(); const Vector2I c1 = touchEvent.getTouch(1)->getPos(); const Vector2I c2 = touchEvent.getTouch(2)->getPos(); const Vector2I cm = c0.add(c1).add(c2).div(3); // compute normal to Initial point Vector3D normal = eventContext->getPlanet()->geodeticSurfaceNormal(_pivotPoint ); // vertical rotation around normal vector to globe Camera *camera = cameraContext->getNextCamera(); camera->copyFrom(_camera0); Angle angle_v = Angle::fromDegrees((_pivotPixel.x()-cm._x)*0.25); camera->rotateWithAxisAndPoint(normal, _pivotPoint.asVector3D(), angle_v); // compute angle between normal and view direction Vector3D view = camera->getViewDirection(); double dot = normal.normalized().dot(view.normalized().times(-1)); double initialAngle = mu->acos(dot) / mu->pi() * 180; // rotate more than 85 degrees or less than 0 degrees is not allowed double delta = (cm._y - _pivotPixel.y()) * 0.25; double finalAngle = initialAngle + delta; if (finalAngle > 85) delta = 85 - initialAngle; if (finalAngle < 0) delta = -initialAngle; // create temporal camera to test if next rotation is valid Camera tempCamera(*camera); // horizontal rotation over the original camera horizontal axix Vector3D u = camera->getHorizontalVector(); tempCamera.rotateWithAxisAndPoint(u, _pivotPoint.asVector3D(), Angle::fromDegrees(delta)); // update camera only if new view intersects globe //tempCamera.updateModelMatrix(); if (!tempCamera.getXYZCenterOfView().isNan()) { camera->copyFrom(tempCamera); } }
Rectangle2I MapScene::MapBounds2() { Vector2I subOrigin = data->destSector; if (subOrigin.IsZero()) { subOrigin = lumosChitBag->GetHomeSector(); } if (subOrigin.IsZero()) { subOrigin.Set(NUM_SECTORS / 2, NUM_SECTORS / 2); } if ( subOrigin.x < MAP2_RAD ) subOrigin.x = MAP2_RAD; if ( subOrigin.y < MAP2_RAD ) subOrigin.y = MAP2_RAD; if ( subOrigin.x >= NUM_SECTORS - MAP2_RAD ) subOrigin.x = NUM_SECTORS - MAP2_RAD - 1; if ( subOrigin.y >= NUM_SECTORS - MAP2_RAD ) subOrigin.y = NUM_SECTORS - MAP2_RAD - 1; Rectangle2I subBounds; subBounds.min = subBounds.max = subOrigin; subBounds.Outset(MAP2_RAD); return subBounds; }
void Visibility::CalcVisibilityRay( int unitID, const Vector2I& pos, const Vector2I& origin ) { /* Previous pass used a true ray casting approach, but this doesn't get good results. Numerical errors, view stopped by leaves, rays going through cracks. Switching to a line walking approach to acheive stability and simplicity. (And probably performance.) */ #if 0 #ifdef DEBUG { // Max sight const int MAX_SIGHT_SQUARED = MAX_EYESIGHT_RANGE*MAX_EYESIGHT_RANGE; Vector2I vec = pos - origin; int len2 = vec.LengthSquared(); GLASSERT( len2 <= MAX_SIGHT_SQUARED ); if ( len2 > MAX_SIGHT_SQUARED ) return; } #endif #endif const Surface* lightMap = map->GetLightMap(); GLRELASSERT( lightMap->Format() == Surface::RGB16 ); const float OBSCURED = 0.50f; const float DARK = ((units[unitID].Team() == ALIEN_TEAM) ? 1.5f :2.0f) / (float)MAX_EYESIGHT_RANGE; const float LIGHT = 1.0f / (float)MAX_EYESIGHT_RANGE; //const int EPS = 10; float light = 1.0f; bool canSee = true; // Always walk the entire line so that the places we can not see are set // as well as the places we can. LineWalk line( origin.x, origin.y, pos.x, pos.y ); while ( line.CurrentStep() <= line.NumSteps() ) { Vector2I p = line.P(); Vector2I q = line.Q(); Vector2I delta = q-p; if ( canSee ) { canSee = map->CanSee( p, q ); if ( canSee ) { U16 c = lightMap->GetImg16( q.x, q.y ); Color4U8 rgba = Surface::CalcRGB16( c ); const float distance = ( delta.LengthSquared() > 1 ) ? 1.4f : 1.0f; if ( map->Obscured( q.x, q.y ) ) { light -= OBSCURED * distance; } else if ( map->Flared( q.x, q.y ) ) { // Do nothing. Treat as perfect white. } else { // Blue channel is typically high. So // very dark ~255 // very light ~255*3 (white) int lum = rgba.r + rgba.g + rgba.b; float fraction = Interpolate( 255.0f, DARK, 765.0f, LIGHT, (float)lum ); light -= fraction * distance; } } } visibilityProcessed.Set( q.x, q.y ); if ( canSee ) { visibilityMap.Set( q.x, q.y, unitID, true ); } // If all the light is used up, we will see no further. if ( canSee && light < 0.0f ) canSee = false; line.Step(); } }
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); } }
void MapScene::DrawMap() { CDynArray<Chit*> query; const ChitContext* context = lumosChitBag->Context(); const Web& web = lumosChitBag->GetSim()->CalcWeb(); Rectangle2I subBounds = MapBounds2(); float map2X = float(subBounds.min.x) / float(NUM_SECTORS); float map2Y = float(subBounds.min.y) / float(NUM_SECTORS); RenderAtom subAtom = mapImage.GetRenderAtom(); subAtom.tx0 = map2X; subAtom.ty1 = map2Y; subAtom.tx1 = map2X + float(MAP2_SIZE) / float(NUM_SECTORS); subAtom.ty0 = map2Y + float(MAP2_SIZE) / float(NUM_SECTORS); mapImage2.SetAtom(subAtom); for (Rectangle2IIterator it(subBounds); !it.Done(); it.Next()) { Vector2I sector = it.Pos(); const SectorData& sd = worldMap->GetSectorData( sector ); int i = (sector.x - subBounds.min.x); int j = (sector.y - subBounds.min.y); int index = j * MAP2_SIZE + i; CoreScript* coreScript = CoreScript::GetCore(sector); CStr<64> str = ""; const char* owner = ""; if (coreScript) { if ( coreScript->InUse() ) { owner = Team::Instance()->TeamName( coreScript->ParentChit()->Team() ).safe_str(); } } str.Format( "%s\n%s", sd.name.safe_str(), owner ); Rectangle2F r = GridBounds2(i, j, true); gridWidget[index].SetPos(r.min.x, r.min.y); gridWidget[index].SetSize(r.Width(), r.Height()); gridWidget[index].Set(context, coreScript, lumosChitBag->GetHomeCore(), &web); } Vector2I homeSector = lumosChitBag->GetHomeSector(); if ( !data->destSector.IsZero() && data->destSector != homeSector ) { const SectorData& sd = worldMap->GetSectorData( data->destSector ); CStr<64> str; str.Format( "Grid Travel\n%s", sd.name.c_str() ); gridTravel.SetText( str.c_str() ); gridTravel.SetEnabled( true ); } else { gridTravel.SetText( "Grid Travel" ); gridTravel.SetEnabled( false ); } // --- MAIN --- Rectangle2I mapBounds = data->worldMap->Bounds(); Rectangle2I map2Bounds; map2Bounds.Set(subBounds.min.x*SECTOR_SIZE, subBounds.min.y*SECTOR_SIZE, subBounds.max.x*SECTOR_SIZE + SECTOR_SIZE-1, subBounds.max.y*SECTOR_SIZE + SECTOR_SIZE-1); Vector2F playerPos = { 0, 0 }; Chit* player = data->player; if ( player ) { playerPos = ToWorld2F(player->Position()); } const float dx = mapImage.Width() / float(NUM_SECTORS); const float dy = mapImage.Height() / float(NUM_SECTORS); for (int j = 0; j < NUM_SECTORS; ++j) { for (int i = 0; i < NUM_SECTORS; ++i) { diplomacy[j*NUM_SECTORS + i].SetSize(dx, dy); diplomacy[j*NUM_SECTORS + i].SetPos(mapImage.X() + dx * float(i), mapImage.Y() + dy * float(j)); } } bool inBounds = true; Vector2F v; for (int i = 0; i < 2; ++i) { const Rectangle2I& b = (i == 0) ? mapBounds : map2Bounds; v = ToUI(i, playerPos, b, &inBounds); playerMark[i].SetCenterPos(v.x, v.y); playerMark[i].SetVisible(inBounds); Vector2F pos = { float(homeSector.x * SECTOR_SIZE), float(homeSector.y * SECTOR_SIZE) }; v = ToUI(i,pos, b, &inBounds); homeMark[i].SetPos(v.x, v.y); homeMark[i].SetVisible(inBounds && !homeSector.IsZero()); pos.Set(float(data->destSector.x * SECTOR_SIZE), float(data->destSector.y * SECTOR_SIZE)); v = ToUI(i,pos, b, &inBounds); // if (i == 0) { // travelMark.SetPos(v.x, v.y); // travelMark.SetVisible(inBounds && !data->destSector.IsZero()); // } for (int k = 0; k < MAX_SQUADS; ++k) { v = ToUI(i, ToWorld2F(data->squadDest[k]), b, &inBounds); squadMark[i][k].SetCenterPos(v.x, v.y); squadMark[i][k].SetVisible(!data->squadDest[k].IsZero() && inBounds); } } { Vector2F world = { (float)map2Bounds.min.x, (float)map2Bounds.min.y }; Vector2F pos = ToUI(0, world, mapBounds, 0); selectionMark.SetPos(pos.x, pos.y); } float scale = float(mapImage.Width()) / float(NUM_SECTORS); { webCanvas.Clear(); for (int i = 1; i < web.NumNodes(); i++) { const MinSpanTree::Node& node = web.NodeAt(i); Vector2I s0 = node.parentPos; Vector2I s1 = node.pos; Vector2F p0 = { (float(s0.x) + 0.5f) * scale, (float(s0.y) + 0.5f) * scale }; Vector2F p1 = { (float(s1.x) + 0.5f) * scale, (float(s1.y) + 0.5f) * scale }; webCanvas.DrawLine(p0.x, p0.y, p1.x, p1.y, 1.0f + node.strength * 2.0f); } } CoreScript* homeCore = context->chitBag->GetHomeCore(); CChitArray citizens; if (homeCore) { homeCore->Citizens(&citizens); } for (int i = 0; i < MAX_CITIZENS; ++i) { if (i < citizens.Size()) { Vector2F cPos = ToWorld2F(citizens[i]->Position()); Vector2F pos = ToUI(0, cPos, mapBounds, 0); unitMarker[i].SetSize(8, 8); unitMarker[i].SetCenterPos(pos.x, pos.y); unitMarker[i].SetVisible(true); } else { unitMarker[i].SetVisible(false); } } for (int j = 0; j < NUM_SECTORS; ++j) { for (int i = 0; i < NUM_SECTORS; ++i) { diplomacy[i].SetAtom(RenderAtom()); Vector2I sector = { i, j }; CoreScript* core = CoreScript::GetCore(sector); RenderAtom atom; if (core && homeCore && homeCore->InUse() && core->InUse()) { ERelate relate = Team::Instance()->GetRelationship(core->ParentChit(), homeCore->ParentChit()); if (relate == ERelate::FRIEND) atom = LumosGame::CalcUIIconAtom("friend"); else if (relate == ERelate::NEUTRAL) atom = LumosGame::CalcUIIconAtom("neutral"); else if (relate == ERelate::ENEMY) atom = LumosGame::CalcUIIconAtom("enemy"); diplomacy[j*NUM_SECTORS + i].SetSize(scale*0.8f, scale*0.8f); } if (core && core->InUse() && Team::IsDeity(core->ParentChit()->Team())) { atom = LumosGame::CalcDeityAtom(core->ParentChit()->Team()); diplomacy[j*NUM_SECTORS + i].SetSize(scale, scale); } diplomacy[j*NUM_SECTORS + i].SetAtom(atom); diplomacy[j*NUM_SECTORS + i].SetCenterPos(mapImage.X() + scale * (float(i) + 0.5f), mapImage.Y() + scale * (float(j) + 0.5f)); } } }
bool Map::isSolid(Vector2I v) const { return getTyle(v)->getType()->isSolid(v.getX() % TileType::PIXEL_PER_TILE, v.getY() % TileType::PIXEL_PER_TILE); }