void CSovereign::InitRelationships (void) // InitRelationships // // Initialize relationships from XML element { int i; DeleteRelationships(); if (m_pInitialRelationships) { for (i = 0; i < m_pInitialRelationships->GetContentElementCount(); i++) { CXMLElement *pRelDesc = m_pInitialRelationships->GetContentElement(i); CSovereign *pTarget = g_pUniverse->FindSovereign(pRelDesc->GetAttributeInteger(SOVEREIGN_ATTRIB)); if (pTarget) { CString sDisposition = pRelDesc->GetAttribute(DISPOSITION_ATTRIB); if (strEquals(sDisposition, DISP_FRIEND)) SetDispositionTowards(pTarget, dispFriend); else if (strEquals(sDisposition, DISP_NEUTRAL)) SetDispositionTowards(pTarget, dispNeutral); else if (strEquals(sDisposition, DISP_ENEMY)) SetDispositionTowards(pTarget, dispEnemy); } } } }
ALERROR CEffectVariantCreator::OnEffectCreateFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc, const CString &sUNID) // OnEffectCreateFromXML // // Creates from XML { ALERROR error; int i; // Allocate the creator array int iCount = pDesc->GetContentElementCount(); if (iCount == 0) { Ctx.sError = CONSTLIT("<Variants> effect must have at least one sub-element."); return ERR_FAIL; } m_Effects.InsertEmpty(iCount); for (i = 0; i < iCount; i++) { CString sSubUNID = strPatternSubst(CONSTLIT("%s/%d"), sUNID, i); CXMLElement *pCreatorDesc = pDesc->GetContentElement(i); if (error = CEffectCreator::CreateFromXML(Ctx, pCreatorDesc, sSubUNID, &m_Effects[i].pEffect)) return error; m_Effects[i].iMaxValue = pCreatorDesc->GetAttributeInteger(MAX_VALUE_ATTRIB); } return NOERROR; }
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; }
bool AddTrait (CNPWorld *pWorld, CXMLElement *pTraitTable, CXMLElement *pTrait, CSymbolTable &Symbols) { int i; // First check to see if the world has any of the traits // listed in the "unless" sections for (i = 0; i < pTrait->GetContentElementCount(); i++) { CXMLElement *pUnless = pTrait->GetContentElement(i); if (strCompare(pUnless->GetTag(), CONSTLIT("Unless")) != 0) continue; // If the world has the prohibited trait then we cannot // add the desired trait. if (pWorld->HasTrait(GetSymbolicAttribute(Symbols, pUnless, CONSTLIT("Trait")))) return false; } // Add the trait pWorld->SetTrait(GetSymbolicAttribute(Symbols, pTrait, CONSTLIT("Trait"))); // Add any traits that are implied by this trait for (i = 0; i < pTrait->GetContentElementCount(); i++) { CXMLElement *pImply = pTrait->GetContentElement(i); if (strCompare(pImply->GetTag(), CONSTLIT("Imply")) != 0) continue; // Random chance of actually having this trait if (mathRandom(1, 100) > pImply->GetAttributeInteger(CONSTLIT("Prob"))) continue; // If we already have this trait the don't bother if (pWorld->HasTrait(GetSymbolicAttribute(Symbols, pImply, CONSTLIT("Trait")))) continue; // Look for the implied trait in the table CXMLElement *pNewTrait = FindTraitInTable(pTraitTable, pImply->GetAttribute(CONSTLIT("Trait"))); // Add it. Note that we don't care if we cannot if (pNewTrait) AddTrait(pWorld, pTraitTable, pNewTrait, Symbols); } return true; }
ALERROR CShapeEffectCreator::OnEffectCreateFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc, const CString &sUNID) // OnEffectCreateFromXML // // Load from XML { int i; CString sAttrib; m_iWidth = pDesc->GetAttributeInteger(SCALE_WIDTH_ATTRIB); m_iLength = pDesc->GetAttributeInteger(SCALE_LENGTH_ATTRIB); m_bDirectional = pDesc->GetAttributeBool(DIRECTIONAL_ATTRIB); m_iWidthInc = pDesc->GetAttributeInteger(SCALE_WIDTH_INC_ATTRIB); m_iLengthInc = pDesc->GetAttributeInteger(SCALE_LENGTH_INC_ATTRIB); m_wColor = ::LoadRGBColor(pDesc->GetAttribute(COLOR_ATTRIB)); if (pDesc->FindAttribute(OPACITY_ATTRIB, &sAttrib)) m_byOpacity = strToInt(sAttrib, 255); else m_byOpacity = 255; // Initialize the points structure m_iPointCount = pDesc->GetContentElementCount(); if (m_iPointCount > 0) { m_Points = new SPoint [m_iPointCount]; m_TransBuffer = new SPoint [m_iPointCount]; for (i = 0; i < m_iPointCount; i++) { CXMLElement *pPointDesc = pDesc->GetContentElement(i); if (!strEquals(pPointDesc->GetTag(), POINT_TAG)) { Ctx.sError = CONSTLIT("<Point> element expected"); return ERR_FAIL; } m_Points[i].x = pPointDesc->GetAttributeInteger(X_ATTRIB); m_Points[i].y = pPointDesc->GetAttributeInteger(Y_ATTRIB); } // Convex polygons (which remain convex no matter the rotation) can be // computed faster with an optimized algorithm, so we keep track here. m_bConvexPolygon = IsConvexPolygon(m_iPointCount, m_Points); } else { m_Points = NULL; m_TransBuffer = NULL; m_bConvexPolygon = true; } return NOERROR; }
ALERROR CSovereign::OnCreateFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc) // OnCreateFromXML // // Create from XML { int i; // Initialize m_sName = pDesc->GetAttribute(CONSTLIT(g_NameAttrib)); // Alignment CString sAlignment = pDesc->GetAttribute(ALIGNMENT_ATTRIB); if (strEquals(sAlignment, CONSTRUCTIVE_CHAOS_ALIGN)) m_iAlignment = alignConstructiveChaos; else if (strEquals(sAlignment, CONSTRUCTIVE_ORDER_ALIGN)) m_iAlignment = alignConstructiveOrder; else if (strEquals(sAlignment, NEUTRAL_ALIGN)) m_iAlignment = alignNeutral; else if (strEquals(sAlignment, DESTRUCTIVE_ORDER_ALIGN)) m_iAlignment = alignDestructiveOrder; else if (strEquals(sAlignment, DESTRUCTIVE_CHAOS_ALIGN)) m_iAlignment = alignDestructiveChaos; else return ERR_FAIL; // Load language CXMLElement *pLanguage = pDesc->GetContentElementByTag(LANGUAGE_TAG); if (pLanguage) { int iCount = pLanguage->GetContentElementCount(); for (i = 0; i < iCount; i++) { CXMLElement *pItem = pLanguage->GetContentElement(i); CString *pText = new CString(pItem->GetAttribute(TEXT_ATTRIB)); DWORD dwID = pItem->GetAttributeInteger(ID_ATTRIB); if (dwID != 0) m_Language.AddEntry(dwID, pText); } } // Load relationships m_pInitialRelationships = pDesc->GetContentElementByTag(RELATIONSHIPS_TAG); if (m_pInitialRelationships) m_pInitialRelationships = m_pInitialRelationships->OrphanCopy(); // Done return NOERROR; }
void CDockingPorts::InitPortsFromXML (CSpaceObject *pOwner, CXMLElement *pElement) // InitPortsFromXML // // InitPortsFromXML { // See if we've got a special element with docking port geometry CXMLElement *pDockingPorts = pElement->GetContentElementByTag(DOCKING_PORTS_TAG); if (pDockingPorts) { m_iPortCount = pDockingPorts->GetContentElementCount(); if (m_iPortCount > 0) { m_pPort = new DockingPort[m_iPortCount]; for (int i = 0; i < m_iPortCount; i++) { CXMLElement *pPort = pDockingPorts->GetContentElement(i); CVector vDockPos((pPort->GetAttributeInteger(X_ATTRIB) * g_KlicksPerPixel), (pPort->GetAttributeInteger(Y_ATTRIB) * g_KlicksPerPixel)); m_pPort[i].iStatus = psEmpty; m_pPort[i].pObj = NULL; m_pPort[i].vPos = vDockPos; m_pPort[i].iRotation = (VectorToPolar(vDockPos) + 180) % 360; } } } // Otherwise, initialize ports based on a count else InitPorts(pOwner, pElement->GetAttributeInteger(DOCKING_PORTS_ATTRIB), 64 * g_KlicksPerPixel); }
ALERROR CUniverse::InitSounds (SDesignLoadCtx &Ctx, CXMLElement *pSounds, CResourceDb &Resources) // InitSounds // // Loads sound resources { ALERROR error; // Nothing to do if we don't want sound resources if (m_pSoundMgr == NULL || Ctx.bNoResources) return NOERROR; // Figure out if we've got a special folder for the resources CString sRoot = pSounds->GetAttribute(FOLDER_ATTRIB); // Loop over all sound resources for (int i = 0; i < pSounds->GetContentElementCount(); i++) { CXMLElement *pItem = pSounds->GetContentElement(i); DWORD dwUNID = (DWORD)pItem->GetAttributeInteger(UNID_ATTRIB); CString sFilename = pItem->GetAttribute(FILENAME_ATTRIB); int iChannel; // Load the resource if (error = Resources.LoadSound(*m_pSoundMgr, sRoot, sFilename, &iChannel)) { Ctx.sError = strPatternSubst(CONSTLIT("Unable to load sound file: %s"), sFilename); return error; } // Add to our map if (error = m_Sounds.AddEntry((int)dwUNID, (CObject *)iChannel)) { Ctx.sError = strPatternSubst(CONSTLIT("Unable to add sound file: %x"), dwUNID); return error; } } return NOERROR; }
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 CGroupOfGenerators::LoadFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc) // LoadFromXML // // Load from XML { int i; ALERROR error; m_iCount = pDesc->GetContentElementCount(); if (m_iCount > 0) { m_Table = new SEntry [m_iCount]; utlMemSet(m_Table, sizeof(SEntry) * m_iCount, 0); for (i = 0; i < m_iCount; 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; } } else m_Table = NULL; 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 CAdventureDesc::OnCreateFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc) // OnCreateFromXML // // Load from XML { ALERROR error; int i; // If we are part of the default resource, then get the adventure UNID if (Ctx.pExtension == NULL) { m_dwExtensionUNID = pDesc->GetAttributeInteger(ADVENTURE_UNID_ATTRIB); m_fInDefaultResource = true; } // Otherwise, we remember the extension that we were loaded from else { m_dwExtensionUNID = Ctx.pExtension->GetUNID(); m_fInDefaultResource = false; } // Load the name, etc m_sName = pDesc->GetAttribute(NAME_ATTRIB); if (error = ::LoadUNID(Ctx, pDesc->GetAttribute(BACKGROUND_ID_ATTRIB), &m_dwBackgroundUNID)) return error; // Starting ship criteria CString sCriteria; if (!pDesc->FindAttribute(STARTING_SHIP_CRITERIA_ATTRIB, &sCriteria)) sCriteria = CONSTLIT("*"); if (error = CDesignTypeCriteria::ParseCriteria(sCriteria, &m_StartingShips)) return ComposeLoadError(Ctx, ERR_STARTING_SHIP_CRITERIA); m_fIncludeOldShipClasses = pDesc->GetAttributeBool(INCLUDE_10_STARTING_CLASSES_ATTRIB); // Starting position m_sStartingNodeID = pDesc->GetAttribute(STARTING_SYSTEM_ATTRIB); m_sStartingPos = pDesc->GetAttribute(STARTING_POS_ATTRIB); // Welcome message if (!pDesc->FindAttribute(WELCOME_MESSAGE_ATTRIB, &m_sWelcomeMessage)) m_sWelcomeMessage = CONSTLIT("Welcome to Transcendence!"); // Init some flags m_fIsCurrentAdventure = false; // If we don't have a name, then get it from the extension if (m_sName.IsBlank()) { if (Ctx.pExtension) m_sName = Ctx.pExtension->GetName(); } // Otherwise, if the extension doesn't have a name, then we can set it else if (Ctx.pExtension && strFind(Ctx.pExtension->GetName(), CONSTLIT("Extension")) == 0) Ctx.pExtension->SetName(m_sName); // Initialize armor and shield damage adjustment tables InitDefaultDamageAdj(); for (i = 1; i <= MAX_ITEM_LEVEL; i++) { m_ArmorDamageAdj[i - 1] = g_ArmorDamageAdj[i - 1]; m_ShieldDamageAdj[i - 1] = g_ShieldDamageAdj[i - 1]; } // Load constants CXMLElement *pConstants = pDesc->GetContentElementByTag(CONSTANTS_TAG); if (pConstants) { for (i = 0; i < pConstants->GetContentElementCount(); i++) { CXMLElement *pItem = pConstants->GetContentElement(i); if (strEquals(pItem->GetTag(), ARMOR_DAMAGE_ADJ_TAG)) { int iLevel = pItem->GetAttributeInteger(LEVEL_ATTRIB); if (iLevel < 1 || iLevel > MAX_ITEM_LEVEL) { Ctx.sError = strPatternSubst(CONSTLIT("Invalid level: %d."), iLevel); return ERR_FAIL; } if (error = m_ArmorDamageAdj[iLevel - 1].InitFromXML(Ctx, pItem, true)) return error; } else if (strEquals(pItem->GetTag(), SHIELD_DAMAGE_ADJ_TAG)) { int iLevel = pItem->GetAttributeInteger(LEVEL_ATTRIB); if (iLevel < 1 || iLevel > MAX_ITEM_LEVEL) { Ctx.sError = strPatternSubst(CONSTLIT("Invalid level: %d."), iLevel); return ERR_FAIL; } if (error = m_ShieldDamageAdj[iLevel - 1].InitFromXML(Ctx, pItem, true)) return error; } else { Ctx.sError = strPatternSubst(CONSTLIT("Invalid constant definition element: %s."), pItem->GetTag()); return ERR_FAIL; } } } return NOERROR; }
ALERROR CNPUniverse::LoadClassesFromXML (CXMLElement *pTemplate, CSymbolTable &Symbols, CString *retsError) // LoadClassesFromXML // // Loads the unit classes, etc. { ALERROR error; CXMLElement *pSection; CXMLElement *pTable; int i; // Load universal constants section if ((pSection = FindElement(pTemplate, CONSTLIT("DefineUniversalConstants"), retsError)) == NULL) return ERR_FAIL; // Load tech table if ((pTable = FindElement(pSection, CONSTLIT("TechTable"), retsError)) == NULL) return ERR_FAIL; if (pTable->GetContentElementCount() != techCount - 1) { *retsError = CONSTLIT("<TechTable> does not have the right number of entries."); return ERR_FAIL; } for (i = 0; i < pTable->GetContentElementCount(); i++) { CXMLElement *pEntry = pTable->GetContentElement(i); m_TechTable[i + 1].sName = pEntry->GetAttribute(CONSTLIT("Name")); m_TechTable[i + 1].iProductionFactor = pEntry->GetAttributeInteger(CONSTLIT("Prod")); m_TechTable[i + 1].iStdLivingFactor = pEntry->GetAttributeInteger(CONSTLIT("StdLiving")); m_TechTable[i + 1].iPollutionFactor = pEntry->GetAttributeInteger(CONSTLIT("Pollution")); } // Load unit classes if ((pSection = FindElement(pTemplate, CONSTLIT("DefineUnitClasses"), retsError)) == NULL) return ERR_FAIL; for (i = 0; i < pSection->GetContentElementCount(); i++) { CNPUnitClass *pClass = new CNPUnitClass; if (pClass == NULL) { *retsError = CONSTLIT("Out of memory"); return ERR_FAIL; } if (error = pClass->LoadFromXML(pSection->GetContentElement(i), Symbols)) { *retsError = CONSTLIT("Unable to load unit class"); return ERR_FAIL; } m_UnitClasses.SetEntry(pClass->GetUNID(), pClass); } // Get the default sovereign if ((pSection = FindElement(pTemplate, CONSTLIT("DefineSovereigns"), retsError)) == NULL) return ERR_FAIL; if ((m_pPlayerTemplate = FindElement(pSection, CONSTLIT("DefineDefaultPlayer"), retsError)) == NULL) return ERR_FAIL; m_pPlayerTemplate = m_pPlayerTemplate->OrphanCopy(); return NOERROR; }
ALERROR CNPUniverse::InitFromXML (CXMLElement *pTemplate, CSymbolTable &Symbols, CString *retsError) // InitFromXML // // Initializes from an XML template { ALERROR error; int iNullPoints; CreateCtx Ctx; // Initialize context Ctx.pTemplate = pTemplate; Ctx.pSymbols = &Symbols; // Get some elements CXMLElement *pOptions = pTemplate->GetContentElementByTag(CONSTLIT("DefineOptions")); // Initialize iNullPoints = pOptions->GetAttributeInteger(CONSTLIT("NullPointCount")); m_iMaxPlayers = pOptions->GetAttributeInteger(CONSTLIT("MaxPlayers")); m_iBaseAnno = pOptions->GetAttributeInteger(CONSTLIT("BaseAnno")); m_iTurn = 0; // Create the Overlord sovereign CNPSovereign *pOverlord; if (error = CreateSovereign(LITERAL("The Universe"), NULL, NULL, &pOverlord)) { *retsError = LITERAL("Unable to create Overlord sovereign"); return error; } m_dwOverlord = pOverlord->GetUNID(); // Create the default, independent sovereign CNPSovereign *pIndep; if (error = CreateSovereign(LITERAL("Independent"), NULL, NULL, &pIndep)) { *retsError = LITERAL("Unable to create independent sovereign"); return error; } m_dwIndependent = pIndep->GetUNID(); // Create the null point network. if (error = CreateNullPointNetwork(iNullPoints)) { *retsError = LITERAL("Unable to create null point network"); return error; } // Create worlds if (error = CreateRandomWorlds(Ctx)) { *retsError = LITERAL("Unable to create worlds"); return error; } // Next turn m_dwNextTurn = ::GetTickCount() + (DWORD)(SecondsPerOro * 1000); return NOERROR; }
ALERROR CNPUniverse::CreateSovereign (CString sName, CNPWorld *pCapital, CXMLElement *pSovTemplate, CNPSovereign **retpSovereign) // CreateSovereign // // Creates a new sovereign { ALERROR error; CNPSovereign *pSovereign; int i; if (error = CNPSovereign::Create(m_Sovereigns.RegisterEntry(), sName, &pSovereign)) return error; m_Sovereigns.SetEntry(pSovereign->GetUNID(), pSovereign); // Obviously we know about ourselves pSovereign->SetKnowledge(pSovereign->GetUNID()); // Set a capital if (pCapital) { pSovereign->SetCapital(pCapital->GetUNID()); pCapital->RemoveTrait(traitReservedCapital); pCapital->SetTrait(traitCapital); pCapital->SetSovereign(pSovereign); // Scan the capital CNPNullPoint *pNP = GetNullPoint(pCapital->GetLocation()); ScanNullPoint(pSovereign, pNP, 1); // Scan the area around the capital for (i = 0; i < pNP->GetLinkCount(); i++) { CNPNullPoint *pDest = pNP->GetLinkDest(i); ScanNullPoint(pSovereign, pDest, 1); } // Create ships if (pSovTemplate) { CNPFleet *pFleet = NULL; for (i = 0; i < pSovTemplate->GetContentElementCount(); i++) { CXMLElement *pShip = pSovTemplate->GetContentElement(i); if (strCompare(pShip->GetTag(), CONSTLIT("Unit")) == 0) { // Create the fleet, if needed if (pFleet == NULL) if (error = CreateFleet(pNP, pSovereign, &pFleet)) return error; // Add the ship to the fleet CNPUnit Unit(pShip->GetAttributeInteger(CONSTLIT("Class")), 0, 0); pFleet->GetAssetList().AddUnit(Unit); } } } } // Done if (retpSovereign) *retpSovereign = pSovereign; return NOERROR; }
ALERROR CNPUniverse::CreateRandomWorld (CreateCtx &Ctx, CNPNullPoint *pNP, CNPSovereign *pSovereign) // CreateRandomWorld // // Creates a random world at the given null point { ALERROR error; CNPWorld *pWorld; int i, iRoll; // Create the world if (error = CNPWorld::Create(m_Worlds.RegisterEntry(), pNP->GetUNID(), pSovereign, &pWorld)) { Ctx.sError = LITERAL("Out of memory"); return error; } m_Worlds.SetEntry(pWorld->GetUNID(), pWorld); // Add to the null point if (error = pNP->AddWorld(pWorld)) { delete pWorld; Ctx.sError = LITERAL("Out of memory"); return error; } // Add some traits to the world CXMLElement *pTraitTable = Ctx.pTemplate->GetContentElementByTag(CONSTLIT("DefineWorldTraitTable")); if (mathRandom(1, 100) <= 20) AddRandomTrait(Ctx, pWorld, ttMajorDisadvantage, 1, pTraitTable); if (mathRandom(1, 100) <= 35) AddRandomTrait(Ctx, pWorld, ttMinorDisadvantage, 1, pTraitTable); if (mathRandom(1, 100) <= 20) AddRandomTrait(Ctx, pWorld, ttMinorDisadvantage, 1, pTraitTable); if (mathRandom(1, 100) <= 20) AddRandomTrait(Ctx, pWorld, ttMajorAdvantage, 1, pTraitTable); if (mathRandom(1, 100) <= 35) AddRandomTrait(Ctx, pWorld, ttMinorAdvantage, 1, pTraitTable); if (mathRandom(1, 100) <= 20) AddRandomTrait(Ctx, pWorld, ttMinorAdvantage, 1, pTraitTable); // Pick a tech level for the world CXMLElement *pTechTable = Ctx.pTemplate->GetContentElementByTag(CONSTLIT("DefineWorldTechLevelTable")); iRoll = mathRandom(1, 100); NPTechLevels iMinTech = pWorld->GetMinTech(); for (i = 0; i < pTechTable->GetContentElementCount(); i++) { CXMLElement *pEntry = pTechTable->GetContentElement(i); int iProb = pEntry->GetAttributeInteger(CONSTLIT("Prob")); if (iRoll <= iProb) { NPTechLevels iTechLevel = (NPTechLevels)GetSymbolicAttribute(*Ctx.pSymbols, pEntry, CONSTLIT("Tech")); // Make sure this tech level is appropriate for the world while (iTechLevel < iMinTech) iTechLevel = (NPTechLevels)(iTechLevel + 1); pWorld->SetTechLevel(iTechLevel); break; } iRoll -= iProb; } // Set the initial population int iPopulation = 0; switch (pWorld->GetTechLevel()) { case techAgricultural: iPopulation = mathRandom(250, 750); break; case techSteam: case techCyber: { for (i = 0; i < 12; i++) iPopulation += mathRandom(0, 500); break; } case techBio: { for (i = 0; i < 10; i++) iPopulation += mathRandom(0, 1000); break; } case techFusion: case techAI: { for (i = 0; i < 8; i++) iPopulation += mathRandom(0, 1600); break; } default: { for (i = 0; i < 10; i++) iPopulation += mathRandom(0, 2000); break; } } pWorld->SetPopulation((1000 * iPopulation) + mathRandom(-500, 500)); // Set the efficiency pWorld->SetEfficiency(25 + mathRandom(0, 25) + mathRandom(0, 25) + mathRandom(0, 25)); // Figure out if this world is a suitable candidate for a capital if (IsWorldSuitableAsCapital(this, pWorld)) pWorld->SetTrait(traitReservedCapital); return NOERROR; }
ALERROR CPlayerSettings::InitFromXML (SDesignLoadCtx &Ctx, CShipClass *pClass, CXMLElement *pDesc) // InitFromXML // // Initialize from an XML element { ALERROR error; int i; m_sDesc = pDesc->GetAttribute(DESC_ATTRIB); if (error = LoadUNID(Ctx, pDesc->GetAttribute(LARGE_IMAGE_ATTRIB), &m_dwLargeImage)) return error; m_fDebug = pDesc->GetAttributeBool(DEBUG_ONLY_ATTRIB); CString sInitialClass = pDesc->GetAttribute(INITIAL_CLASS_ATTRIB); if (strEquals(sInitialClass, CONSTLIT("always"))) { m_fInitialClass = true; m_fIncludeInAllAdventures = true; } else { m_fInitialClass = CXMLElement::IsBoolTrueValue(sInitialClass); m_fIncludeInAllAdventures = false; } m_fHasArmorDesc = false; m_fHasReactorDesc = false; m_fHasShieldDesc = false; // Some ship capabilities bool bValue; if (pDesc->FindAttributeBool(AUTOPILOT_ATTRIB, &bValue)) m_fAutopilot = bValue; else m_fAutopilot = true; // Load some miscellaneous data CString sAttrib; if (!pDesc->FindAttribute(STARTING_CREDITS_ATTRIB, &sAttrib)) sAttrib = CONSTLIT("5d20+200"); if (error = m_StartingCredits.InitFromXML(Ctx, sAttrib)) return error; m_sStartNode = pDesc->GetAttribute(STARTING_SYSTEM_ATTRIB); m_sStartPos = pDesc->GetAttribute(STARTING_POS_ATTRIB); if (m_sStartPos.IsBlank()) m_sStartPos = CONSTLIT("Start"); // Load the ship screen CString sShipScreenUNID = pDesc->GetAttribute(SHIP_SCREEN_ATTRIB); if (sShipScreenUNID.IsBlank()) sShipScreenUNID = strFromInt(DEFAULT_SHIP_SCREEN_UNID, false); m_pShipScreen.LoadUNID(Ctx, sShipScreenUNID); // Load the armor display data CXMLElement *pArmorDisplay = pDesc->GetContentElementByTag(ARMOR_DISPLAY_TAG); if (pArmorDisplay && pArmorDisplay->GetContentElementCount() > 0) { // Loop over all sub elements for (i = 0; i < pArmorDisplay->GetContentElementCount(); i++) { CXMLElement *pSub = pArmorDisplay->GetContentElement(i); if (strEquals(pSub->GetTag(), ARMOR_SECTION_TAG)) { SArmorSegmentImageDesc &ArmorDesc = *m_ArmorDesc.Segments.Insert(); if (error = ArmorDesc.Image.InitFromXML(Ctx, pSub)) return ComposeLoadError(Ctx, ERR_ARMOR_DISPLAY_NEEDED); ArmorDesc.sName = pSub->GetAttribute(NAME_ATTRIB); ArmorDesc.xDest = pSub->GetAttributeInteger(DEST_X_ATTRIB); ArmorDesc.yDest = pSub->GetAttributeInteger(DEST_Y_ATTRIB); ArmorDesc.xHP = pSub->GetAttributeInteger(HP_X_ATTRIB); ArmorDesc.yHP = pSub->GetAttributeInteger(HP_Y_ATTRIB); ArmorDesc.yName = pSub->GetAttributeInteger(NAME_Y_ATTRIB); ArmorDesc.cxNameBreak = pSub->GetAttributeInteger(NAME_BREAK_WIDTH); ArmorDesc.xNameDestOffset = pSub->GetAttributeInteger(NAME_DEST_X_ATTRIB); ArmorDesc.yNameDestOffset = pSub->GetAttributeInteger(NAME_DEST_Y_ATTRIB); } else if (strEquals(pSub->GetTag(), SHIP_IMAGE_TAG)) { if (error = m_ArmorDesc.ShipImage.InitFromXML(Ctx, pSub)) return ComposeLoadError(Ctx, ERR_SHIP_IMAGE_NEEDED); } else return ComposeLoadError(Ctx, strPatternSubst(CONSTLIT("Unknown ArmorDisplay element: "), pSub->GetTag())); } m_fHasArmorDesc = true; } else m_fHasArmorDesc = false; // Load shield display data CXMLElement *pShieldDisplay = pDesc->GetContentElementByTag(SHIELD_DISPLAY_TAG); if (pShieldDisplay) { // Load the new shield effect if (error = m_ShieldDesc.pShieldEffect.LoadEffect(Ctx, strPatternSubst(CONSTLIT("%d:p:s"), pClass->GetUNID()), pShieldDisplay->GetContentElementByTag(SHIELD_EFFECT_TAG), pShieldDisplay->GetAttribute(SHIELD_EFFECT_ATTRIB))) return error; // If we don't have the new effect, load the backwards compatibility // image. if (m_ShieldDesc.pShieldEffect.IsEmpty()) { if (error = m_ShieldDesc.Image.InitFromXML(Ctx, pShieldDisplay->GetContentElementByTag(IMAGE_TAG))) return ComposeLoadError(Ctx, ERR_SHIELD_DISPLAY_NEEDED); } m_fHasShieldDesc = true; } // If we have a shield effect then we must have an armor image if (!m_ShieldDesc.pShieldEffect.IsEmpty() && m_ArmorDesc.ShipImage.GetBitmapUNID() == 0) return ComposeLoadError(Ctx, ERR_MUST_HAVE_SHIP_IMAGE); // Load reactor display data CXMLElement *pReactorDisplay = pDesc->GetContentElementByTag(REACTOR_DISPLAY_TAG); if (pReactorDisplay) { if (error = m_ReactorDesc.ReactorImage.InitFromXML(Ctx, pReactorDisplay->GetContentElementByTag(IMAGE_TAG))) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); CXMLElement *pImage = pReactorDisplay->GetContentElementByTag(POWER_LEVEL_IMAGE_TAG); if (pImage == NULL || (error = m_ReactorDesc.PowerLevelImage.InitFromXML(Ctx, pImage))) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); m_ReactorDesc.xPowerLevelImage = pImage->GetAttributeInteger(DEST_X_ATTRIB); m_ReactorDesc.yPowerLevelImage = pImage->GetAttributeInteger(DEST_Y_ATTRIB); pImage = pReactorDisplay->GetContentElementByTag(FUEL_LEVEL_IMAGE_TAG); if (pImage == NULL || (error = m_ReactorDesc.FuelLevelImage.InitFromXML(Ctx, pImage))) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); m_ReactorDesc.xFuelLevelImage = pImage->GetAttributeInteger(DEST_X_ATTRIB); m_ReactorDesc.yFuelLevelImage = pImage->GetAttributeInteger(DEST_Y_ATTRIB); pImage = pReactorDisplay->GetContentElementByTag(FUEL_LOW_LEVEL_IMAGE_TAG); if (pImage == NULL || (error = m_ReactorDesc.FuelLowLevelImage.InitFromXML(Ctx, pImage))) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); if (error = InitRectFromElement(pReactorDisplay->GetContentElementByTag(REACTOR_TEXT_TAG), &m_ReactorDesc.rcReactorText)) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); if (error = InitRectFromElement(pReactorDisplay->GetContentElementByTag(POWER_LEVEL_TEXT_TAG), &m_ReactorDesc.rcPowerLevelText)) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); if (error = InitRectFromElement(pReactorDisplay->GetContentElementByTag(FUEL_LEVEL_TEXT_TAG), &m_ReactorDesc.rcFuelLevelText)) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); m_fHasReactorDesc = true; } // Done return NOERROR; }
ALERROR CNPUniverse::AddRandomTrait (CreateCtx &Ctx, CNPWorld *pWorld, TraitType iSection, int iCount, CXMLElement *pTraitTable) // AddRandomTrait // // Adds traits from the given table { int iSectionStart; // Find the beginning of the section iSectionStart = 0; while (iSectionStart < pTraitTable->GetContentElementCount() && pTraitTable->GetContentElement(iSectionStart)->GetAttributeInteger(CONSTLIT("Table")) != iSection) iSectionStart++; // If not found, we fail if (iSectionStart == pTraitTable->GetContentElementCount()) { Ctx.sError = LITERAL("Unable to find appropriate trait table section"); return ERR_FAIL; } // Keep looping for each trait to add for (int i = 0; i < iCount; i++) { // Keep trying until we successfully add some trait or // until we get sick of trying. for (int j = 0; j < 10; j++) { int iRoll = mathRandom(1, 100); int iEntry = iSectionStart; CXMLElement *pEntry; while (iEntry < pTraitTable->GetContentElementCount() && (pEntry = pTraitTable->GetContentElement(iEntry)) && (pEntry->GetAttributeInteger(CONSTLIT("Table")) == iSection) && (iRoll = iRoll - pEntry->GetAttributeInteger(CONSTLIT("Prob"))) > 0) iEntry++; // If not found, we fail if (iRoll > 0) { Ctx.sError = LITERAL("Trait table probabilities do not add up to 100%"); return ERR_FAIL; } // Add the trait. If we add it successfully then we stop // the inner loop. if (AddTrait(pWorld, pTraitTable, pEntry, *Ctx.pSymbols)) break; } } return NOERROR; }
void InitStationTypeImage (SEntryDesc &Entry, CStationType *pStationType) { struct SSatImageDesc { const CObjectImageArray *pImage; CCompositeImageSelector Selector; int xOffset; int yOffset; }; int i; SSelectorInitCtx InitCtx; pStationType->SetImageSelector(InitCtx, &Entry.Selector); const CObjectImageArray *pMainImage = &pStationType->GetImage(Entry.Selector, CCompositeImageModifiers()); // If we have no satellites, then we can just return the single station // image. CXMLElement *pSatellites = pStationType->GetSatellitesDesc(); if (pSatellites == NULL) { Entry.pImage = pMainImage; return; } // Figure out the extents of the image RECT rcMainImage = pMainImage->GetImageRect(); RECT rcBounds; rcBounds.left = -(RectWidth(rcMainImage) / 2); rcBounds.top = -(RectHeight(rcMainImage) / 2); rcBounds.right = rcBounds.left + RectWidth(rcMainImage); rcBounds.bottom = rcBounds.top + RectHeight(rcMainImage); // Loop over all satellites and get metrics TArray<SSatImageDesc> SatImages; for (i = 0; i < pSatellites->GetContentElementCount(); i++) { CXMLElement *pSatDesc = pSatellites->GetContentElement(i); if (!pSatDesc->FindAttribute(SEGMENT_ATTRIB) || !strEquals(STATION_TAG, pSatDesc->GetTag())) continue; // Get the type of the satellite CStationType *pSatType = g_pUniverse->FindStationType(pSatDesc->GetAttributeInteger(TYPE_ATTRIB)); if (pSatType == NULL) continue; // Prepare the image for the satellite SSatImageDesc *pSatImage = SatImages.Insert(); pSatType->SetImageSelector(InitCtx, &pSatImage->Selector); // If we have an image variant, then set it int iVariant; if (pSatDesc->FindAttributeInteger(IMAGE_VARIANT_ATTRIB, &iVariant)) { IImageEntry *pRoot = pSatType->GetImage().GetRoot(); DWORD dwID = (pRoot ? pRoot->GetID() : DEFAULT_SELECTOR_ID); pSatImage->Selector.DeleteAll(); pSatImage->Selector.AddVariant(dwID, iVariant); } pSatImage->pImage = &pSatType->GetImage(pSatImage->Selector, CCompositeImageModifiers()); // Now get the offset pSatImage->xOffset = pSatDesc->GetAttributeInteger(X_OFFSET_ATTRIB); pSatImage->yOffset = pSatDesc->GetAttributeInteger(Y_OFFSET_ATTRIB); // Compute the satellite rect RECT rcSatImage = pSatImage->pImage->GetImageRect(); RECT rcSatBounds; rcSatBounds.left = pSatImage->xOffset - (RectWidth(rcSatImage) / 2); rcSatBounds.top = -pSatImage->yOffset - (RectHeight(rcSatImage) / 2); rcSatBounds.right = rcSatBounds.left + RectWidth(rcSatImage); rcSatBounds.bottom = rcSatBounds.top + RectHeight(rcSatImage); // Increase the size of the bounds rcBounds.left = Min(rcBounds.left, rcSatBounds.left); rcBounds.right = Max(rcBounds.right, rcSatBounds.right); rcBounds.top = Min(rcBounds.top, rcSatBounds.top); rcBounds.bottom = Max(rcBounds.bottom, rcSatBounds.bottom); } // If no segments, then we just return the basic image if (SatImages.GetCount() == 0) { Entry.pImage = pMainImage; return; } // Create an image that will hold the composite CG32bitImage *pCompositeImage = new CG32bitImage; pCompositeImage->Create(RectWidth(rcBounds), RectHeight(rcBounds), CG32bitImage::alpha8, CG32bitPixel::Null()); int xCenter = -rcBounds.left; int yCenter = -rcBounds.top; // Paint the main image pMainImage->PaintImage(*pCompositeImage, xCenter, yCenter, 0, Entry.iRotation, true); // Paint all the satellites for (i = 0; i < SatImages.GetCount(); i++) SatImages[i].pImage->PaintImage(*pCompositeImage, xCenter + SatImages[i].xOffset, yCenter - SatImages[i].yOffset, 0, 0, true); // Now create the proper image array RECT rcResult; rcResult.left = 0; rcResult.top = 0; rcResult.right = RectWidth(rcBounds); rcResult.bottom = RectHeight(rcBounds); int xOffset = (RectWidth(rcBounds) / 2) - xCenter; int yOffset = (RectHeight(rcBounds) / 2) - yCenter; Entry.pCompositeImageArray = new CObjectImageArray; Entry.pCompositeImageArray->Init(pCompositeImage, rcResult, 0, 0, true, xOffset, yOffset); // Done Entry.pImage = Entry.pCompositeImageArray; }
void CDockingPorts::InitPortsFromXML (CSpaceObject *pOwner, CXMLElement *pElement) // InitPortsFromXML // // InitPortsFromXML { int i; // See if we've got a special element with docking port geometry CXMLElement *pDockingPorts = pElement->GetContentElementByTag(DOCKING_PORTS_TAG); if (pDockingPorts) { // Initialize max dist // NOTE: pOwner can be NULL because sometimes we init ports from a ship class // (without an object). int iDefaultDist = Max(DEFAULT_DOCK_DISTANCE_LS, (pOwner ? 8 + (int)((pOwner->GetBoundsRadius() / LIGHT_SECOND) + 0.5) : 0)); m_iMaxDist = pDockingPorts->GetAttributeIntegerBounded(MAX_DIST_ATTRIB, 1, -1, iDefaultDist); // If we have sub-elements then these are port definitions. m_iPortCount = pDockingPorts->GetContentElementCount(); if (m_iPortCount > 0) { m_pPort = new SDockingPort[m_iPortCount]; for (i = 0; i < m_iPortCount; i++) { CXMLElement *pPort = pDockingPorts->GetContentElement(i); CVector vDockPos((pPort->GetAttributeInteger(X_ATTRIB) * g_KlicksPerPixel), (pPort->GetAttributeInteger(Y_ATTRIB) * g_KlicksPerPixel)); m_pPort[i].vPos = vDockPos; if (pPort->FindAttributeInteger(ROTATION_ATTRIB, &m_pPort[i].iRotation)) m_pPort[i].iRotation = (m_pPort[i].iRotation % 360); else m_pPort[i].iRotation = (VectorToPolar(vDockPos) + 180) % 360; if (pPort->GetAttributeBool(BRING_TO_FRONT_ATTRIB)) m_pPort[i].iLayer = plBringToFront; else if (pPort->GetAttributeBool(SEND_TO_BACK_ATTRIB)) m_pPort[i].iLayer = plSendToBack; } } // Otherwise, we expect a port count and radius else if ((m_iPortCount = pDockingPorts->GetAttributeIntegerBounded(PORT_COUNT_ATTRIB, 0, -1, 0)) > 0) { int iRadius = pDockingPorts->GetAttributeIntegerBounded(PORT_RADIUS_ATTRIB, 0, -1, DEFAULT_PORT_POS_RADIUS); int iAngle = 360 / m_iPortCount; // We need the image scale to adjust coordinates int iScale = (pOwner ? pOwner->GetImage().GetImageViewportSize() : 512); // Initialize ports m_pPort = new SDockingPort[m_iPortCount]; for (i = 0; i < m_iPortCount; i++) { C3DConversion::CalcCoord(iScale, i * iAngle, iRadius, 0, &m_pPort[i].vPos); m_pPort[i].iRotation = ((i * iAngle) + 180) % 360; } } // Otherwise, no ports else { m_iPortCount = 0; m_pPort = NULL; } } // Otherwise, initialize ports based on a count else InitPorts(pOwner, pElement->GetAttributeInteger(DOCKING_PORTS_ATTRIB), 64 * g_KlicksPerPixel); }
void CDockingPorts::InitPortsFromXML (CSpaceObject *pOwner, CXMLElement *pElement) // InitPortsFromXML // // InitPortsFromXML { int i; // See if we've got a special element with docking port geometry CXMLElement *pDockingPorts = pElement->GetContentElementByTag(DOCKING_PORTS_TAG); if (pDockingPorts) { // Initialize max dist m_iMaxDist = pDockingPorts->GetAttributeIntegerBounded(MAX_DIST_ATTRIB, 1, -1, DEFAULT_DOCK_DISTANCE_LS); // If we have sub-elements then these are port definitions. m_iPortCount = pDockingPorts->GetContentElementCount(); if (m_iPortCount > 0) { m_pPort = new DockingPort[m_iPortCount]; for (i = 0; i < m_iPortCount; i++) { CXMLElement *pPort = pDockingPorts->GetContentElement(i); CVector vDockPos((pPort->GetAttributeInteger(X_ATTRIB) * g_KlicksPerPixel), (pPort->GetAttributeInteger(Y_ATTRIB) * g_KlicksPerPixel)); m_pPort[i].iStatus = psEmpty; m_pPort[i].pObj = NULL; m_pPort[i].vPos = vDockPos; if (pPort->FindAttributeInteger(ROTATION_ATTRIB, &m_pPort[i].iRotation)) m_pPort[i].iRotation = (m_pPort[i].iRotation % 360); else m_pPort[i].iRotation = (VectorToPolar(vDockPos) + 180) % 360; } } // Otherwise, we expect a port count and radius else if ((m_iPortCount = pDockingPorts->GetAttributeIntegerBounded(PORT_COUNT_ATTRIB, 0, -1, 0)) > 0) { m_pPort = new DockingPort[m_iPortCount]; int iRadius = pDockingPorts->GetAttributeIntegerBounded(PORT_RADIUS_ATTRIB, 0, -1, DEFAULT_PORT_POS_RADIUS); Metric rRadius = g_KlicksPerPixel * iRadius; int iAngle = 360 / m_iPortCount; for (i = 0; i < m_iPortCount; i++) { m_pPort[i].iStatus = psEmpty; m_pPort[i].pObj = NULL; m_pPort[i].vPos = PolarToVector(i * iAngle, rRadius); m_pPort[i].iRotation = ((i * iAngle) + 180) % 360; } } // Otherwise, no ports else { m_iPortCount = 0; m_pPort = NULL; } } // Otherwise, initialize ports based on a count else InitPorts(pOwner, pElement->GetAttributeInteger(DOCKING_PORTS_ATTRIB), 64 * g_KlicksPerPixel); }
ALERROR CPlayerSettings::InitFromXML (SDesignLoadCtx &Ctx, CShipClass *pClass, CXMLElement *pDesc) // InitFromXML // // Initialize from an XML element { ALERROR error; int i; m_sDesc = pDesc->GetAttribute(DESC_ATTRIB); m_dwLargeImage = LoadUNID(Ctx, pDesc->GetAttribute(LARGE_IMAGE_ATTRIB)); m_fDebug = pDesc->GetAttributeBool(DEBUG_ONLY_ATTRIB); m_fInitialClass = pDesc->GetAttributeBool(INITIAL_CLASS_ATTRIB); m_fHasArmorDesc = false; m_fHasReactorDesc = false; m_fHasShieldDesc = false; // Some ship capabilities bool bValue; if (pDesc->FindAttributeBool(AUTOPILOT_ATTRIB, &bValue)) m_fAutopilot = bValue; else m_fAutopilot = true; // Load some miscellaneous data CString sAttrib; if (!pDesc->FindAttribute(STARTING_CREDITS_ATTRIB, &sAttrib)) sAttrib = CONSTLIT("5d20+200"); if (error = m_StartingCredits.InitFromXML(Ctx, sAttrib)) return error; m_sStartNode = pDesc->GetAttribute(STARTING_SYSTEM_ATTRIB); m_sStartPos = pDesc->GetAttribute(STARTING_POS_ATTRIB); if (m_sStartPos.IsBlank()) m_sStartPos = CONSTLIT("Start"); // Load the ship screen CString sShipScreenUNID = pDesc->GetAttribute(SHIP_SCREEN_ATTRIB); if (sShipScreenUNID.IsBlank()) sShipScreenUNID = strFromInt(DEFAULT_SHIP_SCREEN_UNID, FALSE); m_pShipScreen.LoadUNID(Ctx, sShipScreenUNID); // Load the armor display data CXMLElement *pArmorDisplay = pDesc->GetContentElementByTag(ARMOR_DISPLAY_TAG); if (pArmorDisplay && pArmorDisplay->GetContentElementCount() > 0) { m_iArmorDescCount = pArmorDisplay->GetContentElementCount(); m_pArmorDesc = new SArmorImageDesc [m_iArmorDescCount]; for (i = 0; i < m_iArmorDescCount; i++) { SArmorImageDesc &ArmorDesc = m_pArmorDesc[i]; CXMLElement *pSegment = pArmorDisplay->GetContentElement(i); if (error = ArmorDesc.Image.InitFromXML(Ctx, pSegment)) return ComposeLoadError(Ctx, ERR_ARMOR_DISPLAY_NEEDED); ArmorDesc.sName = pSegment->GetAttribute(NAME_ATTRIB); ArmorDesc.xDest = pSegment->GetAttributeInteger(DEST_X_ATTRIB); ArmorDesc.yDest = pSegment->GetAttributeInteger(DEST_Y_ATTRIB); ArmorDesc.xHP = pSegment->GetAttributeInteger(HP_X_ATTRIB); ArmorDesc.yHP = pSegment->GetAttributeInteger(HP_Y_ATTRIB); ArmorDesc.yName = pSegment->GetAttributeInteger(NAME_Y_ATTRIB); ArmorDesc.cxNameBreak = pSegment->GetAttributeInteger(NAME_BREAK_WIDTH); ArmorDesc.xNameDestOffset = pSegment->GetAttributeInteger(NAME_DEST_X_ATTRIB); ArmorDesc.yNameDestOffset = pSegment->GetAttributeInteger(NAME_DEST_Y_ATTRIB); } m_fHasArmorDesc = true; } else { m_fHasArmorDesc = false; m_iArmorDescCount = 0; m_pArmorDesc = NULL; } // Load shield display data CXMLElement *pShieldDisplay = pDesc->GetContentElementByTag(SHIELD_DISPLAY_TAG); if (pShieldDisplay) { if (error = m_ShieldDesc.Image.InitFromXML(Ctx, pShieldDisplay->GetContentElementByTag(IMAGE_TAG))) return ComposeLoadError(Ctx, ERR_SHIELD_DISPLAY_NEEDED); m_fHasShieldDesc = true; } // Load reactor display data CXMLElement *pReactorDisplay = pDesc->GetContentElementByTag(REACTOR_DISPLAY_TAG); if (pReactorDisplay) { if (error = m_ReactorDesc.ReactorImage.InitFromXML(Ctx, pReactorDisplay->GetContentElementByTag(IMAGE_TAG))) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); CXMLElement *pImage = pReactorDisplay->GetContentElementByTag(POWER_LEVEL_IMAGE_TAG); if (pImage == NULL || (error = m_ReactorDesc.PowerLevelImage.InitFromXML(Ctx, pImage))) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); m_ReactorDesc.xPowerLevelImage = pImage->GetAttributeInteger(DEST_X_ATTRIB); m_ReactorDesc.yPowerLevelImage = pImage->GetAttributeInteger(DEST_Y_ATTRIB); pImage = pReactorDisplay->GetContentElementByTag(FUEL_LEVEL_IMAGE_TAG); if (pImage == NULL || (error = m_ReactorDesc.FuelLevelImage.InitFromXML(Ctx, pImage))) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); m_ReactorDesc.xFuelLevelImage = pImage->GetAttributeInteger(DEST_X_ATTRIB); m_ReactorDesc.yFuelLevelImage = pImage->GetAttributeInteger(DEST_Y_ATTRIB); pImage = pReactorDisplay->GetContentElementByTag(FUEL_LOW_LEVEL_IMAGE_TAG); if (pImage == NULL || (error = m_ReactorDesc.FuelLowLevelImage.InitFromXML(Ctx, pImage))) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); if (error = InitRectFromElement(pReactorDisplay->GetContentElementByTag(REACTOR_TEXT_TAG), &m_ReactorDesc.rcReactorText)) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); if (error = InitRectFromElement(pReactorDisplay->GetContentElementByTag(POWER_LEVEL_TEXT_TAG), &m_ReactorDesc.rcPowerLevelText)) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); if (error = InitRectFromElement(pReactorDisplay->GetContentElementByTag(FUEL_LEVEL_TEXT_TAG), &m_ReactorDesc.rcFuelLevelText)) return ComposeLoadError(Ctx, ERR_REACTOR_DISPLAY_NEEDED); m_fHasReactorDesc = true; } // Done return NOERROR; }
ALERROR CTopologyNode::InitFromSystemXML (CXMLElement *pSystem, CString *retsError) // InitFromSystemXML // // Initializes the system information based on an XML element. // NOTE: We assume the universe is fully bound at this point. { ALERROR error; CString sSystemUNID = pSystem->GetAttribute(UNID_ATTRIB); DWORD dwUNID = strToInt(sSystemUNID, 0, NULL); // If the system node contains a table of different system types, then // remember the root node because some of the system information (such as the // name) may be there. CXMLElement *pSystemParent = NULL; // If there is no UNID attribute then it means that the system // is randomly determined based on a table if (dwUNID == 0 && pSystem->GetContentElementCount() == 1) { CXMLElement *pTableElement = pSystem->GetContentElement(0); if (pTableElement == NULL) { ASSERT(false); return ERR_FAIL; } CRandomEntryResults System; if (error = CRandomEntryGenerator::Generate(pTableElement, System)) { *retsError = strPatternSubst(CONSTLIT("Topology %s: Unable to generate random system UNID"), m_sID); return ERR_FAIL; } if (System.GetCount() != 1) { *retsError = strPatternSubst(CONSTLIT("Topology %s: Table generated no systems"), m_sID); return ERR_FAIL; } pSystemParent = pSystem; pSystem = System.GetResult(0); dwUNID = pSystem->GetAttributeInteger(UNID_ATTRIB); } // Set the system UNID if (dwUNID != 0) m_SystemUNID = dwUNID; // Get the system type CSystemType *pSystemType = g_pUniverse->FindSystemType(m_SystemUNID); // Set the name of the system CString sName; if (!pSystem->FindAttribute(NAME_ATTRIB, &sName)) if (pSystemParent) sName = pSystemParent->GetAttribute(NAME_ATTRIB); if (!sName.IsBlank()) SetName(sName); // Set the level int iLevel = 0; if (!pSystem->FindAttributeInteger(LEVEL_ATTRIB, &iLevel)) if (pSystemParent) iLevel = pSystemParent->GetAttributeInteger(LEVEL_ATTRIB); if (iLevel > 0) SetLevel(iLevel); if (GetLevel() == 0) SetLevel(1); // Add variants for the system CString sVariant; if (pSystem->FindAttribute(VARIANT_ATTRIB, &sVariant)) AddVariantLabel(sVariant); if (pSystemParent && pSystemParent->FindAttribute(VARIANT_ATTRIB, &sVariant)) AddVariantLabel(sVariant); // Add attributes for the node/system CString sAttribs; if (pSystem->FindAttribute(ATTRIBUTES_ATTRIB, &sAttribs)) AddAttributes(sAttribs); if (pSystemParent && pSystemParent->FindAttribute(ATTRIBUTES_ATTRIB, &sAttribs)) AddAttributes(sAttribs); if (pSystemType && !pSystemType->GetAttributes().IsBlank()) AddAttributes(pSystemType->GetAttributes()); return NOERROR; }
ALERROR CWeaponFireDesc::InitFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc, const CString &sUNID, bool bDamageOnly) // InitFromXML // // Loads shot data from an element { ALERROR error; int i; m_pExtension = Ctx.pExtension; m_fVariableInitialSpeed = false; m_bFragment = false; // Load basic attributes m_sUNID = sUNID; m_Lifetime.LoadFromXML(pDesc->GetAttribute(LIFETIME_ATTRIB)); int iMaxLifetime = m_Lifetime.GetMaxValue(); m_bCanDamageSource = pDesc->GetAttributeBool(CAN_HIT_SOURCE_ATTRIB); m_bAutoTarget = pDesc->GetAttributeBool(AUTO_TARGET_ATTRIB); m_bNoFriendlyFire = pDesc->GetAttributeBool(NO_FRIENDLY_FIRE_ATTRIB); m_InitialDelay.LoadFromXML(pDesc->GetAttribute(INITIAL_DELAY_ATTRIB)); // Load missile speed CString sData; if (pDesc->FindAttribute(MISSILE_SPEED_ATTRIB, &sData)) { if (error = m_MissileSpeed.LoadFromXML(sData)) { Ctx.sError = CONSTLIT("Invalid missile speed attribute"); return ERR_FAIL; } m_fVariableInitialSpeed = !m_MissileSpeed.IsConstant(); m_rMissileSpeed = (double)m_MissileSpeed.GetAveValue() * LIGHT_SPEED / 100; } else { m_fVariableInitialSpeed = false; m_rMissileSpeed = LIGHT_SPEED; } // Load the effect to use if (error = m_pEffect.LoadEffect(Ctx, strPatternSubst("%s:e", sUNID), pDesc->GetContentElementByTag(EFFECT_TAG), pDesc->GetAttribute(EFFECT_ATTRIB))) return error; // Load stealth m_iStealth = pDesc->GetAttributeInteger(STEALTH_ATTRIB); if (m_iStealth == 0) m_iStealth = CSpaceObject::stealthNormal; // Other properties m_iSplashChance = pDesc->GetAttributeIntegerBounded(PARTICLE_SPLASH_CHANCE_ATTRIB, 0, 100, 0); m_iMissChance = pDesc->GetAttributeIntegerBounded(PARTICLE_MISS_CHANCE_ATTRIB, 0, 100, 0); // Load specific properties CString sValue = pDesc->GetAttribute(FIRE_TYPE_ATTRIB); if (strEquals(sValue, FIRE_TYPE_MISSILE) || strEquals(sValue, FIRE_TYPE_BEAM)) { m_iFireType = (strEquals(sValue, FIRE_TYPE_BEAM) ? ftBeam : ftMissile); // For backwards compatibility, if we don't have an effect, assume // a beam effect. if (m_iFireType == ftBeam && m_pEffect == NULL) { if (error = m_pEffect.CreateBeamEffect(Ctx, pDesc, strPatternSubst("%s:e", sUNID))) return error; // Backwards compatibility in case a CBeam object is loaded from // an old save file. m_iBeamType = beamLaser; m_wPrimaryColor = CG16bitImage::RGBValue(0xf1, 0x5f, 0x2a); m_wSecondaryColor = CG16bitImage::RGBValue(0xff, 0x00, 0x00); m_iIntensity = 1; } // Load the image for the missile CXMLElement *pImage = pDesc->GetContentElementByTag(IMAGE_TAG); if (pImage) if (error = m_Image.InitFromXML(Ctx, pImage)) return error; m_bDirectional = pDesc->GetAttributeBool(DIRECTIONAL_ATTRIB); if (m_bDirectional && m_pEffect) m_pEffect->SetVariants(g_RotationRange); m_iAccelerationFactor = pDesc->GetAttributeInteger(ACCELERATION_FACTOR_ATTRIB); int iMaxSpeed = pDesc->GetAttributeInteger(MAX_MISSILE_SPEED_ATTRIB); if (iMaxSpeed == 0) m_rMaxMissileSpeed = m_rMissileSpeed; else m_rMaxMissileSpeed = (Metric)iMaxSpeed * LIGHT_SPEED / 100.0; // Hit points and interaction m_iHitPoints = pDesc->GetAttributeInteger(HIT_POINTS_ATTRIB); CString sInteraction; if (pDesc->FindAttribute(INTERACTION_ATTRIB, &sInteraction)) m_iInteraction = strToInt(sInteraction, 100); else m_iInteraction = (m_iFireType == ftBeam ? 0 : 100); // Load exhaust data CXMLElement *pExhaust = pDesc->GetContentElementByTag(MISSILE_EXHAUST_TAG); if (pExhaust) { m_iExhaustRate = pExhaust->GetAttributeInteger(EXHAUST_RATE_ATTRIB); m_iExhaustLifetime = pExhaust->GetAttributeInteger(EXHAUST_LIFETIME_ATTRIB); m_rExhaustDrag = pExhaust->GetAttributeInteger(EXHAUST_DRAG_ATTRIB) / 100.0; CXMLElement *pImage = pExhaust->GetContentElementByTag(IMAGE_TAG); if (error = m_ExhaustImage.InitFromXML(Ctx, pImage)) return error; } else { m_iExhaustRate = 0; m_iExhaustLifetime = 0; m_rExhaustDrag = 0.0; } } else if (strEquals(sValue, FIRE_TYPE_AREA)) { m_iFireType = ftArea; m_rMaxMissileSpeed = m_rMissileSpeed; // Load expansion speed if (pDesc->FindAttribute(EXPANSION_SPEED_ATTRIB, &sData)) { if (error = m_ExpansionSpeed.LoadFromXML(sData)) { Ctx.sError = CONSTLIT("Invalid expansionSpeed attribute"); return ERR_FAIL; } } else m_ExpansionSpeed.SetConstant(20); // Area damage density if (pDesc->FindAttribute(AREA_DAMAGE_DENSITY_ATTRIB, &sData)) { if (error = m_AreaDamageDensity.LoadFromXML(sData)) { Ctx.sError = CONSTLIT("Invalid areaDamageDensity attribute"); return ERR_FAIL; } } else m_AreaDamageDensity.SetConstant(32); // Must have effect if (m_pEffect == NULL) { Ctx.sError = CONSTLIT("Must have <Effect> for area damage."); return ERR_FAIL; } } else if (strEquals(sValue, FIRE_TYPE_PARTICLES)) { m_iFireType = ftParticles; m_rMaxMissileSpeed = m_rMissileSpeed; if (error = m_ParticleCount.LoadFromXML(pDesc->GetAttribute(PARTICLE_COUNT_ATTRIB))) { Ctx.sError = CONSTLIT("Invalid particle count."); return error; } if (error = m_ParticleEmitTime.LoadFromXML(pDesc->GetAttribute(PARTICLE_EMIT_TIME_ATTRIB))) { Ctx.sError = CONSTLIT("Invalid particle emit time."); return error; } m_iParticleSpread = pDesc->GetAttributeInteger(PARTICLE_SPREAD_ANGLE_ATTRIB); m_iParticleSpreadWidth = pDesc->GetAttributeInteger(PARTICLE_SPREAD_WIDTH_ATTRIB); } else if (strEquals(sValue, FIRE_TYPE_RADIUS)) { m_iFireType = ftRadius; m_rMaxMissileSpeed = m_rMissileSpeed; m_rMinRadius = LIGHT_SECOND * (Metric)pDesc->GetAttributeInteger(MIN_RADIUS_ATTRIB); m_rMaxRadius = LIGHT_SECOND * (Metric)pDesc->GetAttributeInteger(MAX_RADIUS_ATTRIB); // For radius, lifetime attribute is not required. We always set the lifetime // to the effect lifetime. if (m_pEffect && iMaxLifetime == 0) { int iEffectLifetime = m_pEffect->GetLifetime(); // If the effect lifetime is infinite then change it // to something more finite (this is technically an error condition) if (iEffectLifetime == -1) iEffectLifetime = 666; m_Lifetime.SetConstant(iEffectLifetime); iMaxLifetime = iEffectLifetime; } } else if (!bDamageOnly) { Ctx.sError = CONSTLIT("Invalid weapon fire type"); return ERR_FAIL; } // The effect should have the same lifetime as the shot // Note: For radius damage it is the other way around (we set iMaxLifetime based on // the effect--see above) if (m_pEffect) m_pEffect->SetLifetime(iMaxLifetime); // We initialize this with the UNID, and later resolve the reference // during OnDesignLoadComplete m_pAmmoType.LoadUNID(Ctx, pDesc->GetAttribute(AMMO_ID_ATTRIB)); // Maneuverability m_iManeuverability = pDesc->GetAttributeInteger(MANEUVERABILITY_ATTRIB); m_iManeuverRate = pDesc->GetAttributeIntegerBounded(MANEUVER_RATE_ATTRIB, 1, 180, -1); if (m_iManeuverRate == -1 && m_iManeuverability > 0) m_iManeuverRate = g_RotationAngle; else if (m_iManeuverability == 0 && m_iManeuverRate > 0) m_iManeuverability = 1; // Load continuous and passthrough m_iContinuous = pDesc->GetAttributeInteger(BEAM_CONTINUOUS_ATTRIB); if (pDesc->FindAttributeInteger(PASSTHROUGH_ATTRIB, &m_iPassthrough)) { // In previous versions passthrough was a boolean value, so for backwards // compatibility we treat 0 as 50%. // // Note: We don't do this for ftArea because we need a way to specify // passthrough=0 (since ftArea defaults to non-zero passthrough). Also, // ftArea has no backwards compatibility issues (passthrough is only // supported for 1.1 and above). if (m_iPassthrough == 0 && m_iFireType != ftArea) m_iPassthrough = 50; } else { // If this is an area weapon, we set passthrough to a default value // (for backwards compatibility) if (m_iFireType == ftArea) m_iPassthrough = 80; else m_iPassthrough = 0; } // Load damage if (error = m_Damage.LoadFromXML(Ctx, pDesc->GetAttribute(DAMAGE_ATTRIB))) { Ctx.sError = strPatternSubst(CONSTLIT("Invalid damage specification: %s"), pDesc->GetAttribute(DAMAGE_ATTRIB)); return error; } // Fragments m_pFirstFragment = NULL; SFragmentDesc *pLastFragment = NULL; int iFragCount = 0; for (i = 0; i < pDesc->GetContentElementCount(); i++) { CXMLElement *pFragDesc = pDesc->GetContentElement(i); if (!strEquals(FRAGMENT_TAG, pFragDesc->GetTag())) continue; // Create a new fragmentation descriptor SFragmentDesc *pNewDesc = new SFragmentDesc; pNewDesc->pNext = NULL; if (pLastFragment) pLastFragment->pNext = pNewDesc; else m_pFirstFragment = pNewDesc; pLastFragment = pNewDesc; // Load fragment data pNewDesc->pDesc = new CWeaponFireDesc; CString sFragUNID = strPatternSubst("%s/f%d", sUNID, iFragCount++); if (error = pNewDesc->pDesc->InitFromXML(Ctx, pFragDesc, sFragUNID)) return error; pNewDesc->pDesc->m_bFragment = true; // Set the fragment count CString sCount = pFragDesc->GetAttribute(COUNT_ATTRIB); if (sCount.IsBlank()) sCount = pDesc->GetAttribute(FRAGMENT_COUNT_ATTRIB); pNewDesc->Count.LoadFromXML(sCount); // Set MIRV flag pNewDesc->bMIRV = (pFragDesc->GetAttributeBool(MULTI_TARGET_ATTRIB) || pDesc->GetAttributeBool(FRAGMENT_TARGET_ATTRIB)); } // If we have fragments, then set proximity appropriately // NOTE: We set the fail safe value even if we don't set the proximity // blast because we might set m_bProximityBlast later if there // is an OnFragment event. m_bProximityBlast = (iFragCount != 0); m_iProximityFailsafe = pDesc->GetAttributeInteger(FAILSAFE_ATTRIB); // Compute max effective range if (m_iFireType == ftArea) m_rMaxEffectiveRange = (m_ExpansionSpeed.GetAveValue() * LIGHT_SECOND / 100.0) * Ticks2Seconds(iMaxLifetime) * 0.75; else { Metric rEffectiveLifetime; if (m_iManeuverability > 0) rEffectiveLifetime = Ticks2Seconds(iMaxLifetime) * 0.75; else rEffectiveLifetime = Min(Ticks2Seconds(iMaxLifetime), 100.0); Metric rSpeed = (m_rMissileSpeed + m_rMaxMissileSpeed) / 2; m_rMaxEffectiveRange = rSpeed * rEffectiveLifetime; // If we have fragments, add to the effective range if (m_pFirstFragment) m_rMaxEffectiveRange += m_pFirstFragment->pDesc->m_rMaxEffectiveRange; } // Effects if (error = m_pHitEffect.LoadEffect(Ctx, strPatternSubst("%s:h", sUNID), pDesc->GetContentElementByTag(HIT_EFFECT_TAG), pDesc->GetAttribute(HIT_EFFECT_ATTRIB))) return error; if (error = m_pFireEffect.LoadEffect(Ctx, strPatternSubst("%s:f", sUNID), pDesc->GetContentElementByTag(FIRE_EFFECT_TAG), pDesc->GetAttribute(FIRE_EFFECT_ATTRIB))) return error; // Vapor trail if (!pDesc->FindAttributeInteger(VAPOR_TRAIL_WIDTH_ATTRIB, &m_iVaporTrailWidth)) m_iVaporTrailWidth = 100 * pDesc->GetAttributeInteger(VAPOR_TRAIL_ATTRIB); if (m_iVaporTrailWidth) { m_wVaporTrailColor = LoadRGBColor(pDesc->GetAttribute(VAPOR_TRAIL_COLOR_ATTRIB)); m_iVaporTrailLength = pDesc->GetAttributeInteger(VAPOR_TRAIL_LENGTH_ATTRIB); if (m_iVaporTrailLength <= 0) m_iVaporTrailLength = 64; if (!pDesc->FindAttributeInteger(VAPOR_TRAIL_WIDTH_INC_ATTRIB, &m_iVaporTrailWidthInc)) m_iVaporTrailWidthInc = 25; } else m_iVaporTrailLength = 0; // Sound DWORD dwSoundID = LoadUNID(Ctx, pDesc->GetAttribute(SOUND_ATTRIB)); if (dwSoundID) m_iFireSound = g_pUniverse->FindSound(dwSoundID); else m_iFireSound = -1; // Events CXMLElement *pEventsDesc = pDesc->GetContentElementByTag(EVENTS_TAG); if (pEventsDesc) { if (error = m_Events.InitFromXML(Ctx, pEventsDesc)) return error; } // Check to see if this element has an enhanced sub-element. If so, then we // recurse. CXMLElement *pEnhanced = pDesc->GetContentElementByTag(ENHANCED_TAG); if (pEnhanced) { m_pEnhanced = new CWeaponFireDesc(*this); if (error = m_pEnhanced->OverrideDesc(Ctx, pEnhanced)) return error; } else m_pEnhanced = NULL; return NOERROR; }