예제 #1
0
void CoreScript::AddTech()
{
	tech += TECH_ADDED_BY_VISITOR;
	tech = Clamp( tech, 0.0, Min( double(TECH_MAX), double( MaxTech() ) - 0.01 ));
	achievement.techLevel = Max(achievement.techLevel, (int)tech);

	int team = ParentChit()->Team();
	int superTeam = Team::Instance()->SuperTeam(team);
	if (team != superTeam) {
		CoreScript* super = CoreScript::GetCoreFromTeam(superTeam);
		if (super) {
			super->AddTech();

			// EXPERIMENTAL: also transfer Au
			Wallet* wallet = parentChit->GetWallet();
			GLASSERT(wallet);
			if (wallet 
				&& super->ParentChit()->GetWallet() 
				&& (wallet->Gold() > (GOLD_XFER_TAKEOVER *3/2))) 
			{
				int gold = GOLD_XFER_TAKEOVER / 10;
				super->ParentChit()->GetWallet()->Deposit(wallet, gold);
			}
		}
	}
}
예제 #2
0
Vector2I LumosChitBag::GetHomeSector()	const
{ 
	grinliz::Vector2I v = { 0, 0 };
	CoreScript* home = GetHomeCore();
	if (home && home->ParentChit() ) {
		v = ToSector(home->ParentChit()->Position());
	}
	return v;
}
예제 #3
0
CoreScript* CoreScript::GetCoreFromTeam(int team)
{
	if (!teamToCoreInfo)
		return 0;	// happens on tear down
	if (team == 0)
		return 0;

	int index = 0;
	if (teamToCoreInfo->Query(team, &index)) {
		// Make sure it is current:
		GLASSERT(index >= 0 && index < NUM_SECTORS*NUM_SECTORS);
		CoreScript* cs = coreInfoArr[index].coreScript;
//		GLASSERT(cs);	// cores get destroyed at odd times.
		if (cs && cs->ParentChit()->Team() == team) {
			return cs;
		}
	}

	for (int i = 0; i < NUM_SECTORS*NUM_SECTORS; ++i) {
		if (coreInfoArr[i].coreScript && coreInfoArr[i].coreScript->ParentChit()->Team() == team) {
			teamToCoreInfo->Add(team, i);
			return coreInfoArr[i].coreScript;
		}
	}
	return 0;
}
예제 #4
0
void CoreScript::OnChitMsg(Chit* chit, const ChitMsg& msg)
{
	// Logic split between Sim::OnChitMsg and CoreScript::OnChitMsg
	if (msg.ID() == ChitMsg::CHIT_DESTROYED && (chit == parentChit)) {
		while (!citizens.Empty()) {
			int citizenID = citizens.Pop();
			Chit* citizen = Context()->chitBag->GetChit(citizenID);
			if (citizen && citizen->GetItem()) {
				// Set to rogue team.
				citizen->GetItem()->SetRogue();
			}
		}

		Vector2I pos2i = ToWorld2I(chit->Position());
		Vector2I sector = ToSector(pos2i);

		if (Team::Instance()->IsController(chit->Team())) {
			NewsEvent news(NewsEvent::SUPERTEAM_DELETED, ToWorld2F(pos2i), chit->GetItemID(), 0);
			Context()->chitBag->GetNewsHistory()->Add(news);
		}
		int controllerTeam = 0;
		if (Team::Instance()->IsControlled(chit->Team(), &controllerTeam)) {
			CoreScript* controller = CoreScript::GetCoreFromTeam(controllerTeam);
			GLASSERT(controller);
			if (controller) {
				NewsEvent news(NewsEvent::SUBTEAM_DELETED, ToWorld2F(pos2i), chit->GetItemID(), controller->ParentChit()->GetItemID());
				Context()->chitBag->GetNewsHistory()->Add(news);
			}
		}

		int deleterID = chit->GetItemComponent() ? chit->GetItemComponent()->LastDamageID() : 0;
		Chit* deleter = Context()->chitBag->GetChit(deleterID);
		int superTeam = 0;
		if (deleter
			&& (deleter->Team() == Team::Instance()->SuperTeam(deleter->Team()))
			&& Team::IsDenizen(deleter->Team())
			&& Team::IsDenizen(chit->Team()))
		{
			superTeam = deleter->Team();
		}

		if (chit->Team() != TEAM_NEUTRAL) {
			if (superTeam) {
				LumosChitBag::CreateCoreData data = { sector, true, chit->Team(), deleter ? deleter->Team() : 0 };
				Context()->chitBag->coreCreateList.Push(data);
			}
			else {
				LumosChitBag::CreateCoreData data = { sector, false, chit->Team(), deleter ? deleter->Team() : 0 };
				Context()->chitBag->coreCreateList.Push(data);
			}
		}
		else {
			// Neutral cores are taken over by wandering over them
			// with enough friend units to have critical mass.
			LumosChitBag::CreateCoreData data = { sector, false, 0, 0 };
			Context()->chitBag->coreCreateList.Push(data);
		}
		Team::Instance()->CoreDestroyed(parentChit->Team());
	}
}
예제 #5
0
void MapScene::EnableButtons()
{
	Vector2I v = data->destSector;
	CoreScript* cs = CoreScript::GetCore(v);
	CoreScript* homeCore = lumosChitBag->GetHomeCore();

	if (!homeCore) {
		warButton.SetEnabled(false);
		peaceButton.SetEnabled(false);
		peaceButton.SetText("Peace Treaty");
		return;
	}

	warButton.SetEnabled(Team::Instance()->War(cs, homeCore, false, &lumosChitBag->GetSim()->GetCachedWeb()));
	int peace = Team::Instance()->Peace(cs, homeCore, false, &lumosChitBag->GetSim()->GetCachedWeb());
	const Wallet* wallet = homeCore->ParentChit()->GetWallet();

	if (peace > 0 && wallet->HasGold(peace)) {
		CStr<64> str;
		str.Format("Peace Treaty %d Au", peace);
		peaceButton.SetEnabled(true);
		peaceButton.SetText(str.c_str());
	}
	else {
		peaceButton.SetEnabled(false);
		peaceButton.SetText("Peace Treaty");
	}
}
예제 #6
0
Chit* LumosChitBag::QueryRemovable( const grinliz::Vector2I& pos2i )
{
	Vector2F pos2 = { (float)pos2i.x+0.5f, (float)pos2i.y+0.5f };

	CChitArray		array;
	RemovableFilter removableFilter;

	Chit* core = 0;
	CoreScript* cs = CoreScript::GetCore(ToSector(pos2i));
	if (cs) core = cs->ParentChit();


	// Big enough to snag buildings:
	QuerySpatialHash(&array, pos2, 0.8f, core, &removableFilter);

	Chit* found = 0;
	// 1x1 buildings.
	for( int i=0; i<array.Size(); ++i ) {
		// We are casting a wide net to get buildings.
		if (array[i]->Bounds().Contains(pos2i)) {
			found = array[i];
			break;
		}
	}
	return found;
}
예제 #7
0
Chit* LumosChitBag::NewVisitor( int visitorIndex, const Web& web)
{
	const ChitContext* context = Context();
	if (web.Empty()) return 0;

	Vector2I startSector = { NUM_SECTORS / 2, NUM_SECTORS / 2 };
	CoreScript* cs = CoreScript::GetCore(startSector);
	if (!cs) return 0;	// cores get deleted, web is cached, etc.
	Vector3F pos = cs->ParentChit()->Position();

	Chit* chit = NewChit();
	const GameItem& rootItem = ItemDefDB::Instance()->Get( "visitor" );

	chit->Add( new RenderComponent( rootItem.ResourceName() ));

	AIComponent* ai = new AIComponent();
	chit->Add( ai );
	GLASSERT( visitorIndex >= 0 && visitorIndex < Visitors::NUM_VISITORS );
	ai->SetVisitorIndex( visitorIndex );
	Visitors::Instance()->visitorData[visitorIndex].Connect();	// initialize.

	// Visitors start at world center, with gridMove, and go from there.
	chit->SetPosition( pos );

	PathMoveComponent* pmc = new PathMoveComponent();
	chit->Add(pmc);

	AddItem( rootItem.Name(), chit, context->engine, TEAM_VISITOR, 0 );
	chit->Add( new HealthComponent());
	//chit->Add( new VisitorStateComponent());
	return chit;
}
예제 #8
0
void LumosChitBag::DoTick(U32 delta)
{
	// From the CHIT_DESTROYED_START we have a list of
	// Cores that will be going away...check them here,
	// so that we replace as soon as possible.
	while (!coreCreateList.Empty()) {
		CreateCoreData data = coreCreateList.Pop();
		CoreScript* sc = CoreScript::GetCore(data.sector);
		Vector2I sector = data.sector;
		CoreScript* conqueringCore = CoreScript::GetCoreFromTeam(data.conqueringTeam);

		if (!sc) {
			// FIXME: last criteria "must be super team" isn't correct. Sub-teams
			// should be able to conquor for super teams.

			if (data.wantsTakeover
				&& data.conqueringTeam
				&& conqueringCore
				&& Team::IsDenizen(data.conqueringTeam)
				&& (Team::Instance()->SuperTeam(data.conqueringTeam) == data.conqueringTeam))
			{
				TakeOverCore(sector, conqueringCore->ParentChit());
			}
			else {
				CoreScript::CreateCore(sector, TEAM_NEUTRAL, Context());
			}
		}
	}
	super::DoTick(delta);
}
예제 #9
0
void MapScene::ItemTapped(const gamui::UIItem* item)
{
	Vector2I sector = { 0, 0 };
	Vector2I v = data->destSector;
	CoreScript* cs = CoreScript::GetCore(v);
	CoreScript* homeCore = lumosChitBag->GetHomeCore();

	if (item == &okay) {
		data->destSector.Zero();
		lumosGame->PopScene();
	}
	else if (item == &gridTravel) {
		lumosGame->PopScene();
	}
	else if (item == &viewButton) {
		data->view = true;
		lumosGame->PopScene();
	}
	else if (item == &mapImage) {
		float x = 0, y = 0;
		gamui2D.GetRelativeTap(&x, &y);
		sector.x = int(x * float(NUM_SECTORS));
		sector.y = int(y * float(NUM_SECTORS));
		data->destSector = sector;
		DrawMap();
		EnableButtons();
	}
	else if (item == &mapImage2) {
		float x = 0, y = 0;
		gamui2D.GetRelativeTap(&x, &y);
		Rectangle2I b = MapBounds2();
		sector.x = b.min.x + int(x * float(b.Width()));
		sector.y = b.min.y + int(y * float(b.Height()));
		data->destSector = sector;
		DrawMap();
		EnableButtons();
	}
	else if (item == &warButton) {
		Team::Instance()->War(cs, homeCore, true, &lumosChitBag->GetSim()->GetCachedWeb());
		DrawMap();
		EnableButtons();
	}
	else if (item == &peaceButton) {
		int cost = Team::Instance()->Peace(cs, homeCore, false, &lumosChitBag->GetSim()->GetCachedWeb());
		Wallet* wallet = homeCore->ParentChit()->GetWallet();
		if (wallet->HasGold(cost)) {
			ReserveBank::Instance()->GetWallet()->Deposit(wallet, cost);
			Team::Instance()->Peace(cs, homeCore, true, &lumosChitBag->GetSim()->GetCachedWeb());
			DrawMap();
			EnableButtons();
		}
	}
}
예제 #10
0
void Web::Calc(const Vector2I* exclude)
{
	static Vector2I origin = { NUM_SECTORS / 2, NUM_SECTORS / 2 };
	CArray<Vector2I, NUM_SECTORS * NUM_SECTORS> cores;
	cores.Push(origin);

	int n = 0;
	CoreScript** list = CoreScript::GetCoreList(&n);
	for (int i = 0; i < n; ++i) {
		CoreScript* cs = list[i];
		Vector2I sector = ToSector(cs->ParentChit()->Position());
		if (    (sector != origin) && cs && cs->InUse() 
			 && Team::Instance()->GetRelationship(cs->ParentChit()->Team(), TEAM_VISITOR) != ERelate::ENEMY) 
		{
			GLASSERT(cores.HasCap());
			if (!exclude || (*exclude != sector)) {
				cores.Push(sector);
			}
		}
	}
	tree.Calc(cores.Mem(), cores.Size());
}
예제 #11
0
int MapSpatialComponent::DoTick(U32 delta)
{
	if (slowTick.Delta(delta)) {
		CoreScript* cs = CoreScript::GetCore(ToSector(parentChit->Position()));
		glowTarget = 0;

		if (needsCorePower) {
			if (cs && cs->InUse()) {
				Rectangle2I porch = this->PorchPos();
				if (porch.min.IsZero()) {
					// No porch. Just need core.
					glowTarget = 1;
				}
				else {
					Vector2F start = ToWorld2F(porch.min);
					Vector2F end = ToWorld2F(cs->ParentChit()->Position());
					if (Context()->worldMap->CalcPath(start, end, 0, 0, false)) {
						glowTarget = 1;
					}
				}
			}
		}
		else {
			glowTarget = 1;
			glow = 1;
		}
	}

	if (glow != glowTarget) {
		glow = TravelTo(0.7f, delta, glow, glowTarget);
	}
	if (parentChit->GetItem() && parentChit->GetItem()->IName() == ISC::core) {
		glow = glowTarget = 1;
	}

	RenderComponent* rc = parentChit->GetRenderComponent();
	if (rc) {
		const GameItem* gameItem = parentChit->GetItem();
		if (gameItem && gameItem->keyValues.GetIString(ISC::procedural) == ISC::team) {
//			int team = parentChit->Team();
			ProcRenderInfo info;
			AssignProcedural(parentChit->GetItem(), &info);
			info.color.X(Matrix4::M41) *= glow;
			info.color.X(Matrix4::M42) *= glow;
			info.color.X(Matrix4::M43) *= glow;
			rc->SetProcedural(0, info);
			rc->SetSaturation(0.5f + 0.5f*glow);
		}
	}
	return VERY_LONG_TICK;
}
예제 #12
0
CoreScript* LumosChitBag::TakeOverCore(const Vector2I& sector, Chit* conquerer)
{
	int conqueringTeam = conquerer->Team();
	int teamID = Team::Instance()->GenTeam(Team::Group(conqueringTeam));
	bool isSubDomain = !Team::IsRogue(conqueringTeam);

	if (isSubDomain) {
		Team::Instance()->AddSubteam(conqueringTeam, teamID);
	}
	CoreScript* newCore = CoreScript::CreateCore(sector, teamID, Context());
	GLASSERT(CoreScript::GetCore(sector) == newCore);
	newCore->ParentChit()->Add(DomainAI::Factory(teamID));

	CDynArray<Chit*> arr;
	// After takeover, all the citizens are rogue and buildings are neutral.
	// As a first pass, simply takeover everything that meets that criteria.

	ChitAcceptAll filter;
	BuildingFilter buildingFilter;
	Context()->chitBag->QuerySpatialHash(&arr, InnerSectorBounds(sector), 0, &filter);

	for (Chit* c : arr) {
		if (c->PlayerControlled()) 
			continue;
		GameItem* mainItem = c->GetItem();
		if (!mainItem) 
			continue;

		if (mainItem->IsDenizen() && Team::IsRogue(mainItem->Team())) {
			newCore->AddCitizen(c);
		}
		else if (buildingFilter.Accept(c) && mainItem->IName() != ISC::core) {
			c->GetItem()->SetTeam(teamID);
		}
	}
	// Finally, give this new core a chance. 
	// Transfer money from Conquering domain.
	CoreScript* conqueringCore = CoreScript::GetCoreFromTeam(conquerer->Team());
	if (conqueringCore) {
		int gold = conqueringCore->ParentChit()->GetWallet()->Gold() / 4;
		gold = Min(gold, GOLD_XFER_TAKEOVER);
		newCore->ParentChit()->GetWallet()->Deposit(conqueringCore->ParentChit()->GetWallet(), gold);
	}

	NewsEvent news(isSubDomain ? NewsEvent::DOMAIN_CONQUER : NewsEvent::DOMAIN_TAKEOVER,
				   ToWorld2F(newCore->ParentChit()->Position()),
				   newCore->ParentChit()->GetItemID(),
				   conquerer->GetItemID());
	Context()->chitBag->GetNewsHistory()->Add(news);

	return newCore;
}
예제 #13
0
int RebuildAIComponent::DoTick(U32 delta)
{
	GameItem* mainItem = parentChit->GetItem();
	Vector2I sector = ToSector(parentChit->Position());
	CoreScript* cs = CoreScript::GetCore(sector);

	if (ticker.Delta(delta) && mainItem && cs) {

		// Create workers, if needed.
		Rectangle2F b = ToWorld2F(InnerSectorBounds(sector));
		CChitArray arr;
		ItemNameFilter workerFilter(ISC::worker);
		Context()->chitBag->QuerySpatialHash(&arr, b, 0, &workerFilter);
		if (arr.Empty()) {
			if (mainItem->wallet.Gold() >= WORKER_BOT_COST) {
				ReserveBank::GetWallet()->Deposit(&mainItem->wallet, WORKER_BOT_COST);
				Context()->chitBag->NewWorkerChit(cs->ParentChit()->Position(), parentChit->Team());
			}
		}

		// Pull a task off the queue and send a worker out.
		if (workItems.Size()) {
			WorkQueue* workQueue = cs->GetWorkQueue();
			if (workQueue) {
				WorkItem wi = workItems.Pop();
				BuildScript buildScript;
				int id = 0;
				buildScript.GetDataFromStructure(wi.structure, &id);
				if (workQueue->AddAction(wi.pos, id, float(wi.rot), 0)) {
					GLOUTPUT(("ReBuild: Structure %s at %d,%d r=%d POP to work queue.\n", wi.structure.safe_str(), wi.pos.x, wi.pos.y, int(wi.rot)));
				}
				else {
					GLOUTPUT(("ReBuild: Re-Push structure %s at %d,%d to work queue.\n", wi.structure.safe_str(), wi.pos.x, wi.pos.y));
					workItems.Push(wi);
				}
			}
		}
	}
	return ticker.Next();
}
예제 #14
0
CoreScript* CoreScript::CreateCore( const Vector2I& sector, int team, const ChitContext* context)
{
	// Destroy the existing core.
	// Create a new core, attached to the player.
	CoreScript* cs = CoreScript::GetCore(sector);
	if (cs) {
		Chit* core = cs->ParentChit();
		GLASSERT(core);

		CDynArray< Chit* > queryArr;

		// Tell all the AIs the core is going away.
		ChitHasAIComponent filter;
		Rectangle2F b = ToWorld2F(InnerSectorBounds(sector));
		context->chitBag->QuerySpatialHash(&queryArr, b, 0, &filter);
		for (int i = 0; i < queryArr.Size(); ++i) {
			queryArr[i]->GetAIComponent()->ClearTaskList();
		}

		//context.chitBag->QueueDelete(core);
		// QueueDelete is safer, but all kinds of asserts fire (correctly)
		// if 2 cores are in the same place. This may cause an issue
		// if CreateCore is called during the DoTick()
		// Setting the hp to 0 and then calling DoTick()
		// is a sleazy trick to clean up.
		core->GetItem()->hp = 0;
		if (core->GetHealthComponent()) {
			core->GetHealthComponent()->DoTick(1);
		}
		context->chitBag->DeleteChit(core);
	}

	const SectorData& sd = context->worldMap->GetSectorData(sector);
	if (sd.HasCore()) {
		int group = 0, id = 0;
		Team::SplitID(team, &group, &id);

		// Lots of trouble with this code. Used to assert,
		// but always seemed to be another case. White list
		// groups that *can* take over a core.
		if (team == TEAM_NEUTRAL || team == TEAM_TROLL || Team::IsDeity(team) || Team::IsDenizen(team)) {
			// Okay! take over.
			GLASSERT(!Team::IsDenizen(team) || id);		// make sure rogues got filtered out.
		}
		else {
			team = group = id = 0;
		}
		Chit* chit = context->chitBag->NewBuilding(sd.core, "core", team);

		// 'in use' instead of blocking.
		MapSpatialComponent* ms = GET_SUB_COMPONENT(chit, SpatialComponent, MapSpatialComponent);
		GLASSERT(ms);
		ms->SetBlocks(false);
		
		CoreScript* cs = new CoreScript();
		chit->Add(cs);
		GLASSERT(CoreScript::GetCore(ToSector(sd.core)) == cs);

		if (Team::IsDeity(team))
			chit->GetItem()->SetProperName(Team::Instance()->TeamName(team));
		else
			chit->GetItem()->SetProperName(sd.name);

		if (team != TEAM_NEUTRAL) {
			chit->GetItem()->SetSignificant(context->chitBag->GetNewsHistory(), 
											ToWorld2F(chit->Position()), 
											NewsEvent::DOMAIN_CREATED, NewsEvent::DOMAIN_DESTROYED, 0);


			// Make the dwellers defend the core.
			chit->Add(new GuardScript());

			// Make all buildings to be this team.
			CDynArray<Chit*> buildings;
			Vector2I buildingSector = ToSector(chit->Position());
			context->chitBag->FindBuilding(IString(), buildingSector, 0, LumosChitBag::EFindMode::NEAREST, &buildings, 0);
			
			for (int i = 0; i < buildings.Size(); ++i) {
				Chit* c = buildings[i];
				if (c->GetItem() && c->GetItem()->IName() != ISC::core) {
					c->GetItem()->SetTeam(team);
				}
			}
		}
		return cs;
	}
	return 0;
}
예제 #15
0
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);
	}
}
예제 #16
0
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));
		}
	}
}