ALERROR CGroupOfGenerators::LoadFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc) // LoadFromXML // // Load from XML { int i; ALERROR error; // Load content elements m_Table.InsertEmpty(pDesc->GetContentElementCount()); for (i = 0; i < m_Table.GetCount(); i++) { CXMLElement *pEntry = pDesc->GetContentElement(i); m_Table[i].iChance = pEntry->GetAttributeInteger(CHANCE_ATTRIB); if (m_Table[i].iChance == 0) m_Table[i].iChance = 100; CString sCount = pEntry->GetAttribute(COUNT_ATTRIB); if (sCount.IsBlank()) m_Table[i].Count = DiceRange(0, 0, 1); else m_Table[i].Count.LoadFromXML(sCount); if (error = IItemGenerator::CreateFromXML(Ctx, pEntry, &m_Table[i].pItem)) return error; } // See if we force an average value CString sAttrib; if (pDesc->FindAttribute(LEVEL_VALUE_ATTRIB, &sAttrib)) { TArray<int> Values; ParseIntegerList(sAttrib, 0, &Values); m_AverageValue.InsertEmpty(MAX_ITEM_LEVEL + 1); m_AverageValue[0] = 0; for (i = 0; i < Values.GetCount(); i++) m_AverageValue[i + 1] = Values[i]; for (i = Values.GetCount() + 1; i <= MAX_ITEM_LEVEL; i++) m_AverageValue[i] = 0; } else if (pDesc->FindAttribute(VALUE_ATTRIB, &sAttrib)) { int iValue = strToInt(sAttrib, 0); m_AverageValue.InsertEmpty(MAX_ITEM_LEVEL + 1); m_AverageValue[0] = 0; for (i = 1; i <= MAX_ITEM_LEVEL; i++) m_AverageValue[i] = iValue; } return NOERROR; }
CTopologyNode *CConquerNodesProc::ChooseRandomNode (CTopologyNodeList &NodeList, TArray<SNodeWeight> &Weights) // ChooseRandomNode // // Chooses a random node from the list, using Weights as a descriminator { int i; // Generate a weight for each node TArray<int> Chance; TArray<int> Success; Chance.InsertEmpty(NodeList.GetCount()); Success.InsertEmpty(NodeList.GetCount()); int iTotalChance = 0; for (i = 0; i < NodeList.GetCount(); i++) if (NodeList[i]->IsMarked()) { Chance[i] = CalcNodeWeight(NodeList[i], Weights, &Success[i]); iTotalChance += Chance[i]; } else Chance[i] = 0; // If nothing left, return if (iTotalChance == 0) return NULL; // Pick a random node int iRoll = mathRandom(1, iTotalChance); for (i = 0; i < Chance.GetCount(); i++) { if (iRoll <= Chance[i]) { if (mathRandom(1, 100) <= Success[i]) return NodeList[i]; else return NULL; } else iRoll -= Chance[i]; } ASSERT(false); return NULL; }
void CGameSession::PaintSoundtrackTitles (CG32bitImage &Dest) // PaintSoundtrackTitles // // Paints the info about the currently playing soundtrack. { int iPos; CMusicResource *pTrack = m_Soundtrack.GetCurrentTrack(&iPos); if (pTrack == NULL) return; int iSegment = pTrack->FindSegment(iPos); // Time int iMilliseconds = iPos % 1000; int iSeconds = (iPos / 1000) % 60; int iMinutes = (iPos / 60000); // Add all the components TArray<CString> Desc; Desc.InsertEmpty(3); Desc[0] = pTrack->GetPerformedBy(); Desc[1] = pTrack->GetFilename(); Desc[2] = strPatternSubst(CONSTLIT("Segment %d of %d [%02d:%02d.%03d]"), iSegment + 1, pTrack->GetSegmentCount(), iMinutes, iSeconds, iMilliseconds); // Paint PaintInfoText(Dest, pTrack->GetTitle(), Desc, true); }
ALERROR CCompositeEntry::InitFromXML (SDesignLoadCtx &Ctx, CIDCounter &IDGen, CXMLElement *pDesc) // InitFromXML // // Initialize from XML { ALERROR error; int i; m_dwID = IDGen.GetID(); // Load each sub-entry in turn int iCount = pDesc->GetContentElementCount(); if (iCount == 0) return NOERROR; m_Layers.InsertEmpty(iCount); for (i = 0; i < iCount; i++) { if (error = CCompositeImageDesc::InitEntryFromXML(Ctx, pDesc->GetContentElement(i), IDGen, &m_Layers[i])) return error; } // Done return NOERROR; }
TArray<CString> CDatum::AsStringArray (void) const // AsStringArray // // Coerces to an array of strings. { int i; TArray<CString> Result; Result.InsertEmpty(GetCount()); for (i = 0; i < GetCount(); i++) Result[i] = GetElement(i).AsString(); return Result; }
ALERROR CLocationCriteriaTableEntry::InitFromXML (SDesignLoadCtx &Ctx, CIDCounter &IDGen, CXMLElement *pDesc) // InitFromXML // // Initialize from XML { ALERROR error; int i; m_dwID = IDGen.GetID(); m_iDefault = -1; // Load each sub-entry in turn int iCount = pDesc->GetContentElementCount(); if (iCount == 0) return NOERROR; m_Table.InsertEmpty(iCount); for (i = 0; i < iCount; i++) { CXMLElement *pItem = pDesc->GetContentElement(i); if (error = CCompositeImageDesc::InitEntryFromXML(Ctx, pItem, IDGen, &m_Table[i].pImage)) return error; // Load the criteria CString sCriteria = pItem->GetAttribute(CRITERIA_ATTRIB); if (error = m_Table[i].Criteria.Parse(sCriteria, 0, &Ctx.sError)) return error; if (m_iDefault == -1 && m_Table[i].Criteria.MatchesDefault()) m_iDefault = i; } // If we don't have a default, the pick the last item. if (m_iDefault == -1 && m_Table.GetCount() > 0) m_iDefault = m_Table.GetCount() - 1; // Done return NOERROR; }
void CIntGraph::AddGraph (CIntGraph &Source) // AddGraph // // Adds the source graph to this graph { int i; // Keep a map between source ID and dest ID TArray<DWORD> SourceToDest; SourceToDest.InsertEmpty(Source.m_Nodes.GetCount()); for (i = 0; i < Source.m_Nodes.GetCount(); i++) { SNode *pNode = Source.GetNode(i); if (!NodeIsFree(pNode)) { // Add node to destination DWORD dwNewID; AddNode(pNode->x, pNode->y, &dwNewID); // Add a mapping SourceToDest[i] = dwNewID; } } // Now add the connections between nodes for (i = 0; i < Source.m_Nodes.GetCount(); i++) { SNode *pNode = Source.GetNode(i); if (!NodeIsFree(pNode)) { SConnection *pConnection = Source.GetForwardConnection(pNode); while (pConnection) { Connect(SourceToDest[i], SourceToDest[pConnection->iTo]); pConnection = Source.GetNextConnection(pConnection); } } } }
ALERROR CTableOfGenerators::LoadFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc) // LoadFromXML // // Load from XML { int i; ALERROR error; m_iTotalChance = 0; int iCount = pDesc->GetContentElementCount(); if (iCount > 0) { m_Table.InsertEmpty(iCount); // Pre-initialize to NULL in case we exit with an error for (i = 0; i < iCount; i++) m_Table[i].pItem = NULL; // Load for (i = 0; i < iCount; i++) { CXMLElement *pEntry = pDesc->GetContentElement(i); m_Table[i].iChance = pEntry->GetAttributeInteger(CHANCE_ATTRIB); m_iTotalChance += m_Table[i].iChance; CString sCount = pEntry->GetAttribute(COUNT_ATTRIB); if (sCount.IsBlank()) m_Table[i].Count = DiceRange(0, 0, 1); else m_Table[i].Count.LoadFromXML(sCount); if (error = IItemGenerator::CreateFromXML(Ctx, pEntry, &m_Table[i].pItem)) return error; } } return NOERROR; }
ALERROR CTableEntry::InitFromXML (SDesignLoadCtx &Ctx, CIDCounter &IDGen, CXMLElement *pDesc) // InitFromXML // // Initialize from XML { ALERROR error; int i; m_dwID = IDGen.GetID(); // Load each sub-entry in turn int iCount = pDesc->GetContentElementCount(); if (iCount == 0) return NOERROR; m_iTotalChance = 0; m_Table.InsertEmpty(iCount); for (i = 0; i < iCount; i++) { CXMLElement *pItem = pDesc->GetContentElement(i); if (error = CCompositeImageDesc::InitEntryFromXML(Ctx, pItem, IDGen, &m_Table[i].pImage)) return error; // Load the chance m_Table[i].iChance = pItem->GetAttributeIntegerBounded(CHANCE_ATTRIB, 0, -1, 1); m_iTotalChance += m_Table[i].iChance; } // Done return NOERROR; }
ALERROR CTableOfDeviceGenerators::LoadFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc) // LoadFromXML // // Load from XML { int i; ALERROR error; m_Count.LoadFromXML(pDesc->GetAttribute(COUNT_ATTRIB)); if (m_Count.IsEmpty()) m_Count.SetConstant(1); m_iTotalChance = 0; int iCount = pDesc->GetContentElementCount(); if (iCount > 0) { m_Table.InsertEmpty(iCount); for (i = 0; i < iCount; i++) { CXMLElement *pEntry = pDesc->GetContentElement(i); m_Table[i].iChance = pEntry->GetAttributeInteger(CHANCE_ATTRIB); m_iTotalChance += m_Table[i].iChance; if (error = IDeviceGenerator::CreateFromXML(Ctx, pEntry, &m_Table[i].pDevice)) { m_Table[i].pDevice = NULL; return error; } } } return NOERROR; }
ALERROR CGroupOfGenerators::OnDesignLoadComplete (SDesignLoadCtx &Ctx) // OnDesignLoadComplete // // Resolve references { int i; ALERROR error; for (i = 0; i < m_Table.GetCount(); i++) { if (error = m_Table[i].pItem->OnDesignLoadComplete(Ctx)) return error; } // Initialize count adjustment m_CountAdj.InsertEmpty(m_AverageValue.GetCount()); for (i = 0; i < m_AverageValue.GetCount(); i++) m_CountAdj[i] = -1.0; return NOERROR; }
void CMnemosynthDb::GenerateDelta (TArray<SMnemosynthUpdate> *retUpdates, CDatum *retdLocalUpdates) // GenerateDelta // // Generates a list of changes since the last time we called this { CSmartLock Lock(m_cs); int i, j; // Edge conditions if (m_Endpoints.GetCount() == 0) { *retdLocalUpdates = CDatum(); return; } // If we are not the central module, then we only need to // generate a list of updates made by our own endpoint // (and send it to our central module). if (!m_pProcess->IsCentralModule()) { if (GetLocalEndpoint().dwSeqRecv > GetLocalEndpoint().dwSeqSent) { SMnemosynthUpdate *pUpdate = retUpdates->Insert(); pUpdate->sDestEndpoint = strPattern("%s/CentralModule", m_pProcess->GetMachineName()); // Generate a payload for our updates CComplexArray *pEntries = new CComplexArray; for (i = 0; i < m_Collections.GetCount(); i++) { const CString &sCollection = m_Collections.GetKey(i); SCollection *pCollection = &m_Collections[i]; for (j = 0; j < pCollection->Entries.GetCount(); j++) { SEntry *pEntry = &pCollection->Entries[j]; if (pEntry->dwOwnerID == 0 && pEntry->dwSequence > GetLocalEndpoint().dwSeqSent) { CDatum dEntry = GenerateEntry(i, pCollection->Entries.GetKey(j), pEntry); pEntries->Insert(dEntry); // If this entry is Nil then we can deleted. (We don't // need it as a deletion stub since we just composed // the update. If this message gets lost we need to // resend everything). if (pCollection->Entries.GetValue(j).dValue.IsNil()) { pCollection->Entries.Delete(j); j--; } } } } // Create the payload CComplexStruct *pPayload = new CComplexStruct; pPayload->SetElement(STR_COLLECTIONS, GenerateCollectionsArray()); pPayload->SetElement(STR_ENDPOINT, GetLocalEndpoint().sName); pPayload->SetElement(STR_ENTRIES, CDatum(pEntries)); pPayload->SetElement(FIELD_PROCESS_ID, CDatum(GetLocalEndpoint().dwProcessID)); // Add it CDatum dLocalUpdates = CDatum(pPayload); pUpdate->Payloads.Insert(dLocalUpdates); // Return it *retdLocalUpdates = dLocalUpdates; } else *retdLocalUpdates = CDatum(); } // Otherwise, loop over all endpoints and generate a different // update entry for each one that we need to handle else { bool bFullUpdateNeeded = false; for (i = 1; i < m_Endpoints.GetCount(); i++) if (m_Endpoints[i].bFullUpdate) { bFullUpdateNeeded = true; break; } // Collections CDatum dCollections = GenerateCollectionsArray(); // We end up creating one or two arrays of deltas. The first // array has all the changes since we last generated a delta // (this is used for endpoints that we updated last time). // // The second array has a full set of data (this is for new // endpoints). TArray<CComplexArray *> UpdateEntries; TArray<CComplexArray *> FullEntries; TArray<CDatum> UpdatePayloads; TArray<CDatum> FullPayloads; UpdateEntries.InsertEmpty(m_Endpoints.GetCount()); UpdatePayloads.InsertEmpty(m_Endpoints.GetCount()); if (bFullUpdateNeeded) { FullEntries.InsertEmpty(m_Endpoints.GetCount()); FullPayloads.InsertEmpty(m_Endpoints.GetCount()); } for (i = 0; i < m_Endpoints.GetCount(); i++) { UpdateEntries[i] = new CComplexArray; CComplexStruct *pStruct = new CComplexStruct; pStruct->SetElement(STR_COLLECTIONS, dCollections); pStruct->SetElement(STR_ENDPOINT, m_Endpoints[i].sName); pStruct->SetElement(STR_ENTRIES, CDatum(UpdateEntries[i])); pStruct->SetElement(FIELD_PROCESS_ID, CDatum(m_Endpoints[i].dwProcessID)); UpdatePayloads[i] = CDatum(pStruct); if (bFullUpdateNeeded) { FullEntries[i] = new CComplexArray; pStruct = new CComplexStruct; pStruct->SetElement(STR_COLLECTIONS, dCollections); pStruct->SetElement(STR_ENDPOINT, m_Endpoints[i].sName); pStruct->SetElement(STR_ENTRIES, CDatum(FullEntries[i])); pStruct->SetElement(FIELD_PROCESS_ID, CDatum(m_Endpoints[i].dwProcessID)); FullPayloads[i] = CDatum(pStruct); } } // Loop over all entries in the database and add them to the // appropriate payload arrays for (i = 0; i < m_Collections.GetCount(); i++) { const CString &sCollection = m_Collections.GetKey(i); SCollection *pCollection = &m_Collections[i]; for (j = 0; j < pCollection->Entries.GetCount(); j++) { SEntry *pEntry = &pCollection->Entries[j]; // Get the endpoint for the owner of this collection int iOwner = FindEndpointIndex(pEntry->dwOwnerID); if (iOwner == -1) continue; // Add to the update array if (pEntry->dwSequence > m_Endpoints[iOwner].dwSeqSent) { CDatum dEntry = GenerateEntry(i, pCollection->Entries.GetKey(j), pEntry); UpdateEntries[iOwner]->Insert(dEntry); #ifdef DEBUG_MNEMOSYNTH printf("[CMnemosynthDb::GenerateDelta]: Endpoint %s %x\n", (LPSTR)m_Endpoints[iOwner].sName, m_Endpoints[iOwner].dwSeqSent); #endif } // Add to full array, if necessary if (bFullUpdateNeeded) { // Don't bother inserting Nil entries (since this is a full // update). if (!pEntry->dValue.IsNil()) { CDatum dEntry = GenerateEntry(i, pCollection->Entries.GetKey(j), pEntry); FullEntries[iOwner]->Insert(dEntry); } } // If this entry is Nil then we can deleted. (We don't // need it as a deletion stub since we just composed // the update. If this message gets lost we need to // resend everything). if (pEntry->dValue.IsNil()) { pCollection->Entries.Delete(j); j--; } } } // Now iterate over all destination endpoints for (i = 1; i < m_Endpoints.GetCount(); i++) { SEndpoint *pDestEndpoint = &m_Endpoints[i]; #ifdef DEBUG_MNEMOSYNTH printf("[CMnemosynthDb::GenerateDelta]: Composing for endpoint %s %s%s.\n", (LPSTR)pDestEndpoint->sName, (pDestEndpoint->bCentralModule ? "CentralModule " : ""), (pDestEndpoint->bLocalMachine ? "local" : "")); #endif // If this is a local module, then send it any updates // for everything except itself if (pDestEndpoint->bLocalMachine && !pDestEndpoint->bCentralModule) { SMnemosynthUpdate *pUpdate = NULL; for (j = 0; j < m_Endpoints.GetCount(); j++) if (i != j) { // If we have no update entries, then skip. if (!pDestEndpoint->bFullUpdate && UpdatePayloads[j].GetElement(STR_ENTRIES).GetCount() == 0) continue; // Add an update entry if (pUpdate == NULL) { pUpdate = retUpdates->Insert(); pUpdate->sDestEndpoint = pDestEndpoint->sName; } if (pDestEndpoint->bFullUpdate) pUpdate->Payloads.Insert(FullPayloads[j]); else pUpdate->Payloads.Insert(UpdatePayloads[j]); } } // Otherwise, if this is a foreign central module, then // send it any updates for all local endpoints else if (pDestEndpoint->bCentralModule && !pDestEndpoint->bLocalMachine) { SMnemosynthUpdate *pUpdate = NULL; #ifdef DEBUG_MNEMOSYNTH if (pDestEndpoint->bFullUpdate) printf("[CMnemosynthDb::GenerateDelta]: Composing FULL update for %s\n", (LPSTR)pDestEndpoint->sName); else printf("[CMnemosynthDb::GenerateDelta]: Composing DIFF update for %s\n", (LPSTR)pDestEndpoint->sName); #endif for (j = 0; j < m_Endpoints.GetCount(); j++) if (m_Endpoints[j].bLocalMachine) { // If we have no update entries, then skip. if (!pDestEndpoint->bFullUpdate && UpdatePayloads[j].GetElement(STR_ENTRIES).GetCount() == 0) continue; #ifdef DEBUG_MNEMOSYNTH printf("[CMnemosynthDb::GenerateDelta]: Updates from %s\n", (LPSTR)m_Endpoints[j].sName); #endif // Add an update entry if (pUpdate == NULL) { pUpdate = retUpdates->Insert(); pUpdate->sDestEndpoint = pDestEndpoint->sName; } if (pDestEndpoint->bFullUpdate) pUpdate->Payloads.Insert(FullPayloads[j]); else pUpdate->Payloads.Insert(UpdatePayloads[j]); } } } // Local updates *retdLocalUpdates = UpdatePayloads[0]; } // Reset for (i = 0; i < m_Endpoints.GetCount(); i++) { m_Endpoints[i].dwSeqSent = m_Endpoints[i].dwSeqRecv; m_Endpoints[i].bFullUpdate = false; } m_ModifiedEvent.Reset(); }
void CArchonProcess::CollectGarbage (void) // CollectGarbage // // Collects garbage { CString sTask; try { int i; // Compute how long it's been since we last collected garbage DWORD dwStart = sysGetTickCount(); DWORD dwTimeSinceLastCollection = dwStart - m_dwLastGarbageCollect; // If it has been less than a certain time, then only collect garbage if // all engines are idle. if (dwTimeSinceLastCollection < MAX_GARBAGE_COLLECT_WAIT) { // Check to see if engines are idle bool bEnginesIdle = true; for (i = 0; i < m_Engines.GetCount(); i++) if (!m_Engines[i].pEngine->IsIdle()) { bEnginesIdle = false; break; } // If the engines are busy, then check to see if we have enough // memory to wait some more. if (!bEnginesIdle) { CProcess CurrentProc; CurrentProc.CreateCurrentProcess(); CProcess::SMemoryInfo MemoryInfo; if (!CurrentProc.GetMemoryInfo(&MemoryInfo)) { LogBlackBox(ERR_CANT_GET_MEMORY_INFO); return; } // If we have enough memory, then wait to collect garbage if (MemoryInfo.dwCurrentAlloc < MAX_GARBAGE_COLLECT_MEMORY) return; // Warning that we're running out of memory LogBlackBox(ERR_MEMORY_WARNING); } } // Collect #ifdef DEBUG_GARBAGE_COLLECTION printf("[%s] Collecting garbage.\n", (LPSTR)m_sName); #endif m_dwLastGarbageCollect = dwStart; m_RunEvent.Reset(); m_PauseEvent.Set(); // Keep track of how long each engine takes to pause (for diagnostic // purposes). TArray<DWORD> PauseTime; PauseTime.InsertEmpty(m_Engines.GetCount()); // Some engines still need an explicit call (because they don't have // their own main thread). for (i = 0; i < m_Engines.GetCount(); i++) m_Engines[i].pEngine->SignalPause(); // Wait for the engines to stop for (i = 0; i < m_Engines.GetCount(); i++) { DWORD dwStart = sysGetTickCount(); m_Engines[i].pEngine->WaitForPause(); PauseTime[i] = sysGetTicksElapsed(dwStart); } // Wait for our threads to stop m_EventThread.WaitForPause(); m_ImportThread.WaitForPause(); // Now we ask all engines to mark their data in use for (i = 0; i < m_Engines.GetCount(); i++) { sTask = strPattern("Marking data: %s engine.", m_Engines[i].pEngine->GetName()); m_Engines[i].pEngine->Mark(); } // Now we mark our own structures sTask = STR_MARKING_MNEMOSYNTH; m_MnemosynthDb.Mark(); sTask = STR_MARKING_EVENT_THREAD; m_EventThread.Mark(); sTask = STR_MARKING_IMPORT_THREAD; m_ImportThread.Mark(); // Now we sweep all unused sTask = STR_MARK_AND_SWEEP; DWORD dwSweepStart = sysGetTickCount(); CDatum::MarkAndSweep(); DWORD dwSweepTime = sysGetTickCount() - dwSweepStart; sTask = NULL_STR; // Now we start all engines up again m_PauseEvent.Reset(); m_RunEvent.Set(); // If garbage collection took too long, then we need to log it. DWORD dwTime = sysGetTickCount() - dwStart; if (dwTime >= 500) { // Log each engine that took too long for (i = 0; i < m_Engines.GetCount(); i++) if (PauseTime[i] >= 500) Log(MSG_LOG_INFO, strPattern(STR_ENGINE_PAUSE_TIME, m_Engines[i].pEngine->GetName(), PauseTime[i] / 1000, (PauseTime[i] % 1000) / 10)); // Log overall time Log(MSG_LOG_INFO, strPattern(STR_GARBAGE_COLLECTION, dwTime / 1000, (dwTime % 1000) / 10, dwSweepTime / 1000, (dwSweepTime % 1000) / 10)); } } catch (...) { if (sTask.IsEmpty()) CriticalError(ERR_CRASH_IN_COLLECT_GARBAGE); else CriticalError(strPattern("CRASH: %s", sTask)); } }
void GenerateImageChart (CUniverse &Universe, CXMLElement *pCmdLine) { int i; enum OrderTypes { orderSmallest = 1, orderLargest = 2, orderName = 3, orderLevel = 4, orderSovereign = 5, orderManufacturer = 6, }; // Item criteria bool bHasItemCriteria; CString sCriteria; CItemCriteria ItemCriteria; if (bHasItemCriteria = pCmdLine->FindAttribute(CONSTLIT("itemCriteria"), &sCriteria)) CItem::ParseCriteria(sCriteria, &ItemCriteria); else CItem::InitCriteriaAll(&ItemCriteria); // Get the criteria from the command line. CDesignTypeCriteria Criteria; if (pCmdLine->FindAttribute(CONSTLIT("criteria"), &sCriteria)) { if (CDesignTypeCriteria::ParseCriteria(sCriteria, &Criteria) != NOERROR) { printf("ERROR: Unable to parse criteria.\n"); return; } } else if (bHasItemCriteria) { if (CDesignTypeCriteria::ParseCriteria(CONSTLIT("i"), &Criteria) != NOERROR) { printf("ERROR: Unable to parse criteria.\n"); return; } } else { printf("ERROR: Expected criteria.\n"); return; } bool bAll = pCmdLine->GetAttributeBool(CONSTLIT("all")); // Options bool bTextBoxesOnly = pCmdLine->GetAttributeBool(CONSTLIT("textBoxesOnly")); bool bFieldUNID = pCmdLine->GetAttributeBool(CONSTLIT("unid")); // Figure out what order we want CString sOrder = pCmdLine->GetAttribute(CONSTLIT("sort")); int iOrder; if (strEquals(sOrder, CONSTLIT("smallest"))) iOrder = orderSmallest; else if (strEquals(sOrder, CONSTLIT("largest"))) iOrder = orderLargest; else if (strEquals(sOrder, CONSTLIT("level"))) iOrder = orderLevel; else if (strEquals(sOrder, CONSTLIT("sovereign"))) iOrder = orderSovereign; else if (strEquals(sOrder, CONSTLIT("manufacturer"))) iOrder = orderManufacturer; else iOrder = orderName; bool b3DGrid = pCmdLine->GetAttributeBool(CONSTLIT("3DGrid")); bool bDockingPorts = pCmdLine->GetAttributeBool(CONSTLIT("portPos")); bool bDevicePos = pCmdLine->GetAttributeBool(CONSTLIT("devicePos")); // Image size int cxDesiredWidth; if (pCmdLine->FindAttributeInteger(CONSTLIT("width"), &cxDesiredWidth)) cxDesiredWidth = Max(512, cxDesiredWidth); else cxDesiredWidth = 1280; // Spacing int cxSpacing = pCmdLine->GetAttributeInteger(CONSTLIT("xSpacing")); int cxExtraMargin = pCmdLine->GetAttributeInteger(CONSTLIT("xMargin")); int cxImageMargin = 2 * pCmdLine->GetAttributeInteger(CONSTLIT("xImageMargin")); // Font for text CString sTypeface; int iSize; bool bBold; bool bItalic; if (!CG16bitFont::ParseFontDesc(pCmdLine->GetAttribute(CONSTLIT("font")), &sTypeface, &iSize, &bBold, &bItalic)) { sTypeface = CONSTLIT("Arial"); iSize = 10; bBold = false; bItalic = false; } CG16bitFont NameFont; NameFont.Create(sTypeface, -PointsToPixels(iSize), bBold, bItalic); CG32bitPixel rgbNameColor = CG32bitPixel(255, 255, 255); // Rotation int iRotation = pCmdLine->GetAttributeInteger(CONSTLIT("rotation")); // Output file CString sFilespec = pCmdLine->GetAttribute(CONSTLIT("output")); if (!sFilespec.IsBlank()) sFilespec = pathAddExtensionIfNecessary(sFilespec, CONSTLIT(".bmp")); // Generate a sorted table of types TSortMap<CString, SEntryDesc> Table; for (i = 0; i < Universe.GetDesignTypeCount(); i++) { CDesignType *pType = Universe.GetDesignType(i); SEntryDesc NewEntry; // Make sure we match the criteria if (!pType->MatchesCriteria(Criteria)) continue; // Figure stuff stuff out based on the specific design type switch (pType->GetType()) { case designItemType: { CItemType *pItemType = CItemType::AsType(pType); CItem Item(pItemType, 1); // Skip if not in item criteria if (!Item.MatchesCriteria(ItemCriteria)) continue; // Skip virtual classes if (pItemType->IsVirtual()) continue; // Initialize the entry NewEntry.pType = pType; NewEntry.sName = pItemType->GetNounPhrase(0); NewEntry.pImage = &pItemType->GetImage(); NewEntry.iSize = RectWidth(NewEntry.pImage->GetImageRect()); break; } case designShipClass: { CShipClass *pClass = CShipClass::AsType(pType); // Skip non-generic classess if (!bAll && !pClass->HasLiteralAttribute(CONSTLIT("genericClass"))) continue; // Initialize the entry NewEntry.pType = pType; NewEntry.sName = pClass->GetNounPhrase(0); NewEntry.iSize = RectWidth(pClass->GetImage().GetImageRect()); NewEntry.pImage = &pClass->GetImage(); NewEntry.iRotation = pClass->Angle2Direction(iRotation); NewEntry.sSovereignName = (pClass->GetDefaultSovereign() ? pClass->GetDefaultSovereign()->GetTypeNounPhrase() : NULL_STR); break; } case designStationType: { CStationType *pStationType = CStationType::AsType(pType); // Skip generic classes if (!bAll && !pStationType->HasLiteralAttribute(CONSTLIT("generic"))) continue; NewEntry.pType = pType; NewEntry.sName = pStationType->GetNounPhrase(0); NewEntry.iSize = pStationType->GetSize(); NewEntry.sSovereignName = (pStationType->GetSovereign() ? pStationType->GetSovereign()->GetTypeNounPhrase() : NULL_STR); InitStationTypeImage(NewEntry, pStationType); break; } default: // Don't know how to handle this type continue; break; } // Adjust name if (bFieldUNID) NewEntry.sName = strPatternSubst(CONSTLIT("%s (%x)"), NewEntry.sName, NewEntry.pType->GetUNID()); // Compute the sort key char szBuffer[1024]; switch (iOrder) { case orderLargest: wsprintf(szBuffer, "%09d%s%x", 1000000 - NewEntry.iSize, NewEntry.sName.GetASCIIZPointer(), pType->GetUNID()); break; case orderLevel: wsprintf(szBuffer, "%09d%s%x", pType->GetLevel(), NewEntry.sName.GetASCIIZPointer(), pType->GetUNID()); break; case orderSmallest: wsprintf(szBuffer, "%09d%s%x", NewEntry.iSize, NewEntry.sName.GetASCIIZPointer(), pType->GetUNID()); break; case orderSovereign: wsprintf(szBuffer, "%s|%s|%x", NewEntry.sSovereignName.GetASCIIZPointer(), NewEntry.sName.GetASCIIZPointer(), pType->GetUNID()); NewEntry.sCategorize = NewEntry.sSovereignName; break; case orderManufacturer: { CString sManufacturer = NewEntry.pType->GetPropertyString(CONSTLIT("manufacturer")); wsprintf(szBuffer, "%s|%s|%x", sManufacturer.GetASCIIZPointer(), NewEntry.sName.GetASCIIZPointer(), pType->GetUNID()); NewEntry.sCategorize = sManufacturer; break; } default: wsprintf(szBuffer, "%s%x", NewEntry.sName.GetASCIIZPointer(), pType->GetUNID()); break; } // Add to list Table.Insert(CString(szBuffer), NewEntry); } // Allocate an arranger that tracks where to paint each world. CImageArranger Arranger; // Settings for the overall arrangement CImageArranger::SArrangeDesc Desc; Desc.cxDesiredWidth = Max(512, cxDesiredWidth - (2 * (cxSpacing + cxExtraMargin))); Desc.cxSpacing = cxSpacing; Desc.cxExtraMargin = cxExtraMargin; Desc.pHeader = &NameFont; // Generate a table of cells for the arranger TArray<CCompositeImageSelector> Selectors; Selectors.InsertEmpty(Table.GetCount()); CString sLastCategory; TArray<CImageArranger::SCellDesc> Cells; for (i = 0; i < Table.GetCount(); i++) { SEntryDesc &Entry = Table[i]; CImageArranger::SCellDesc *pNewCell = Cells.Insert(); pNewCell->cxWidth = (Entry.pImage ? RectWidth(Entry.pImage->GetImageRect()) : 0) + cxImageMargin; pNewCell->cyHeight = (Entry.pImage ? RectHeight(Entry.pImage->GetImageRect()) : 0) + cxImageMargin; pNewCell->sText = Entry.sName; if (!strEquals(sLastCategory, Entry.sCategorize)) { sLastCategory = Entry.sCategorize; pNewCell->bStartNewRow = true; } } // Arrange Arranger.ArrangeByRow(Desc, Cells); // Create a large image CG32bitImage Output; int cxWidth = Max(cxDesiredWidth, Arranger.GetWidth()); int cyHeight = Arranger.GetHeight(); Output.Create(cxWidth, cyHeight); printf("Creating %dx%d image.\n", cxWidth, cyHeight); // Paint the images for (i = 0; i < Table.GetCount(); i++) { SEntryDesc &Entry = Table[i]; int x = Arranger.GetX(i); int y = Arranger.GetY(i); // Paint if (x != -1) { int xCenter = x + (Arranger.GetWidth(i) / 2); int yCenter = y + (Arranger.GetHeight(i) / 2); int xOffset; int yOffset; Entry.pImage->GetImageOffset(0, Entry.iRotation, &xOffset, &yOffset); int cxImage = RectWidth(Entry.pImage->GetImageRect()); int cyImage = RectHeight(Entry.pImage->GetImageRect()); // Paint image if (!bTextBoxesOnly && Entry.pImage) { Entry.pImage->PaintImageUL(Output, x + (Arranger.GetWidth(i) - cxImage) / 2, y + (Arranger.GetHeight(i) - cyImage) / 2, 0, Entry.iRotation); } // Paint type specific stuff switch (Entry.pType->GetType()) { case designStationType: { CStationType *pStationType = CStationType::AsType(Entry.pType); int xStationCenter = xCenter - xOffset; int yStationCenter = yCenter - yOffset; if (bDockingPorts) pStationType->PaintDockPortPositions(Output, xStationCenter, yStationCenter); if (bDevicePos) pStationType->PaintDevicePositions(Output, xStationCenter, yStationCenter); // If we have docking or device positions, mark the center of the station if (bDockingPorts || bDevicePos) { const int LINE_HALF_LENGTH = 24; const CG32bitPixel RGB_CENTER_CROSS(255, 255, 0); Output.DrawLine(xStationCenter - LINE_HALF_LENGTH, yStationCenter, xStationCenter + LINE_HALF_LENGTH, yStationCenter, 1, RGB_CENTER_CROSS); Output.DrawLine(xStationCenter, yStationCenter - LINE_HALF_LENGTH, xStationCenter, yStationCenter + LINE_HALF_LENGTH, 1, RGB_CENTER_CROSS); } break; } } // Paint the 3D grid, if necessary if (b3DGrid) { int iScale = Entry.pImage->GetImageViewportSize(); Metric rMaxRadius = g_KlicksPerPixel * cxImage * 0.5; const Metric rGridSize = LIGHT_SECOND; Metric rRadius; for (rRadius = rGridSize; rRadius <= rMaxRadius; rRadius += rGridSize) { int iRadius = (int)((rRadius / g_KlicksPerPixel) + 0.5); const int iGridAngle = 8; int iPrevAngle = 0; int iAngle; for (iAngle = iGridAngle; iAngle <= 360; iAngle += iGridAngle) { int xFrom, yFrom; C3DConversion::CalcCoord(iScale, iPrevAngle, iRadius, 0, &xFrom, &yFrom); int xTo, yTo; C3DConversion::CalcCoord(iScale, iAngle, iRadius, 0, &xTo, &yTo); Output.DrawLine(xFrom + xCenter, yFrom + yCenter, xTo + xCenter, yTo + yCenter, 1, CG32bitPixel(255, 255, 0)); iPrevAngle = iAngle; } } } // Paint name int xText = Arranger.GetTextX(i); int yText = Arranger.GetTextY(i); if (xText != -1) { if (bTextBoxesOnly) Output.Fill(xText, yText, Arranger.GetTextWidth(i), Arranger.GetTextHeight(i), 0xffff); if (!bTextBoxesOnly) { Output.FillColumn(xCenter, y + Arranger.GetHeight(i), yText - (y + Arranger.GetHeight(i)), rgbNameColor); NameFont.DrawText(Output, xText, yText, rgbNameColor, Entry.sName); } } } } // Write to file or clipboard OutputImage(Output, sFilespec); }
void CRayEffectPainter::CalcIntermediates (void) // CalcIntermediates // // Calculate intermediate values used for painting. { int i, v, w; if (!m_bInitialized) { enum EColorTypes { colorNone, colorGlow, }; enum EOpacityTypes { opacityNone, opacityGlow, opacityGrainy, opacityTaperedGlow, }; enum EWidthAdjTypes { widthAdjNone, widthAdjBlob, widthAdjDiamond, widthAdjJagged, widthAdjOval, widthAdjTapered, widthAdjCone, }; EColorTypes iColorTypes = colorNone; EOpacityTypes iOpacityTypes = opacityNone; EWidthAdjTypes iWidthAdjType = widthAdjNone; EWidthAdjTypes iReshape = widthAdjNone; EOpacityTypes iTexture = opacityNone; m_iWidthCount = m_iWidth; m_iLengthCount = 2 * m_iLength; // Every combination requires a slightly different set up switch (m_iShape) { case shapeCone: switch (m_iStyle) { case styleBlob: iColorTypes = colorGlow; iOpacityTypes = opacityTaperedGlow; iWidthAdjType = widthAdjBlob; iReshape = widthAdjCone; break; case styleGlow: iColorTypes = colorGlow; iOpacityTypes = opacityTaperedGlow; iWidthAdjType = widthAdjCone; break; case styleGrainy: iColorTypes = colorGlow; iOpacityTypes = opacityTaperedGlow; iWidthAdjType = widthAdjCone; iTexture = opacityGrainy; break; case styleJagged: iColorTypes = colorGlow; iOpacityTypes = opacityTaperedGlow; iWidthAdjType = widthAdjJagged; iReshape = widthAdjCone; break; } break; case shapeDiamond: switch (m_iStyle) { case styleBlob: iColorTypes = colorGlow; iOpacityTypes = opacityTaperedGlow; iWidthAdjType = widthAdjBlob; iReshape = widthAdjDiamond; break; case styleGlow: iColorTypes = colorGlow; iOpacityTypes = opacityTaperedGlow; iWidthAdjType = widthAdjDiamond; break; case styleGrainy: iColorTypes = colorGlow; iOpacityTypes = opacityTaperedGlow; iWidthAdjType = widthAdjDiamond; iTexture = opacityGrainy; break; case styleJagged: iColorTypes = colorGlow; iOpacityTypes = opacityTaperedGlow; iWidthAdjType = widthAdjJagged; iReshape = widthAdjDiamond; break; } break; case shapeOval: switch (m_iStyle) { case styleBlob: iColorTypes = colorGlow; iOpacityTypes = opacityTaperedGlow; iWidthAdjType = widthAdjBlob; iReshape = widthAdjOval; break; case styleGlow: iColorTypes = colorGlow; iOpacityTypes = opacityTaperedGlow; iWidthAdjType = widthAdjOval; break; case styleGrainy: iColorTypes = colorGlow; iOpacityTypes = opacityTaperedGlow; iWidthAdjType = widthAdjOval; iTexture = opacityGrainy; break; case styleJagged: iColorTypes = colorGlow; iOpacityTypes = opacityTaperedGlow; iWidthAdjType = widthAdjJagged; iReshape = widthAdjOval; break; } break; case shapeStraight: switch (m_iStyle) { case styleBlob: iColorTypes = colorGlow; iOpacityTypes = opacityGlow; iWidthAdjType = widthAdjBlob; break; case styleGlow: iColorTypes = colorGlow; iOpacityTypes = opacityGlow; break; case styleGrainy: iColorTypes = colorGlow; iOpacityTypes = opacityGlow; iTexture = opacityGrainy; break; case styleJagged: iColorTypes = colorGlow; iOpacityTypes = opacityGlow; iWidthAdjType = widthAdjJagged; break; } break; case shapeTapered: switch (m_iStyle) { case styleBlob: iColorTypes = colorGlow; iOpacityTypes = opacityTaperedGlow; iWidthAdjType = widthAdjBlob; iReshape = widthAdjTapered; break; case styleGlow: iColorTypes = colorGlow; iOpacityTypes = opacityTaperedGlow; iWidthAdjType = widthAdjTapered; break; case styleGrainy: iColorTypes = colorGlow; iOpacityTypes = opacityTaperedGlow; iWidthAdjType = widthAdjTapered; iTexture = opacityGrainy; break; case styleJagged: iColorTypes = colorGlow; iOpacityTypes = opacityTaperedGlow; iWidthAdjType = widthAdjJagged; iReshape = widthAdjTapered; break; } break; } // Full color map switch (iColorTypes) { case colorGlow: { m_ColorMap.InsertEmpty(1); m_ColorMap[0].InsertEmpty(m_iWidthCount); // The center blends towards white WORD wCenter = CG16bitImage::BlendPixel(m_wPrimaryColor, CG16bitImage::RGBValue(255, 255, 255), (DWORD)(255.0 * Min(50, m_iIntensity) / 50.0)); int iBrightPoint = (int)(BRIGHT_FACTOR * m_iWidthCount * m_iIntensity); for (i = 0; i < iBrightPoint; i++) m_ColorMap[0][i] = wCenter; // The rest fades (linearly) from primary color to secondary color Metric rFadeInc = (m_iWidthCount > 0 ? (1.0 / (m_iWidthCount - iBrightPoint)) : 0.0); Metric rFade = 1.0; for (i = iBrightPoint; i < m_iWidthCount; i++, rFade -= rFadeInc) m_ColorMap[0][i] = CG16bitImage::BlendPixel(m_wSecondaryColor, m_wPrimaryColor, (DWORD)(255.0 * rFade)); break; } } // Full opacity switch (iOpacityTypes) { case opacityGlow: { m_OpacityMap.InsertEmpty(1); m_OpacityMap[0].InsertEmpty(m_iWidthCount); // From center to peak we have solid opacity int iPeakPoint = (int)(SOLID_FACTOR * m_iIntensity * m_iWidthCount); for (i = 0; i < iPeakPoint; i++) m_OpacityMap[0][i] = 255; // We decay exponentially to edge Metric rGlowLevel = MIN_GLOW_LEVEL + (m_iIntensity * GLOW_FACTOR); Metric rGlowInc = (m_iWidthCount > 0 ? (1.0 / (m_iWidthCount - iPeakPoint)) : 0.0); Metric rGlow = 1.0; for (i = iPeakPoint; i < m_iWidthCount; i++, rGlow -= rGlowInc) m_OpacityMap[0][i] = (int)(255.0 * rGlowLevel * rGlow * rGlow); break; } case opacityTaperedGlow: { m_OpacityMap.InsertEmpty(m_iLengthCount); for (i = 0; i < m_iLengthCount; i++) m_OpacityMap[i].InsertEmpty(m_iWidthCount); // From center to peak we have solid opacity int iPeakPoint = (int)(SOLID_FACTOR * m_iIntensity * m_iWidthCount); // After the 1/3 point start fading out (linearly) int iFadePoint = m_iLengthCount / TAPER_FRACTION; Metric rTaperInc = (m_iLengthCount > 0 ? (1.0 / (m_iLengthCount - iFadePoint)) : 0.0); // From center to peak we have solid opacity plus taper for (w = 0; w < iPeakPoint; w++) { for (v = 0; v < iFadePoint; v++) m_OpacityMap[v][w] = 255; Metric rTaper = 1.0; for (v = iFadePoint; v < m_iLengthCount; v++, rTaper -= rTaperInc) m_OpacityMap[v][w] = (int)(255.0 * rTaper); } // The glow around the peak decays exponentially Metric rGlowLevel = MIN_GLOW_LEVEL + (m_iIntensity * GLOW_FACTOR); Metric rGlowInc = (m_iWidthCount > 0 ? (1.0 / (m_iWidthCount - iPeakPoint)) : 0.0); Metric rGlow = 1.0; for (w = iPeakPoint; w < m_iWidthCount; w++, rGlow -= rGlowInc) { Metric rGlowPart = rGlowLevel * rGlow * rGlow; for (v = 0; v < iFadePoint; v++) m_OpacityMap[v][w] = (int)(255.0 * rGlowPart); Metric rTaper = 1.0; for (v = iFadePoint; v < m_iLengthCount; v++, rTaper -= rTaperInc) m_OpacityMap[v][w] = (int)(255.0 * rGlowPart * rTaper); } break; } } // Width adjustments switch (iWidthAdjType) { case widthAdjBlob: { m_WidthAdjTop.InsertEmpty(m_iLengthCount); m_WidthAdjBottom.InsertEmpty(m_iLengthCount); // Initialize jagged envelope CalcWaves(m_WidthAdjTop, BLOB_WAVE_SIZE, m_iWidth * WAVY_WAVELENGTH_FACTOR); CalcWaves(m_WidthAdjBottom, BLOB_WAVE_SIZE, m_iWidth * WAVY_WAVELENGTH_FACTOR); break; } case widthAdjCone: { m_WidthAdjTop.InsertEmpty(m_iLengthCount); CalcCone(m_WidthAdjTop); m_WidthAdjBottom = m_WidthAdjTop; break; } case widthAdjDiamond: { m_WidthAdjTop.InsertEmpty(m_iLengthCount); CalcDiamond(m_WidthAdjTop); m_WidthAdjBottom = m_WidthAdjTop; break; } case widthAdjJagged: { m_WidthAdjTop.InsertEmpty(m_iLengthCount); m_WidthAdjBottom.InsertEmpty(m_iLengthCount); // Initialize jagged envelope CalcWaves(m_WidthAdjTop, JAGGED_AMPLITUDE, m_iWidth * JAGGED_WAVELENGTH_FACTOR); CalcWaves(m_WidthAdjBottom, JAGGED_AMPLITUDE, m_iWidth * JAGGED_WAVELENGTH_FACTOR); break; } case widthAdjOval: { m_WidthAdjTop.InsertEmpty(m_iLengthCount); CalcOval(m_WidthAdjTop); m_WidthAdjBottom = m_WidthAdjTop; break; } case widthAdjTapered: { m_WidthAdjTop.InsertEmpty(m_iLengthCount); CalcTaper(m_WidthAdjTop); m_WidthAdjBottom = m_WidthAdjTop; break; } } // Adjust shape switch (iReshape) { case widthAdjCone: { TArray<Metric> TaperAdj; TaperAdj.InsertEmpty(m_iLengthCount); CalcCone(TaperAdj); for (i = 0; i < m_iLengthCount; i++) { m_WidthAdjTop[i] *= TaperAdj[i]; m_WidthAdjBottom[i] *= TaperAdj[i]; } break; } case widthAdjDiamond: { TArray<Metric> TaperAdj; TaperAdj.InsertEmpty(m_iLengthCount); CalcDiamond(TaperAdj); for (i = 0; i < m_iLengthCount; i++) { m_WidthAdjTop[i] *= TaperAdj[i]; m_WidthAdjBottom[i] *= TaperAdj[i]; } break; } case widthAdjOval: { TArray<Metric> TaperAdj; TaperAdj.InsertEmpty(m_iLengthCount); CalcOval(TaperAdj); for (i = 0; i < m_iLengthCount; i++) { m_WidthAdjTop[i] *= TaperAdj[i]; m_WidthAdjBottom[i] *= TaperAdj[i]; } break; } case widthAdjTapered: { TArray<Metric> TaperAdj; TaperAdj.InsertEmpty(m_iLengthCount); CalcTaper(TaperAdj); for (i = 0; i < m_iLengthCount; i++) { m_WidthAdjTop[i] *= TaperAdj[i]; m_WidthAdjBottom[i] *= TaperAdj[i]; } break; } } // Apply texture switch (iTexture) { case opacityGrainy: { const int DIAMETER = 11; const int START = -(DIAMETER / 2); const int CENTER_X = (DIAMETER / 2); const int CENTER_Y = (DIAMETER / 2); const Metric RADIUS = (DIAMETER / 2.0); Metric Adj[DIAMETER][DIAMETER]; for (v = 0; v < DIAMETER; v++) for (w = 0; w < DIAMETER; w++) { int vDiff = v - CENTER_X; int wDiff = w - CENTER_Y; Metric rDist = sqrt((Metric)(vDiff * vDiff + wDiff * wDiff)) / RADIUS; Adj[v][w] = Max(0.0, 1.0 - rDist); } int iPeakPoint = (int)(SOLID_FACTOR * m_iIntensity * m_iWidthCount); int iGrainCount = (int)(4 * sqrt((Metric)m_iLength * m_iWidth)); for (i = 0; i < iGrainCount; i++) { int vCount = m_OpacityMap.GetCount(); int wCount = m_OpacityMap[0].GetCount(); int vCenter = mathRandom(0, vCount - 1); int wCenter = mathRandom(0, wCount - 1); Metric rCenter = GRAINY_SIGMA * mathRandomGaussian(); for (v = 0; v < DIAMETER; v++) { int vPos = START + vCenter + v; if (vPos < 0 || vPos >= vCount) continue; for (w = 0; w < DIAMETER; w++) { int wPos = START + wCenter + w; if (wPos < iPeakPoint || wPos >= wCount) continue; m_OpacityMap[vPos][wPos] = (BYTE)Min(Max(0, (int)((Metric)m_OpacityMap[vPos][wPos] * (1.0 + rCenter * Adj[v][w]))), 255); } } } break; } } // Done m_bInitialized = true; } }
void CGSelectorArea::SetRegionsFromMiscDevices (CSpaceObject *pSource) // SetRegionsFromMiscDevices // // Generates regions showing misc devices (including reactor, drive, // and cargo hold). { int i; ASSERT(pSource); if (pSource == NULL) return; CShip *pShip = pSource->AsShip(); if (pShip == NULL) return; CShipClass *pClass = pShip->GetClass(); // Keep track of layouts that have already been used. TArray<bool> SlotStatus; SlotStatus.InsertEmpty(MISC_DEVICES_LAYOUT_COUNT); for (i = 0; i < MISC_DEVICES_LAYOUT_COUNT; i++) SlotStatus[i] = true; // Reserve the slots for named device types SlotStatus[REACTOR_SLOT_INDEX] = false; SlotStatus[DRIVE_SLOT_INDEX] = false; SlotStatus[CARGO_SLOT_INDEX] = false; // Count the number of miscellaneous devices with 0 // slots (because we may need to bump them). int iSlottedDevices = 0; int iNonSlotDevices = 0; for (i = 0; i < pShip->GetDeviceCount(); i++) { CInstalledDevice *pDevice = pShip->GetDevice(i); if (pDevice->IsEmpty() || pDevice->GetCategory() != itemcatMiscDevice) continue; if (pDevice->GetClass()->GetSlotsRequired() > 0) iSlottedDevices++; else iNonSlotDevices++; } // We try to fit all other devices (and placeholders) before we add a // non-slotted device. int iNonSlotDeviceSlotsAvail = Max(0, MISC_DEVICES_LAYOUT_COUNT - 4 - iSlottedDevices); // Create a region for each device. int iIndex = -1; bool bHasReactor = false; bool bHasDrive = false; bool bHasCargo = false; int iNextUnamedSlot = FIRST_UNNAMED_SLOT_INDEX; for (i = 0; i < pShip->GetDeviceCount(); i++) { CInstalledDevice *pDevice = pShip->GetDevice(i); if (pDevice->IsEmpty()) continue; // Figure out the layout descriptor iIndex = -1; const SLayoutDesc *pLayout = NULL; switch (pDevice->GetCategory()) { case itemcatCargoHold: pLayout = &g_MiscDevicesLayout[CARGO_SLOT_INDEX]; bHasCargo = true; break; case itemcatDrive: pLayout = &g_MiscDevicesLayout[DRIVE_SLOT_INDEX]; bHasDrive = true; break; case itemcatMiscDevice: { // If this is a 0-slot device and we have no more room for // 0-slot devices, then we skip it. if (pDevice->GetClass()->GetSlotsRequired() == 0 && iNonSlotDeviceSlotsAvail <= 0) continue; // If the device already has a position index, then use that (assuming // it's free). iIndex = pDevice->GetSlotPosIndex(); if (iIndex < 0 || iIndex >= SlotStatus.GetCount() || !SlotStatus[iIndex]) iIndex = -1; // If we don't have an assigned slot, figure it out. if (iIndex == -1) { // Look for a new position if (!FindLayoutForPos(pDevice->GetPosOffset(pShip), SlotStatus, &iIndex)) continue; // Remember so we stay in this location. pDevice->SetSlotPosIndex(iIndex); } // Remember the layout and mark it as used. pLayout = &g_MiscDevicesLayout[iIndex]; SlotStatus[iIndex] = false; break; } case itemcatReactor: pLayout = &g_MiscDevicesLayout[REACTOR_SLOT_INDEX]; bHasReactor = true; break; } // Create the region (but only if we have a layout position // for it). if (pLayout) { SEntry *pEntry = m_Regions.Insert(); pEntry->iType = typeInstalledItem; pEntry->pItemCtx = new CItemCtx(pShip, pDevice); pEntry->iSlotPosIndex = iIndex; pEntry->rcRect.left = pLayout->xLeft; pEntry->rcRect.top = pLayout->yTop; pEntry->rcRect.right = pEntry->rcRect.left + ITEM_ENTRY_WIDTH; pEntry->rcRect.bottom = pEntry->rcRect.top + ITEM_ENTRY_HEIGHT; } } // Add empty slots, if necessary if (!bHasReactor) { const SLayoutDesc *pLayout = &g_MiscDevicesLayout[REACTOR_SLOT_INDEX]; SEntry *pEntry = m_Regions.Insert(); pEntry->iType = typeEmptySlot; pEntry->iSlotType = devReactor; pEntry->rcRect.left = pLayout->xLeft; pEntry->rcRect.top = pLayout->yTop; pEntry->rcRect.right = pEntry->rcRect.left + ITEM_ENTRY_WIDTH; pEntry->rcRect.bottom = pEntry->rcRect.top + ITEM_ENTRY_HEIGHT; } if (!bHasDrive) { const SLayoutDesc *pLayout = &g_MiscDevicesLayout[DRIVE_SLOT_INDEX]; SEntry *pEntry = m_Regions.Insert(); pEntry->iType = typeEmptySlot; pEntry->iSlotType = devDrive; pEntry->rcRect.left = pLayout->xLeft; pEntry->rcRect.top = pLayout->yTop; pEntry->rcRect.right = pEntry->rcRect.left + ITEM_ENTRY_WIDTH; pEntry->rcRect.bottom = pEntry->rcRect.top + ITEM_ENTRY_HEIGHT; } if (!bHasCargo) { const SLayoutDesc *pLayout = &g_MiscDevicesLayout[CARGO_SLOT_INDEX]; SEntry *pEntry = m_Regions.Insert(); pEntry->iType = typeEmptySlot; pEntry->iSlotType = devCargo; pEntry->rcRect.left = pLayout->xLeft; pEntry->rcRect.top = pLayout->yTop; pEntry->rcRect.right = pEntry->rcRect.left + ITEM_ENTRY_WIDTH; pEntry->rcRect.bottom = pEntry->rcRect.top + ITEM_ENTRY_HEIGHT; } // Figure out how many empty weapon slots we should create. We add one // empty slot for each weapon slot, but we subtract one if we don't have // a launcher and we always have at least 1 empty slot, in case the player // finds a slot-less weapon. #ifdef SINGLE_FREE_SLOT int iEmptySlots = 1; #else int iNonWeaponSlotsInUse; int iTotalSlotsInUse = pShip->CalcDeviceSlotsInUse(NULL, &iNonWeaponSlotsInUse); int iEmptySlots = Max(1, Min((pClass->GetMaxDevices() - iTotalSlotsInUse), (pClass->GetMaxNonWeapons() - iNonWeaponSlotsInUse)) - (bHasReactor ? 0 : 1) - (bHasDrive ? 0 : 1) - (bHasCargo ? 0 : 1)); #endif for (i = 0; i < iEmptySlots; i++) { if (FindLayoutForPos(CVector(), SlotStatus, &iIndex)) { const SLayoutDesc *pLayout = &g_MiscDevicesLayout[iIndex]; SEntry *pEntry = m_Regions.Insert(); pEntry->iType = typeEmptySlot; pEntry->iSlotType = devNone; pEntry->iSlotPosIndex = iIndex; pEntry->rcRect.left = pLayout->xLeft; pEntry->rcRect.top = pLayout->yTop; pEntry->rcRect.right = pEntry->rcRect.left + ITEM_ENTRY_WIDTH; pEntry->rcRect.bottom = pEntry->rcRect.top + ITEM_ENTRY_HEIGHT; SlotStatus[iIndex] = false; } } }
void CItemList::SortItems (void) // SortItems // // Sorts items in order: // // installed/not-installed // armor/weapon/device/other { if (GetCount() == 0) return; int i; CSymbolTable Sort(false, true); for (i = 0; i < GetCount(); i++) { CItem &Item = GetItem(i); CItemType *pType = Item.GetType(); // All installed items first CString sInstalled; if (Item.IsInstalled()) sInstalled = CONSTLIT("0"); else sInstalled = CONSTLIT("1"); // Next, sort on category CString sCat; switch (pType->GetCategory()) { case itemcatWeapon: case itemcatLauncher: sCat = CONSTLIT("0"); break; case itemcatMissile: sCat = CONSTLIT("1"); break; case itemcatShields: sCat = CONSTLIT("2"); break; case itemcatReactor: sCat = CONSTLIT("3"); break; case itemcatDrive: sCat = CONSTLIT("4"); break; case itemcatCargoHold: sCat = CONSTLIT("5"); break; case itemcatMiscDevice: sCat = CONSTLIT("6"); break; case itemcatArmor: sCat = CONSTLIT("7"); break; case itemcatFuel: case itemcatUseful: sCat = CONSTLIT("8"); break; default: sCat = CONSTLIT("9"); } // Next, sort by install location if (Item.IsInstalled()) sCat.Append(strPatternSubst(CONSTLIT("%03d%08x"), Item.GetInstalled(), Item.GetType()->GetUNID())); else sCat.Append(CONSTLIT("99900000000")); // Within category, sort by level (highest first) sCat.Append(strPatternSubst(CONSTLIT("%02d"), MAX_ITEM_LEVEL - Item.GetType()->GetApparentLevel())); // Enhanced items before others if (Item.IsEnhanced()) sCat.Append(CONSTLIT("0")); else if (Item.IsDamaged()) sCat.Append(CONSTLIT("2")); else sCat.Append(CONSTLIT("1")); CString sName = pType->GetSortName(); CString sSort = strPatternSubst(CONSTLIT("%s%s%s%d"), sInstalled, sCat, sName, (i * (int)this) % 0x10000); Sort.AddEntry(sSort, (CObject *)i); } // Allocate a new list TArray<CItem *> NewList; NewList.InsertEmpty(GetCount()); // Move the items from the old list to the new list in the new order for (i = 0; i < GetCount(); i++) { int iOld = (int)Sort.GetValue(i); NewList[i] = m_List[iOld]; } // Swap m_List.TakeHandoff(NewList); }
void CCompositeEntry::GetImage (const CCompositeImageSelector &Selector, CObjectImageArray *retImage) // GetImage // // Fills in the image { int i; // Null case if (m_Layers.GetCount() == 0) { *retImage = EMPTY_IMAGE; return; } // Get all the layers TArray<CObjectImageArray> Result; Result.InsertEmpty(m_Layers.GetCount()); for (i = 0; i < m_Layers.GetCount(); i++) m_Layers[i]->GetImage(Selector, &Result[i]); // Create the composited image // // First we need to determine the size of the final image, based // on the size and position of each layer. int xMin = 0; int xMax = 0; int yMin = 0; int yMax = 0; for (i = 0; i < m_Layers.GetCount(); i++) { CObjectImageArray &LayerImage = Result[i]; const RECT &rcRect = LayerImage.GetImageRect(); int xImageOffset = 0; int yImageOffset = 0; int xMaxImage = (RectWidth(rcRect) / 2) + xImageOffset; int xMinImage = xMaxImage - RectWidth(rcRect); int yMaxImage = (RectHeight(rcRect) / 2) + yImageOffset; int yMinImage = yMaxImage - RectHeight(rcRect); xMin = Min(xMin, xMinImage); xMax = Max(xMax, xMaxImage); yMin = Min(yMin, yMinImage); yMax = Max(yMax, yMaxImage); } // Create destination image int cxWidth = xMax - xMin; int cyHeight = yMax - yMin; if (cxWidth <= 0 || cyHeight <= 0) { *retImage = EMPTY_IMAGE; return; } CG16bitImage *pComp = new CG16bitImage; pComp->CreateBlank(cxWidth, cyHeight, false); pComp->SetTransparentColor(); int xCenter = cxWidth / 2; int yCenter = cyHeight / 2; // Blt on the destination for (i = 0; i < m_Layers.GetCount(); i++) { CObjectImageArray &LayerImage = Result[i]; const RECT &rcRect = LayerImage.GetImageRect(); // Paint the image LayerImage.PaintImage(*pComp, xCenter, yCenter, 0, 0); } // Initialize an image RECT rcFinalRect; rcFinalRect.left = 0; rcFinalRect.top = 0; rcFinalRect.right = cxWidth; rcFinalRect.bottom = cyHeight; CObjectImageArray Comp; Comp.Init(pComp, rcFinalRect, 0, 0, true); // Done retImage->TakeHandoff(Comp); }
ALERROR CDesignCollection::SelectExtensions (CAdventureDesc *pAdventure, TArray<DWORD> *pExtensionList, bool *retbBindNeeded, CString *retsError) // SelectExtensions // // Enables all extensions in pExtensionList and disables all others // (if pExtensionList == NULL then we enable all extensions). // // Returns an error if an extension on the list could not be found. { int i; bool bBindNeeded = false; TArray<bool> OldState; OldState.InsertEmpty(GetExtensionCount()); // Disable all extensions for (i = 0; i < GetExtensionCount(); i++) { SExtensionDesc *pEntry = GetExtension(i); if (pEntry->iType == extExtension) { OldState[i] = pEntry->bEnabled; pEntry->bEnabled = false; } } // Enable all extensions in the list if (pExtensionList) { for (i = 0; i < pExtensionList->GetCount(); i++) { SExtensionDesc *pEntry = FindExtension(pExtensionList->GetAt(i)); if (pEntry == NULL || pEntry->iType == extAdventure) { if (retsError) *retsError = strPatternSubst(CONSTLIT("Unable to find extension: %x"), pExtensionList->GetAt(i)); return ERR_NOTFOUND; } if (pEntry->iType == extExtension && IsExtensionCompatibleWithAdventure(pEntry, pAdventure)) pEntry->bEnabled = true; } } else { // Enable all extensions for (i = 0; i < GetExtensionCount(); i++) { SExtensionDesc *pEntry = GetExtension(i); if (pEntry->iType == extExtension && IsExtensionCompatibleWithAdventure(pEntry, pAdventure) && (!pEntry->bDebugOnly || g_pUniverse->InDebugMode())) pEntry->bEnabled = true; } } // See if we made any changes for (i = 0; i < GetExtensionCount(); i++) { SExtensionDesc *pEntry = GetExtension(i); if (pEntry->iType == extExtension && pEntry->bEnabled != OldState[i]) { bBindNeeded = true; break; } } // Done if (retbBindNeeded) *retbBindNeeded = bBindNeeded; return NOERROR; }
void CGSelectorArea::SetRegionsFromWeapons (CSpaceObject *pSource) // SetRegionsFromWeapons // // Creates regions based on installed weapons. { int i; ASSERT(pSource); if (pSource == NULL) return; CShip *pShip = pSource->AsShip(); if (pShip == NULL) return; CShipClass *pClass = pShip->GetClass(); // Keep track of layouts that have already been used. TArray<bool> SlotStatus; SlotStatus.InsertEmpty(MISC_DEVICES_LAYOUT_COUNT); for (i = 0; i < MISC_DEVICES_LAYOUT_COUNT; i++) SlotStatus[i] = true; // If we don't have a launcher, we place the launcher slot first because we // want it to take precedence (position-wise). int iIndex; bool bHasLauncher = (pShip->GetNamedDevice(devMissileWeapon) != NULL); if (!bHasLauncher) { // See if we can figure out the proper position for the launcher based // on the class slots CVector vLauncherPos; SDeviceDesc DeviceDesc; if (pClass->FindDeviceSlotDesc(devMissileWeapon, &DeviceDesc)) vLauncherPos = pClass->GetPosOffset(DeviceDesc.iPosAngle, DeviceDesc.iPosRadius, DeviceDesc.iPosZ, DeviceDesc.b3DPosition); // Find a layout if (FindLayoutForPos(vLauncherPos, SlotStatus, &iIndex)) { const SLayoutDesc *pLayout = &g_MiscDevicesLayout[iIndex]; SEntry *pEntry = m_Regions.Insert(); pEntry->iType = typeEmptySlot; pEntry->iSlotType = devMissileWeapon; pEntry->iSlotPosIndex = iIndex; pEntry->rcRect.left = pLayout->xLeft; pEntry->rcRect.top = pLayout->yTop; pEntry->rcRect.right = pEntry->rcRect.left + ITEM_ENTRY_WIDTH; pEntry->rcRect.bottom = pEntry->rcRect.top + ITEM_ENTRY_HEIGHT; SlotStatus[iIndex] = false; } } // Create a region for each weapon. for (i = 0; i < pShip->GetDeviceCount(); i++) { CInstalledDevice *pDevice = pShip->GetDevice(i); if (pDevice->IsEmpty() || (pDevice->GetCategory() != itemcatWeapon && pDevice->GetCategory() != itemcatLauncher)) continue; if (pDevice->GetCategory() == itemcatLauncher) bHasLauncher = true; // If the device already has a position index, then use that (assuming // it's free). iIndex = pDevice->GetSlotPosIndex(); if (iIndex < 0 || iIndex >= SlotStatus.GetCount() || !SlotStatus[iIndex]) iIndex = -1; // If we don't have an assigned slot, figure it out. if (iIndex == -1) { if (!FindLayoutForPos(pDevice->GetPosOffset(pShip), SlotStatus, &iIndex)) continue; // Remember so we stay in this location. pDevice->SetSlotPosIndex(iIndex); } // Create the region const SLayoutDesc *pLayout = &g_MiscDevicesLayout[iIndex]; SEntry *pEntry = m_Regions.Insert(); pEntry->iType = typeInstalledItem; pEntry->pItemCtx = new CItemCtx(pShip, pDevice); pEntry->iSlotPosIndex = iIndex; pEntry->rcRect.left = pLayout->xLeft; pEntry->rcRect.top = pLayout->yTop; pEntry->rcRect.right = pEntry->rcRect.left + ITEM_ENTRY_WIDTH; pEntry->rcRect.bottom = pEntry->rcRect.top + ITEM_ENTRY_HEIGHT; // Mark the layout as used SlotStatus[iIndex] = false; } // Figure out how many empty weapon slots we should create. We add one // empty slot for each weapon slot, but we subtract one if we don't have // a launcher and we always have at least 1 empty slot, in case the player // finds a slot-less weapon. #ifdef SINGLE_FREE_SLOT int iEmptySlots = 1; #else int iWeaponSlotsInUse; int iTotalSlotsInUse = pShip->CalcDeviceSlotsInUse(&iWeaponSlotsInUse); int iEmptySlots = Max(1, Min((pClass->GetMaxDevices() - iTotalSlotsInUse), (pClass->GetMaxWeapons() - iWeaponSlotsInUse)) - (bHasLauncher ? 0 : 1)); #endif // Try to position the empty slots CVector vWeaponPos; SDeviceDesc DeviceDesc; if (pClass->FindDeviceSlotDesc(devPrimaryWeapon, &DeviceDesc)) vWeaponPos = pClass->GetPosOffset(DeviceDesc.iPosAngle, DeviceDesc.iPosRadius, DeviceDesc.iPosZ, DeviceDesc.b3DPosition); for (i = 0; i < iEmptySlots; i++) { // Find a position if (FindLayoutForPos(vWeaponPos, SlotStatus, &iIndex)) { const SLayoutDesc *pLayout = &g_MiscDevicesLayout[iIndex]; SEntry *pEntry = m_Regions.Insert(); pEntry->iType = typeEmptySlot; pEntry->iSlotType = devPrimaryWeapon; pEntry->iSlotPosIndex = iIndex; pEntry->rcRect.left = pLayout->xLeft; pEntry->rcRect.top = pLayout->yTop; pEntry->rcRect.right = pEntry->rcRect.left + ITEM_ENTRY_WIDTH; pEntry->rcRect.bottom = pEntry->rcRect.top + ITEM_ENTRY_HEIGHT; SlotStatus[iIndex] = false; } } }
void CAeonEngine::MsgGetRows (const SArchonMessage &Msg, const CHexeSecurityCtx *pSecurityCtx) // MsgGetRows // // Aeon.getRows {tableAndView} {key} {count} // Aeon.getMoreRows {tableAndView} {lastKey} {count} { int i; CAeonTable *pTable; DWORD dwViewID; if (!ParseTableAndView(Msg, pSecurityCtx, Msg.dPayload.GetElement(0), &pTable, &dwViewID)) return; // Get the row limits int iRowCount; TArray<int> Limits; CDatum dLimits = Msg.dPayload.GetElement(2); if (dLimits.IsNil()) iRowCount = -1; else if (dLimits.GetCount() <= 1) { iRowCount = (int)dLimits.GetElement(0); if (iRowCount <= 0) iRowCount = -1; } else { iRowCount = (int)dLimits.GetElement(0); if (iRowCount <= 0) iRowCount = -1; Limits.InsertEmpty(dLimits.GetCount() - 1); for (i = 1; i < dLimits.GetCount(); i++) Limits[i - 1] = (int)dLimits.GetElement(i); } // Set up flags and options DWORD dwFlags = 0; dwFlags |= (strEquals(Msg.sMsg, MSG_AEON_GET_ROWS) ? 0 : CAeonTable::FLAG_MORE_ROWS); CDatum dOptions = Msg.dPayload.GetElement(3); for (i = 0; i < dOptions.GetCount(); i++) { if (strEquals(dOptions.GetElement(i), OPTION_INCLUDE_KEY)) dwFlags |= CAeonTable::FLAG_INCLUDE_KEY; else if (strEquals(dOptions.GetElement(i), OPTION_NO_KEY)) dwFlags |= CAeonTable::FLAG_NO_KEY; else { SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, strPattern(ERR_INVALID_GET_ROWS_OPTION, Msg.sMsg, dOptions.GetElement(i).AsString()), Msg); return; } } // Ask the table CDatum dResult; CString sError; if (!pTable->GetRows(dwViewID, Msg.dPayload.GetElement(1), iRowCount, Limits, dwFlags, &dResult, &sError)) { SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, sError, Msg); return; } // Done SendMessageReply(MSG_REPLY_DATA, dResult, Msg); }