ALERROR WriteSubModules (CTDBCompiler &Ctx, CXMLElement *pModule, const CString &sFolder, CDataFile &Out) { int i, j; for (i = 0; i < pModule->GetContentElementCount(); i++) { CXMLElement *pItem = pModule->GetContentElement(i); if (strEquals(pItem->GetTag(), TAG_MODULES)) { for (j = 0; j < pItem->GetContentElementCount(); j++) { CXMLElement *pDesc = pItem->GetContentElement(j); CString sFilename = pDesc->GetAttribute(ATTRIB_FILENAME); if (WriteModule(Ctx, sFilename, sFolder, Out) != NOERROR) continue; } } else if (strEquals(pItem->GetTag(), TAG_MODULE)) { CString sFilename = pItem->GetAttribute(ATTRIB_FILENAME); if (WriteModule(Ctx, sFilename, sFolder, Out) != NOERROR) continue; } } return NOERROR; }
ALERROR WriteModuleSounds (CTDBCompiler &Ctx, CXMLElement *pModule, const CString &sFolder, CDataFile &Out) { ALERROR error; int i; for (i = 0; i < pModule->GetContentElementCount(); i++) { CXMLElement *pItem = pModule->GetContentElement(i); if (strEquals(pItem->GetTag(), TAG_SOUNDS)) { CString sSubFolder = pathAddComponent(sFolder, pItem->GetAttribute(ATTRIB_FOLDER)); if (error = WriteModuleSounds(Ctx, pItem, sSubFolder, Out)) return error; } else if (strEquals(pItem->GetTag(), TAG_SOUND)) { CString sFilename = pItem->GetAttribute(ATTRIB_FILENAME); if (error = WriteResource(Ctx, sFilename, sFolder, false, Out)) continue; } } return NOERROR; }
ALERROR WriteModuleImages (CXMLElement *pModule, const CString &sFolder, CSymbolTable &Resources, CDataFile &Out) { ALERROR error; int i; for (i = 0; i < pModule->GetContentElementCount(); i++) { CXMLElement *pItem = pModule->GetContentElement(i); if (strEquals(pItem->GetTag(), TAG_IMAGES)) { CString sSubFolder = pathAddComponent(sFolder, pItem->GetAttribute(ATTRIB_FOLDER)); if (error = WriteModuleImages(pItem, sSubFolder, Resources, Out)) return error; } else if (strEquals(pItem->GetTag(), TAG_IMAGE)) { CString sFilename = pItem->GetAttribute(ATTRIB_BITMAP); if (!sFilename.IsBlank()) { if (error = WriteResource(sFilename, sFolder, Resources, Out)) continue; } sFilename = pItem->GetAttribute(ATTRIB_BITMASK); if (!sFilename.IsBlank()) { if (error = WriteResource(sFilename, sFolder, Resources, Out)) continue; } } } 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 WriteModuleImages (CTDBCompiler &Ctx, CXMLElement *pModule, const CString &sFolder, CDataFile &Out) { ALERROR error; int i; for (i = 0; i < pModule->GetContentElementCount(); i++) { CXMLElement *pItem = pModule->GetContentElement(i); if (strEquals(pItem->GetTag(), TAG_IMAGES)) { CString sSubFolder = pathAddComponent(sFolder, pItem->GetAttribute(ATTRIB_FOLDER)); if (error = WriteModuleImages(Ctx, pItem, sSubFolder, Out)) return error; } else if (strEquals(pItem->GetTag(), TAG_IMAGE)) { CString sFilename = pItem->GetAttribute(ATTRIB_BITMAP); if (!sFilename.IsBlank()) { bool bCompress = strEquals(strToLower(pathGetExtension(sFilename)), CONSTLIT("bmp")); if (error = WriteResource(Ctx, sFilename, sFolder, bCompress, Out)) continue; } sFilename = pItem->GetAttribute(ATTRIB_BITMASK); if (!sFilename.IsBlank()) { bool bCompress = strEquals(strToLower(pathGetExtension(sFilename)), CONSTLIT("bmp")); if (error = WriteResource(Ctx, sFilename, sFolder, bCompress, Out)) continue; } sFilename = pItem->GetAttribute(ATTRIB_SHADOW_MASK); if (!sFilename.IsBlank()) { bool bCompress = strEquals(strToLower(pathGetExtension(sFilename)), CONSTLIT("bmp")); if (error = WriteResource(Ctx, sFilename, sFolder, bCompress, Out)) continue; } sFilename = pItem->GetAttribute(ATTRIB_HIT_MASK); if (!sFilename.IsBlank()) { bool bCompress = strEquals(strToLower(pathGetExtension(sFilename)), CONSTLIT("bmp")); if (error = WriteResource(Ctx, sFilename, sFolder, bCompress, Out)) continue; } } } return NOERROR; }
ALERROR CSystemMap::ExecuteCreator (STopologyCreateCtx &Ctx, CTopology &Topology, CXMLElement *pCreator) // ExecuteCreator // // Runs a specific creator { ALERROR error; int i; // If this is a root node tag then we add it and all its connections. if (strEquals(pCreator->GetTag(), ROOT_NODE_TAG)) { if (error = Topology.AddTopologyNode(Ctx, pCreator->GetAttribute(ID_ATTRIB))) return error; } // Otherwise we process the creator element else { for (i = 0; i < pCreator->GetContentElementCount(); i++) { CXMLElement *pDirective = pCreator->GetContentElement(i); if (strEquals(pDirective->GetTag(), NODE_TAG)) { if (error = Topology.AddTopologyNode(Ctx, pDirective->GetAttribute(ID_ATTRIB))) return error; } else if (strEquals(pDirective->GetTag(), STARGATE_TAG) || strEquals(pDirective->GetTag(), STARGATES_TAG)) { if (error = Topology.AddStargateFromXML(Ctx, pDirective)) return error; } else { Ctx.sError = strPatternSubst(CONSTLIT("Unknown TopologyCreator directive: %s."), pDirective->GetTag()); return ERR_FAIL; } } } return NOERROR; }
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 CEventHandler::InitFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc) // InitFromXML // // Load all handlers { int i; for (i = 0; i < pDesc->GetContentElementCount(); i++) { CXMLElement *pHandler = pDesc->GetContentElement(i); ICCItem *pCode = g_pUniverse->GetCC().Link(pHandler->GetContentText(0), 0, NULL); if (pCode->IsError()) { Ctx.sError = strPatternSubst("<%s> event: %s", pHandler->GetTag(), pCode->GetStringValue()); return ERR_FAIL; } // If this is an old extension, then make sure the code is not using the // gStation variable, because we no longer support it if (Ctx.pExtension && Ctx.pExtension->dwVersion < 2) { if (g_pUniverse->GetCC().HasIdentifier(pCode, CONSTLIT("gStation"))) { Ctx.sError = CONSTLIT("gStation variable has been deprecated--use gSource instead."); return ERR_FAIL; } } // Done m_Handlers.Insert(pHandler->GetTag(), pCode); } return NOERROR; }
ALERROR CGroupOfDeviceGenerators::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); // Load either a <DeviceSlot> element or another device generator. for (i = 0; i < pDesc->GetContentElementCount(); i++) { CXMLElement *pEntry = pDesc->GetContentElement(i); if (strEquals(pEntry->GetTag(), DEVICE_SLOT_TAG)) { SSlotDesc *pSlotDesc = m_SlotDesc.Insert(); CItem::ParseCriteria(pEntry->GetAttribute(CRITERIA_ATTRIB), &pSlotDesc->Criteria); if (error = IDeviceGenerator::InitDeviceDescFromXML(Ctx, pEntry, &pSlotDesc->DefaultDesc)) return error; pSlotDesc->iMaxCount = pEntry->GetAttributeIntegerBounded(MAX_COUNT_ATTRIB, 0, -1, -1); } else { SEntry *pTableEntry = m_Table.Insert(); pTableEntry->iChance = pEntry->GetAttributeIntegerBounded(CHANCE_ATTRIB, 0, -1, 100); if (error = IDeviceGenerator::CreateFromXML(Ctx, pEntry, &pTableEntry->pDevice)) { pTableEntry->pDevice = NULL; return error; } } } return NOERROR; }
ALERROR CExtension::LoadSystemTypesElement (SDesignLoadCtx &Ctx, CXMLElement *pDesc) // LoadSystemTypesElement // // Loads <SystemTypes> element // (For backwards compatibility) { ALERROR error; int i; for (i = 0; i < pDesc->GetContentElementCount(); i++) { CXMLElement *pItem = pDesc->GetContentElement(i); if (strEquals(pItem->GetTag(), TABLES_TAG)) { CSystemTable *pTable = new CSystemTable; pTable->InitFromXML(Ctx, pItem); if (pTable->GetUNID() == 0) pTable->SetUNID(DEFAULT_SYSTEM_TABLE_UNID); if (error = m_DesignTypes.AddEntry(pTable)) { Ctx.sError = strPatternSubst(CONSTLIT("Error adding system table: %x"), pTable->GetUNID()); return error; } } else { if (error = LoadDesignType(Ctx, pItem)) return error; } } return NOERROR; }
ALERROR CUniverse::InitStarSystemTypes (SDesignLoadCtx &Ctx, CXMLElement *pElement) // InitStarSystemTypes // // Load <StarSystemTypes> tag { ALERROR error; int i; for (i = 0; i < pElement->GetContentElementCount(); i++) { CXMLElement *pItem = pElement->GetContentElement(i); if (strEquals(pItem->GetTag(), TABLES_TAG)) { if (m_pSystemTables) { Ctx.sError = CONSTLIT("Multiple global tables found in <StarSystemDescriptions>"); return ERR_FAIL; } m_pSystemTables = pItem->OrphanCopy(); } else { if (error = m_Design.LoadEntryFromXML(Ctx, pItem)) return error; #ifdef DEBUG_SOURCE_LOAD_TRACE kernelDebugLogMessage("Loaded system type: %x", dwUNID); #endif } } 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 CExtension::CreateBaseFile (SDesignLoadCtx &Ctx, EGameTypes iGame, CXMLElement *pDesc, CExternalEntityTable *pEntities, CExtension **retpBase, TArray<CXMLElement *> *retEmbedded) // CreateBaseFile // // Loads a new extension from the base file. { ALERROR error; int i; // Create an extension object CExtension *pExtension = new CExtension; pExtension->m_sFilespec = Ctx.sResDb; pExtension->m_dwUNID = 0; // Base is the only extension with 0 UNID. pExtension->m_iGame = iGame; pExtension->m_iType = extBase; pExtension->m_iLoadState = loadEntities; pExtension->m_iFolderType = folderBase; pExtension->m_pEntities = pEntities; pExtension->m_ModifiedTime = fileGetModifiedTime(Ctx.sResDb); pExtension->m_bRegistered = true; pExtension->m_bPrivate = true; pExtension->m_bAutoInclude = true; pExtension->m_bUsesXML = false; pExtension->m_bUsesCompatibilityLibrary = false; // Load the apiVersion CString sAPIVersion; if (pDesc->FindAttribute(API_VERSION_ATTRIB, &sAPIVersion)) { pExtension->m_dwAPIVersion = (DWORD)strToInt(sAPIVersion, 0); if (pExtension->m_dwAPIVersion < 12) pExtension->m_dwAPIVersion = 0; } // If this version is later than what we expect, then we fail. if (pExtension->m_dwAPIVersion > API_VERSION) { pExtension->m_pEntities = NULL; // Let our parent clean up delete pExtension; Ctx.sError = CONSTLIT("Newer version of the Transcendence engine is required."); return ERR_FAIL; } // We return the base extension *retpBase = pExtension; // Set up context Ctx.pExtension = pExtension; // Load the Main XML file for (i = 0; i < pDesc->GetContentElementCount(); i++) { CXMLElement *pItem = pDesc->GetContentElement(i); // <Images> if (strEquals(pItem->GetTag(), IMAGES_TAG)) error = pExtension->LoadImagesElement(Ctx, pItem); // <Sounds> else if (strEquals(pItem->GetTag(), SOUNDS_TAG)) error = pExtension->LoadSoundsElement(Ctx, pItem); // <SystemTypes> else if (strEquals(pItem->GetTag(), SYSTEM_TYPES_TAG)) error = pExtension->LoadSystemTypesElement(Ctx, pItem); // <TranscendenceAdventure> else if (strEquals(pItem->GetTag(), TRANSCENDENCE_ADVENTURE_TAG) || strEquals(pItem->GetTag(), TRANSCENDENCE_LIBRARY_TAG) || strEquals(pItem->GetTag(), CORE_LIBRARY_TAG)) { // Return this as an embedded extension retEmbedded->Insert(pItem); error = NOERROR; } // Other types else error = pExtension->LoadDesignElement(Ctx, pItem); // Check for error if (error) { pExtension->m_pEntities = NULL; // Let our parent clean up delete pExtension; return error; } } // Restore Ctx.pExtension = NULL; // Done pExtension->m_iLoadState = loadComplete; 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; }
bool ParseElement (ParserCtx *pCtx, CXMLElement **retpElement) // ParseElement // // Parses an element and returns it. We assume that we've already // parsed an open tag { CXMLElement *pElement; ASSERT(pCtx->iToken == tkTagOpen); // Parse the tag name if (ParseToken(pCtx) != tkText) { pCtx->sError = ERR_ELEMENT_TAG_EXPECTED; return false; } // Create a new element with the tag pElement = new CXMLElement(pCtx->sToken, pCtx->pElement); if (pElement == NULL) throw CException(errOutOfMemory); // Keep parsing until the tag is done ParseToken(pCtx); while (pCtx->iToken != tkTagClose && pCtx->iToken != tkSimpleTagClose) { // If we've got an identifier then this must be an attribute if (pCtx->iToken == tkText) { CString sAttribute = pCtx->sToken; CString sValue; // Expect an equals sign if (ParseToken(pCtx) != tkEquals) { pCtx->sError = ERR_EQUAL_EXPECTED; delete pElement; return false; } // Expect a quote ParseToken(pCtx); if (pCtx->iToken != tkQuote && pCtx->iToken != tkSingleQuote) { pCtx->sError = ERR_ATTRIB_NEEDS_QUOTES; delete pElement; return false; } // Remember what kind of qoute we used so that we can match it // (and so we ignore the other kind inside it). pCtx->iAttribQuote = pCtx->iToken; // Expect the value ParseToken(pCtx, AttributeState); if (pCtx->iToken == tkText) { sValue = pCtx->sToken; ParseToken(pCtx); } else sValue = NULL_STR; // Now expect an end-quote if (pCtx->iToken != pCtx->iAttribQuote) { if (pCtx->iToken != tkError || pCtx->sError.IsEmpty()) pCtx->sError = ERR_MISMATCHED_ATTRIB_QUOTE; delete pElement; return false; } // Add the attribute to the element pElement->AddAttribute(sAttribute, sValue); // Parse the next token ParseToken(pCtx); } // Otherwise this is an error else { if (pCtx->iToken != tkError || pCtx->sError.IsEmpty()) pCtx->sError = ERR_ATTRIB_EXPECTED; delete pElement; return false; } } // Give our controller a chance to deal with an element // (We use this in Transcendence to parse the <Library> element, which // contains external entities). // // NOTE: We only worry about top-level elements (i.e., elements immediately // under the root). if (pCtx->m_pController && pCtx->pElement && pCtx->pElement->GetParentElement() == NULL) { if (!pCtx->m_pController->OnOpenTag(pElement, &pCtx->sError)) { delete pElement; return false; } } // If we don't have an empty element then keep parsing until // we find a close tag if (!pCtx->m_bParseRootElement && pCtx->iToken == tkTagClose) { CXMLElement *pParentElement; // We are recursing pParentElement = pCtx->pElement; pCtx->pElement = pElement; // Parse until we've got the begin close tag while (ParseToken(pCtx, ContentState) != tkEndTagOpen) { // If this is text then append it as content if (pCtx->iToken == tkText) pElement->AppendContent(pCtx->sToken); // Otherwise, append an element else if (pCtx->iToken == tkTagOpen) { CXMLElement *pSubElement; if (!ParseElement(pCtx, &pSubElement)) { pCtx->pElement = pParentElement; delete pElement; return false; } pElement->AppendSubElement(pSubElement); } // Otherwise we're in trouble else { pCtx->pElement = pParentElement; if (pCtx->iToken != tkError || pCtx->sError.IsEmpty()) pCtx->sError = ERR_CONTENT_EXPECTED; delete pElement; return false; } } // Done pCtx->pElement = pParentElement; // The element tag should match ours if (ParseToken(pCtx) != tkText || strEqualsNoCase(pCtx->sToken, pElement->GetTag())) { pCtx->sError = ERR_UNMATCHED_CLOSE_TAG; delete pElement; return false; } // Parse the end tag if (ParseToken(pCtx) != tkTagClose) { pCtx->sError = ERR_CLOSE_TAG_EXPECTED; delete pElement; return false; } } // Done *retpElement = pElement; return true; }
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 CSystemMap::OnCreateFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc) // OnCreateFromXML { ALERROR error; int i; // Load some basic info m_sName = pDesc->GetAttribute(NAME_ATTRIB); m_dwBackgroundImage = pDesc->GetAttributeInteger(BACKGROUND_IMAGE_ATTRIB); if (error = m_pPrimaryMap.LoadUNID(Ctx, pDesc->GetAttribute(PRIMARY_MAP_ATTRIB))) return error; m_bStartingMap = pDesc->GetAttributeBool(STARTING_MAP_ATTRIB); // If we have a primary map, then add it to the Uses list. if (m_pPrimaryMap.GetUNID() != 0) m_Uses.Insert(m_pPrimaryMap); // Scale information m_iInitialScale = pDesc->GetAttributeIntegerBounded(INITIAL_SCALE_ATTRIB, 10, 1000, 100); m_iMaxScale = pDesc->GetAttributeIntegerBounded(MAX_SCALE_ATTRIB, 100, 1000, 200); m_iMinScale = pDesc->GetAttributeIntegerBounded(MIN_SCALE_ATTRIB, 10, 100, 50); // Generate an UNID CString sUNID = strPatternSubst(CONSTLIT("%d"), GetUNID()); // Keep track of root nodes TArray<CString> RootNodes; // Iterate over all child elements and process them for (i = 0; i < pDesc->GetContentElementCount(); i++) { CXMLElement *pItem = pDesc->GetContentElement(i); if (strEquals(pItem->GetTag(), TOPOLOGY_CREATOR_TAG) || strEquals(pItem->GetTag(), ROOT_NODE_TAG)) { m_Creators.Insert(pItem->OrphanCopy()); if (strEquals(pItem->GetTag(), ROOT_NODE_TAG)) RootNodes.Insert(pItem->GetAttribute(ID_ATTRIB)); } else if (strEquals(pItem->GetTag(), TOPOLOGY_PROCESSOR_TAG)) { ITopologyProcessor *pNewProc; CString sProcessorUNID = strPatternSubst(CONSTLIT("%d:p%d"), GetUNID(), m_Processors.GetCount()); if (error = ITopologyProcessor::CreateFromXMLAsGroup(Ctx, pItem, sProcessorUNID, &pNewProc)) return error; m_Processors.Insert(pNewProc); } else if (strEquals(pItem->GetTag(), SYSTEM_TOPOLOGY_TAG)) { if (error = m_FixedTopology.LoadFromXML(Ctx, pItem, this, sUNID, true)) return error; } else if (strEquals(pItem->GetTag(), USES_TAG)) { CSystemMapRef *pRef = m_Uses.Insert(); if (error = pRef->LoadUNID(Ctx, pItem->GetAttribute(UNID_ATTRIB))) return error; } else { // If it's none of the above, see if it is a node descriptor if (error = m_FixedTopology.LoadNodeFromXML(Ctx, pItem, this, sUNID)) return error; } } // Mark all the root nodes. // // We need to do this for backwards compatibility because the old technique // of having a root node with [Prev] for a stargate requires this. This was // used by Huaramarca. for (i = 0; i < RootNodes.GetCount(); i++) if (error = m_FixedTopology.AddRootNode(Ctx, RootNodes[i])) return error; // Init m_bAdded = false; // Debug info m_bDebugShowAttributes = pDesc->GetAttributeBool(DEBUG_SHOW_ATTRIBUTES_ATTRIB); return NOERROR; }
ALERROR CConquerNodesProc::OnInitFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc, const CString &sUNID) // OnInitFromXML // // Initialize from XML element { ALERROR error; int i; // Initialize criteria CTopologyNode::ParseCriteria(NULL, &m_Criteria); // Loop over all elements for (i = 0; i < pDesc->GetContentElementCount(); i++) { CXMLElement *pItem = pDesc->GetContentElement(i); // If we have a criteria, parse it and remember it // (Note: If multiple criteria are found, we take the latest one). if (strEquals(pItem->GetTag(), CRITERIA_TAG)) { // Parse the filter if (error = CTopologyNode::ParseCriteria(pItem, &m_Criteria, &Ctx.sError)) return error; } // Otherwise, treat it as a conqueror definition and insert it in the list else { CString sNewUNID = strPatternSubst(CONSTLIT("%s/%d"), sUNID, m_Conquerors.GetCount()); SConqueror *pConqueror = m_Conquerors.Insert(); // Get some properties pConqueror->iSeedChance = pItem->GetAttributeIntegerBounded(SEED_CHANCE_ATTRIB, 1, 100, 1); pConqueror->iMaxSeeds = pItem->GetAttributeIntegerBounded(MAX_SEEDS_ATTRIB, 1, -1, 1); pConqueror->iExpandChance = pItem->GetAttributeIntegerBounded(EXPAND_CHANCE_ATTRIB, 1, 100, 1); pConqueror->iMaxNodes = pItem->GetAttributeIntegerBounded(MAX_NODES_ATTRIB, 1, -1, 1); // Get the seed and expand probabilities if (error = LoadNodeWeightTable(Ctx, pItem->GetContentElementByTag(SEED_CHANCE_TAG), &pConqueror->Seed)) return error; if (error = LoadNodeWeightTable(Ctx, pItem->GetContentElementByTag(EXPAND_CHANCE_TAG), &pConqueror->Expand)) return error; // Get the processor itself CXMLElement *pProcXML = pItem->GetContentElementByTag(PROCESSOR_TAG); if (pProcXML) { if (error = ITopologyProcessor::CreateFromXMLAsGroup(Ctx, pProcXML, sNewUNID, &pConqueror->pProc)) return error; } else { Ctx.sError = CONSTLIT("<Processor> element not found in <ConquerNodes>"); return ERR_FAIL; } } } return NOERROR; }
ALERROR WriteModule (CTDBCompiler &Ctx, const CString &sFilename, const CString &sFolder, CDataFile &Out, int *retiModuleEntry, bool bCore) { ALERROR error; int i; // Parse the file CXMLElement *pModule; CExternalEntityTable *pEntityTable = new CExternalEntityTable; CFileReadBlock DataFile(pathAddComponent(Ctx.GetRootPath(), sFilename)); CString sError; printf("Parsing %s...", sFilename.GetASCIIZPointer()); if (error = CXMLElement::ParseXML(&DataFile, Ctx.GetCoreEntities(), &pModule, &sError, pEntityTable)) { printf("\n"); Ctx.ReportError(sError); return error; } // If this is a core module (embedded in the root XML) then we add these // entities to the core. [Ctx takes ownership.] if (bCore) Ctx.AddEntityTable(pEntityTable); // Chain entity tables (so that any modules that we load get the benefit). // This will chain Ctx.pCoreEntities (and restore it in the destructor). // // NOTE: If this is a core module, then we don't do this, since we've // already added the entities to the context block. CSaveEntitiesTable SavedEntities(Ctx, (!bCore ? pEntityTable : NULL)); printf("done.\n"); // Compress if this is NOT the main file. We can't compress the // main file because we sometimes need to read it partially. bool bCompress = (retiModuleEntry == NULL); // Write the module itself int iEntry; if (error = WriteGameFile(Ctx, sFilename, bCompress, Out, &iEntry)) return error; // If the caller doesn't want the module entry, then it means that this is // a module (instead of the main file). If so, add it to the resources table if (retiModuleEntry == NULL) Ctx.AddResource(sFilename, iEntry, bCompress); // Store all the image resources if (error = WriteModuleImages(Ctx, pModule, sFolder, Out)) return error; // Store all the sound resources if (error = WriteModuleSounds(Ctx, pModule, sFolder, Out)) return error; // Store all modules if (error = WriteSubModules(Ctx, pModule, sFolder, Out)) return error; // The root module may have a TranscendenceAdventure tag with modules in it for (i = 0; i < pModule->GetContentElementCount(); i++) { CXMLElement *pItem = pModule->GetContentElement(i); if (strEquals(pItem->GetTag(), TAG_CORE_LIBRARY) || strEquals(pItem->GetTag(), TAG_TRANSCENDENCE_ADVENTURE) || strEquals(pItem->GetTag(), TAG_TRANSCENDENCE_LIBRARY)) { // If we have a filename, then we need to save the target as a // module. CString sFilename; if (pItem->FindAttribute(ATTRIB_FILENAME, &sFilename)) { // Write out the module, making sure to set the core flag. if (error = WriteModule(Ctx, sFilename, sFolder, Out, NULL, true)) return error; // We ignore any other elements. continue; } // Store all the image resources if (error = WriteModuleImages(Ctx, pItem, sFolder, Out)) return error; // Store all the sound resources if (error = WriteModuleSounds(Ctx, pItem, sFolder, Out)) return error; // Modules if (error = WriteSubModules(Ctx, pItem, sFolder, Out)) return error; } } // Done if (retiModuleEntry) *retiModuleEntry = iEntry; return NOERROR; }
ALERROR CDockPane::CreateControls (CString *retsError) // CreateControls // // Creates controls based on the pane descriptor. We assume that m_pContainer has // already been created and is empty. { int i; // If there is a <Controls> element then use that to figure out what to // create. CXMLElement *pControls = m_pPaneDesc->GetContentElementByTag(CONTROLS_TAG); if (pControls) { for (i = 0; i < pControls->GetContentElementCount(); i++) { CXMLElement *pControlDef = pControls->GetContentElement(i); // Figure out the type EControlTypes iType; if (strEquals(pControlDef->GetTag(), COUNTER_TAG)) iType = controlCounter; else if (strEquals(pControlDef->GetTag(), ITEM_DISPLAY_TAG)) iType = controlItemDisplay; else if (strEquals(pControlDef->GetTag(), TEXT_TAG)) iType = controlDesc; else if (strEquals(pControlDef->GetTag(), TEXT_INPUT_TAG)) iType = controlTextInput; else { *retsError = strPatternSubst(CONSTLIT("Unknown control element: <%s>."), pControlDef->GetTag()); return ERR_FAIL; } // Get the ID CString sID; if (!pControlDef->FindAttribute(ID_ATTRIB, &sID)) { *retsError = strPatternSubst(CONSTLIT("Missing ID attrib for control element: <%s>."), pControlDef->GetTag()); return ERR_FAIL; } // Create the control CreateControl(iType, sID); } } // Otherwise we create default controls else { // Create the text description control CreateControl(controlDesc, DEFAULT_DESC_ID); // Create counter or input fields if (m_pPaneDesc->GetAttributeBool(SHOW_COUNTER_ATTRIB)) CreateControl(controlCounter, DEFAULT_COUNTER_ID); else if (m_pPaneDesc->GetAttributeBool(SHOW_TEXT_INPUT_ATTRIB)) CreateControl(controlTextInput, DEFAULT_TEXT_INPUT_ID); } return NOERROR; }
ALERROR CTopologyNode::ParseCriteria (CXMLElement *pCrit, SCriteria *retCrit, CString *retsError) // ParseCriteria // // Parses an XML element into a criteria desc { int i; retCrit->iChance = 100; retCrit->iMaxInterNodeDist = -1; retCrit->iMinInterNodeDist = 0; retCrit->iMaxStargates = -1; retCrit->iMinStargates = 0; if (pCrit) { for (i = 0; i < pCrit->GetContentElementCount(); i++) { CXMLElement *pItem = pCrit->GetContentElement(i); if (strEquals(pItem->GetTag(), ATTRIBUTES_TAG)) { CString sCriteria = pItem->GetAttribute(CRITERIA_ATTRIB); ParseCriteriaInt(sCriteria, retCrit); } else if (strEquals(pItem->GetTag(), CHANCE_TAG)) { retCrit->iChance = pItem->GetAttributeIntegerBounded(CHANCE_ATTRIB, 0, 100, 100); } else if (strEquals(pItem->GetTag(), DISTANCE_BETWEEN_NODES_TAG)) { retCrit->iMinInterNodeDist = pItem->GetAttributeIntegerBounded(MIN_ATTRIB, 0, -1, 0); retCrit->iMaxInterNodeDist = pItem->GetAttributeIntegerBounded(MAX_ATTRIB, 0, -1, -1); } else if (strEquals(pItem->GetTag(), DISTANCE_TO_TAG)) { SDistanceTo *pDistTo = retCrit->DistanceTo.Insert(); pDistTo->iMinDist = pItem->GetAttributeIntegerBounded(MIN_ATTRIB, 0, -1, 0); pDistTo->iMaxDist = pItem->GetAttributeIntegerBounded(MAX_ATTRIB, 0, -1, -1); CString sCriteria; if (pItem->FindAttribute(CRITERIA_ATTRIB, &sCriteria)) { SCriteria Criteria; if (ParseCriteriaInt(sCriteria, &Criteria) != NOERROR) { *retsError = strPatternSubst(CONSTLIT("Unable to parse criteria: %s"), sCriteria); return ERR_FAIL; } pDistTo->AttribsRequired = Criteria.AttribsRequired; pDistTo->AttribsNotAllowed = Criteria.AttribsNotAllowed; } else pDistTo->sNodeID = pItem->GetAttribute(NODE_ID_ATTRIB); } else if (strEquals(pItem->GetTag(), STARGATE_COUNT_TAG)) { retCrit->iMinStargates = pItem->GetAttributeIntegerBounded(MIN_ATTRIB, 0, -1, 0); retCrit->iMaxStargates = pItem->GetAttributeIntegerBounded(MAX_ATTRIB, 0, -1, -1); } else { *retsError = strPatternSubst(CONSTLIT("Unknown criteria element: %s"), pItem->GetTag()); return ERR_FAIL; } } } return NOERROR; }
ALERROR CGameSettings::Load (const CString &sFilespec, CString *retsError) // Load // // Load game settings from a file. If the file does not exist, then we // set settings to default values { ALERROR error; int i; // Initialize from defaults for (i = 0; i < OPTIONS_COUNT; i++) SetValue(i, CString(g_OptionData[i].pszDefaultValue, -1, true), true); // Load XML CFileReadBlock DataFile(sFilespec); CXMLElement *pData; CString sError; if (error = CXMLElement::ParseXML(&DataFile, &pData, retsError)) { // ERR_NOTFOUND means that we couldn't find the Settings.xml // file. In that case, initialize from defaults if (error == ERR_NOTFOUND) { LoadFromRegistry(); m_bModified = true; return NOERROR; } // Otherwise, it means that we got an error parsing the file. // Return the error, but leave the settings initialized to defaults // (We should be OK to continue, even with an error). else { m_bModified = false; return error; } } // Initialize to unmodified (as we load settings we might change this) m_bModified = false; // Loop over all elements for (i = 0; i < pData->GetContentElementCount(); i++) { CXMLElement *pItem = pData->GetContentElement(i); if (strEquals(pItem->GetTag(), OPTION_TAG)) { int iOption = FindOptionData(pItem->GetAttribute(NAME_ATTRIB)); if (iOption == -1) { kernelDebugLogMessage("Unknown option: %s", pItem->GetAttribute(NAME_ATTRIB).GetASCIIZPointer()); continue; } SetValue(iOption, pItem->GetAttribute(VALUE_ATTRIB), true); } else if (strEquals(pItem->GetTag(), KEY_MAP_TAG)) { if (error = m_KeyMap.ReadFromXML(pItem)) return error; } else if (m_pExtra) { bool bModified; if (error = m_pExtra->OnLoadSettings(pItem, &bModified)) return error; if (bModified) m_bModified = true; } } // Done delete pData; 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 CUniverse::InitFromXML (SDesignLoadCtx &Ctx, CXMLElement *pElement, CResourceDb &Resources) // InitFromXML // // Initializes the universe from an XML database { ALERROR error; int i; CIDTable UNIDMap(FALSE, FALSE); m_bNoImages = Ctx.bNoResources; // Initialize code chain if (error = m_CC.Boot()) return error; if (error = InitCodeChainPrimitives()) return error; // Create some fonts m_MapLabelFont.Create(MAP_LABEL_TYPEFACE, 12); m_SignFont.Create(SIGN_TYPEFACE, 11, true); // Make sure we have the right version if (!Ctx.bNoVersionCheck) { DWORD dwVersion; // Make sure we have the latest version of the .XML dwVersion = (DWORD)pElement->GetAttributeInteger(VERSION_ATTRIB); if (fileGetProductVersion() > dwVersion) { if (Resources.IsUsingExternalGameFile()) Ctx.sError = CONSTLIT("External definitions file (Transcendence.xml) is obsolete.\nPlease remove 'Transcendence.xml' file from game folder."); else Ctx.sError = CONSTLIT("Source definitions file (Transcendence.xml) is obsolete.\nPlease download the latest version at http://www.neurohack.com/transcendence/Downloads.html."); return ERR_FAIL; } // Make sure we have the latest version of the .EXE dwVersion = (DWORD)pElement->GetAttributeInteger(MIN_VERSION_ATTRIB); if (fileGetProductVersion() < dwVersion) { Ctx.sError = CONSTLIT("Source definitions file (Transcendence.xml) requires a newer version of Transcendence.exe.\nPlease download the latest version at http://www.neurohack.com/transcendence/Downloads.html."); return ERR_FAIL; } } // Load the Main XML file for (i = 0; i < pElement->GetContentElementCount(); i++) { CXMLElement *pDesc = pElement->GetContentElement(i); if (strEquals(pDesc->GetTag(), IMAGES_TAG)) error = InitImages(Ctx, pDesc, Resources); else if (strEquals(pDesc->GetTag(), SOUNDS_TAG)) error = InitSounds(Ctx, pDesc, Resources); else if (strEquals(pDesc->GetTag(), STATION_TYPE_RESOURCES_TAG)) error = InitStationTypeResources(Ctx, pDesc); else if (strEquals(pDesc->GetTag(), STAR_SYSTEM_TYPES_TAG)) error = InitStarSystemTypes(Ctx, pDesc); else if (strEquals(pDesc->GetTag(), MODULES_TAG)) error = LoadModules(Ctx, pDesc); else error = LoadDesignElement(Ctx, pDesc); // Check for error if (error) return error; } 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; }
ALERROR CGameSettings::Load (const CString &sFilespec, CString *retsError) // Load // // Load game settings from a file. If the file does not exist, then we // set settings to default values { ALERROR error; int i; // Initialize from defaults for (i = 0; i < OPTIONS_COUNT; i++) SetValue(i, CString(g_OptionData[i].pszDefaultValue, -1, true), true); // Look for a file in the current directory and see if it is writable. If // not, then look in AppData. We remember the place where we found a valid // file as our AppData root (and we base other directories off that). if (pathIsWritable(sFilespec)) { // AppData is current directory m_sAppData = NULL_STR; } else { m_sAppData = pathAddComponent(pathGetSpecialFolder(folderAppData), TRANSCENDENCE_APP_DATA); if (!pathCreate(m_sAppData) || !pathIsWritable(m_sAppData)) { *retsError = strPatternSubst(CONSTLIT("Unable to write to AppData folder: %s"), m_sAppData); return ERR_FAIL; } } // Settings file CString sSettingsFilespec = pathAddComponent(m_sAppData, sFilespec); // Load XML CFileReadBlock DataFile(sSettingsFilespec); CXMLElement *pData; CString sError; if (error = CXMLElement::ParseXML(&DataFile, &pData, retsError)) { // ERR_NOTFOUND means that we couldn't find the Settings.xml // file. In that case, initialize from defaults if (error == ERR_NOTFOUND) { LoadFromRegistry(); m_bModified = true; return NOERROR; } // Otherwise, it means that we got an error parsing the file. // Return the error, but leave the settings initialized to defaults // (We should be OK to continue, even with an error). else { m_bModified = false; return error; } } // Initialize to unmodified (as we load settings we might change this) m_bModified = false; // Loop over all elements for (i = 0; i < pData->GetContentElementCount(); i++) { CXMLElement *pItem = pData->GetContentElement(i); if (strEquals(pItem->GetTag(), OPTION_TAG)) { int iOption = FindOptionData(pItem->GetAttribute(NAME_ATTRIB)); if (iOption == -1) { kernelDebugLogMessage("Unknown option: %s", pItem->GetAttribute(NAME_ATTRIB)); continue; } SetValue(iOption, pItem->GetAttribute(VALUE_ATTRIB), true); } else if (strEquals(pItem->GetTag(), KEY_MAP_TAG)) { if (error = m_KeyMap.ReadFromXML(pItem)) return error; } else if (strEquals(pItem->GetTag(), EXTENSION_FOLDER_TAG)) { CString sFolder; if (pItem->FindAttribute(PATH_ATTRIB, &sFolder)) m_ExtensionFolders.Insert(sFolder); } else if (strEquals(pItem->GetTag(), EXTENSIONS_TAG)) { if (error = m_Extensions.ReadFromXML(pItem)) return error; } else if (m_pExtra) { bool bModified; if (error = m_pExtra->OnLoadSettings(pItem, &bModified)) return error; if (bModified) m_bModified = true; } } // Done delete pData; return NOERROR; }
ALERROR CLanguageDataBlock::InitFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc) // InitFromXML // // Initializes from an XML block { int i; for (i = 0; i < pDesc->GetContentElementCount(); i++) { CXMLElement *pItem = pDesc->GetContentElement(i); CString sID = pItem->GetAttribute(ID_ATTRIB); if (sID.IsBlank()) { Ctx.sError = strPatternSubst(CONSTLIT("Invalid id in <Language> block")); return ERR_FAIL; } if (strEquals(pItem->GetTag(), TEXT_TAG)) { // Link the code CCodeChainCtx CCCtx; ICCItem *pCode = CCCtx.Link(pItem->GetContentText(0), 0, NULL); if (pCode->IsError()) { Ctx.sError = strPatternSubst(CONSTLIT("Language id: %s : %s"), sID, pCode->GetStringValue()); return ERR_FAIL; } // Add an entry bool bIsNew; SEntry *pEntry = m_Data.SetAt(sID, &bIsNew); if (!bIsNew) { Ctx.sError = strPatternSubst(CONSTLIT("Duplicate <Language> element: %s"), sID); return ERR_FAIL; } // If pCode is a string and not an identifier, then we can just // store it directly. if (pCode->IsIdentifier() && pCode->IsQuoted()) { pEntry->pCode = NULL; pEntry->sText = pCode->GetStringValue(); } // Otherwise we store the code else pEntry->pCode = pCode->Reference(); // Done CCCtx.Discard(pCode); } else if (strEquals(pItem->GetTag(), MESSAGE_TAG)) { // Add an entry bool bIsNew; SEntry *pEntry = m_Data.SetAt(sID, &bIsNew); if (!bIsNew) { Ctx.sError = strPatternSubst(CONSTLIT("Duplicate <Language> element: %s"), sID); return ERR_FAIL; } // Set the text pEntry->pCode = NULL; pEntry->sText = pItem->GetAttribute(TEXT_ATTRIB); } else { Ctx.sError = strPatternSubst(CONSTLIT("Invalid element in <Language> block: <%s>"), pItem->GetTag()); return ERR_FAIL; } } return NOERROR; }
ALERROR CExtension::LoadModuleElement (SDesignLoadCtx &Ctx, CXMLElement *pDesc) // LoadModuleElement // // Loads <Module> { ALERROR error; CString sFilename = pDesc->GetAttribute(FILENAME_ATTRIB); // Load the module XML CXMLElement *pModuleXML; if (error = Ctx.pResDb->LoadModule(Ctx.sFolder, sFilename, &pModuleXML, &Ctx.sError)) { if (error == ERR_NOTFOUND) Ctx.sError = strPatternSubst(CONSTLIT("%s: %s"), Ctx.pResDb->GetFilespec(), Ctx.sError); return error; } if (!strEquals(pModuleXML->GetTag(), TRANSCENDENCE_MODULE_TAG)) { delete pModuleXML; Ctx.sError = strPatternSubst(CONSTLIT("Module must have <TranscendenceModule> root element: %s"), sFilename); return ERR_FAIL; } // We are loading a module bool bOldLoadModule = Ctx.bLoadModule; Ctx.bLoadModule = true; // Look for resources relative to the module path CString sOldFolder = Ctx.sFolder; CString sFolder = pathGetPath(sFilename); if (!sFolder.IsBlank() && Ctx.GetAPIVersion() >= 26) Ctx.sFolder = pathAddComponent(Ctx.sFolder, sFolder); // Errors credited to this file. CString sOldErrorFilespec = Ctx.sErrorFilespec; if (strEquals(pathGetExtension(sOldErrorFilespec), FILESPEC_TDB_EXTENSION)) Ctx.sErrorFilespec = strPatternSubst(CONSTLIT("%s#%s"), sOldErrorFilespec, sFilename); else Ctx.sErrorFilespec = sFilename; // Process each design element in the module if (error = LoadModuleContent(Ctx, pModuleXML)) return error; // Clean up Ctx.sFolder = sOldFolder; Ctx.sErrorFilespec = sOldErrorFilespec; Ctx.bLoadModule = bOldLoadModule; // If we're keeping the XML, then add it to our table if (Ctx.bKeepXML && !m_ModuleXML.Find(sFilename)) m_ModuleXML.Insert(sFilename, pModuleXML); else delete pModuleXML; return NOERROR; }