EventListenerManager::Listener* EventListenerManager::SetEventHandlerInternal( JS::Handle<JSObject*> aScopeObject, nsIAtom* aName, const nsAString& aTypeString, const nsEventHandler& aHandler, bool aPermitUntrustedEvents) { MOZ_ASSERT(aScopeObject || aHandler.HasEventHandler(), "Must have one or the other!"); MOZ_ASSERT(aName || !aTypeString.IsEmpty()); uint32_t eventType = nsContentUtils::GetEventId(aName); Listener* listener = FindEventHandler(eventType, aName, aTypeString); if (!listener) { // If we didn't find a script listener or no listeners existed // create and add a new one. EventListenerFlags flags; flags.mListenerIsJSListener = true; nsCOMPtr<nsIJSEventListener> jsListener; NS_NewJSEventListener(aScopeObject, mTarget, aName, aHandler, getter_AddRefs(jsListener)); EventListenerHolder listenerHolder(jsListener); AddEventListenerInternal(listenerHolder, eventType, aName, aTypeString, flags, true); listener = FindEventHandler(eventType, aName, aTypeString); } else { nsIJSEventListener* jsListener = listener->GetJSListener(); MOZ_ASSERT(jsListener, "How can we have an event handler with no nsIJSEventListener?"); bool same = jsListener->GetHandler() == aHandler; // Possibly the same listener, but update still the context and scope. jsListener->SetHandler(aHandler, aScopeObject); if (mTarget && !same && aName) { mTarget->EventListenerRemoved(aName); mTarget->EventListenerAdded(aName); } } // Set flag to indicate possible need for compilation later listener->mHandlerIsString = !aHandler.HasEventHandler(); if (aPermitUntrustedEvents) { listener->mFlags.mAllowUntrustedEvents = true; } return listener; }
ICCItem *CMission::FireOnReward (ICCItem *pData) // FireOnReward // // Fire <OnReward> // // Callers are responsible for discarding the result, if not NULL. { SEventHandlerDesc Event; if (FindEventHandler(EVENT_ON_REWARD, &Event)) { CCodeChainCtx Ctx; Ctx.SaveAndDefineSourceVar(this); Ctx.SaveAndDefineDataVar(pData); ICCItem *pResult = Ctx.Run(Event); if (pResult->IsError()) { ReportEventError(EVENT_ON_REWARD, pResult); Ctx.Discard(pResult); return NULL; } return pResult; } return NULL; }
ICCItem *CMission::FireOnDeclined (void) // FireOnDeclined // // Fire <OnDeclined>. We return the result of the event, which might contain // instructions for the mission screen. // // Callers are responsible for discarding the result, if not NULL. { SEventHandlerDesc Event; if (FindEventHandler(EVENT_ON_DECLINED, &Event)) { CCodeChainCtx Ctx; Ctx.SaveAndDefineSourceVar(this); ICCItem *pResult = Ctx.Run(Event); if (pResult->IsError()) { ReportEventError(EVENT_ON_DECLINED, pResult); Ctx.Discard(pResult); return NULL; } return pResult; } return NULL; }
Variant DynamicObject::m_RemoveEventHandler(int numargs, Variant args[]) { EventHandler *handler = FindEventHandler(args[0]); if (handler) { UnregisterEventHandler(handler); handler->DecRef(); } return VARNULL; }
bool CWeaponFireDesc::FireOnDamageOverlay (SDamageCtx &Ctx, CEnergyField *pOverlay) // FireOnDamageOverlay // // Fire OnDamageOverlay event. Returns TRUE if we should skip further overlay damage { SEventHandlerDesc Event; if (FindEventHandler(evtOnDamageOverlay, &Event)) { // Setup arguments CCodeChainCtx CCCtx; CCCtx.SaveAndDefineSourceVar(Ctx.pObj); CCCtx.DefineInteger(CONSTLIT("aArmorSeg"), Ctx.iSectHit); CCCtx.DefineInteger(CONSTLIT("aOverlayID"), pOverlay->GetID()); CCCtx.DefineSpaceObject(CONSTLIT("aCause"), Ctx.pCause); CCCtx.DefineSpaceObject(CONSTLIT("aAttacker"), Ctx.Attacker.GetObj()); CCCtx.DefineSpaceObject(CONSTLIT("aOrderGiver"), (Ctx.Attacker.GetObj() ? Ctx.Attacker.GetObj()->GetOrderGiver(Ctx.Attacker.GetCause()) : NULL)); CCCtx.DefineVector(CONSTLIT("aHitPos"), Ctx.vHitPos); CCCtx.DefineInteger(CONSTLIT("aHitDir"), Ctx.iDirection); CCCtx.DefineInteger(CONSTLIT("aDamageHP"), Ctx.iDamage); CCCtx.DefineString(CONSTLIT("aDamageType"), GetDamageShortName(Ctx.Damage.GetDamageType())); CCCtx.DefineItemType(CONSTLIT("aWeaponType"), Ctx.pDesc->GetWeaponType()); ICCItem *pResult = CCCtx.Run(Event); if (pResult->IsError()) Ctx.pObj->ReportEventError(ON_DAMAGE_OVERLAY_EVENT, pResult); // If we return Nil, then we continue processing bool bResult; if (pResult->IsNil()) bResult = false; // Otherwise, the result is the damage left else { Ctx.iDamage = pResult->GetIntegerValue(); bResult = true; } CCCtx.Discard(pResult); return bResult; } else return false; }
bool CWeaponFireDesc::FireOnFragment (const CDamageSource &Source, CSpaceObject *pShot, const CVector &vHitPos, CSpaceObject *pNearestObj, CSpaceObject *pTarget) // FireOnFragment // // Event fires when a shot fragments. If we return TRUE then we skip the default // fragmentation event. { SEventHandlerDesc Event; if (FindEventHandler(evtOnFragment, &Event)) { // Setup arguments CCodeChainCtx CCCtx; CCCtx.SaveAndDefineSourceVar(pShot); CCCtx.DefineSpaceObject(CONSTLIT("aNearestObj"), pNearestObj); CCCtx.DefineSpaceObject(CONSTLIT("aTargetObj"), pTarget); CCCtx.DefineVector(CONSTLIT("aHitPos"), vHitPos); CCCtx.DefineInteger(CONSTLIT("aHitDir"), (pShot ? pShot->GetRotation() : 0)); CCCtx.DefineItemType(CONSTLIT("aWeaponType"), GetWeaponType()); CCCtx.DefineString(CONSTLIT("aWeaponFragment"), m_sUNID); CSpaceObject *pAttacker = Source.GetObj(); CCCtx.DefineSpaceObject(CONSTLIT("aCause"), pShot); CCCtx.DefineSpaceObject(CONSTLIT("aAttacker"), pAttacker); CCCtx.DefineSpaceObject(CONSTLIT("aOrderGiver"), (pAttacker ? pAttacker->GetOrderGiver(Source.GetCause()) : NULL)); ICCItem *pResult = CCCtx.Run(Event); if (pResult->IsError()) pShot->ReportEventError(ON_FRAGMENT_EVENT, pResult); // If we return Nil, then we continue processing bool bResult; if (pResult->IsNil()) bResult = false; // Otherwise, we skip fragmentation else bResult = true; CCCtx.Discard(pResult); return bResult; } else return false; }
int DynamicObject::FireEvent(const char *event) { int rc = 0; EventHandler *handler = FindEventHandler(event); if (handler) { Tls *tls = tlsGet(); tls->object = this; lmbox_free(tls->event); tls->event = strdup(event); systemObject->Log(3, "Executing event handler %s for event %s in %s (run=%d)", handler->GetName(), event, name, systemObject->IsRunning()); rc = handler->Fire(); systemObject->Log(5, "Result is %d in %s from event handler %s for event %s", rc, name, handler->GetName(), event); handler->DecRef(); lmbox_destroy((void**)&tls->event); } return rc; }
void Object::UnsubscribeFromEvent(StringHash eventType) { for (;;) { EventHandler* previous; EventHandler* handler = FindEventHandler(eventType, &previous); if (handler) { if (handler->GetSender()) context_->RemoveEventReceiver(this, handler->GetSender(), eventType); else context_->RemoveEventReceiver(this, eventType); eventHandlers_.Erase(handler, previous); } else break; } }
void EventListenerManager::RemoveEventHandler(nsIAtom* aName, const nsAString& aTypeString) { if (mClearingListeners) { return; } uint32_t eventType = nsContentUtils::GetEventId(aName); Listener* listener = FindEventHandler(eventType, aName, aTypeString); if (listener) { mListeners.RemoveElementAt(uint32_t(listener - &mListeners.ElementAt(0))); mNoListenerForEvent = NS_EVENT_NULL; mNoListenerForEventAtom = nullptr; if (mTarget && aName) { mTarget->EventListenerRemoved(aName); } } }
const TypedEventHandler* EventListenerManager::GetTypedEventHandler(nsIAtom* aEventName, const nsAString& aTypeString) { uint32_t eventType = nsContentUtils::GetEventId(aEventName); Listener* listener = FindEventHandler(eventType, aEventName, aTypeString); if (!listener) { return nullptr; } JSEventHandler* jsEventHandler = listener->GetJSEventHandler(); if (listener->mHandlerIsString) { CompileEventHandlerInternal(listener, nullptr, nullptr); } const TypedEventHandler& typedHandler = jsEventHandler->GetTypedEventHandler(); return typedHandler.HasEventHandler() ? &typedHandler : nullptr; }
void CAdventureDesc::FireOnGameStart (void) // FireOnGameStart // // Fire OnGameStart event { SEventHandlerDesc Event; if (FindEventHandler(ON_GAME_START_EVENT, &Event)) { CCodeChainCtx Ctx; // Run code ICCItem *pResult = Ctx.Run(Event); if (pResult->IsError()) kernelDebugLogMessage("OnGameStart error: %s", pResult->GetStringValue()); Ctx.Discard(pResult); } }
void CMission::FireOnStart (void) // FireOnStart // // Fire <OnStarted> { SEventHandlerDesc Event; if (FindEventHandler(EVENT_ON_STARTED, &Event)) { CCodeChainCtx Ctx; Ctx.SaveAndDefineSourceVar(this); ICCItem *pResult = Ctx.Run(Event); if (pResult->IsError()) ReportEventError(EVENT_ON_STARTED, pResult); Ctx.Discard(pResult); } }
void CMission::FireOnSetPlayerTarget (const CString &sReason) // FireOnSetPlayerTarget // // Fire <OnSetPlayerTarget> { SEventHandlerDesc Event; if (FindEventHandler(EVENT_ON_SET_PLAYER_TARGET, &Event)) { CCodeChainCtx Ctx; Ctx.SaveAndDefineSourceVar(this); Ctx.DefineString(STR_A_REASON, sReason); ICCItem *pResult = Ctx.Run(Event); if (pResult->IsError()) ReportEventError(EVENT_ON_SET_PLAYER_TARGET, pResult); Ctx.Discard(pResult); } }
void CMission::FireCustomEvent (const CString &sEvent) // FireCustomEvent // // Fires a custom timed event { SEventHandlerDesc Event; if (FindEventHandler(sEvent, &Event)) { CCodeChainCtx Ctx; Ctx.SetEvent(eventDoEvent); Ctx.SaveAndDefineSourceVar(this); ICCItem *pResult = Ctx.Run(Event); if (pResult->IsError()) ReportEventError(sEvent, pResult); Ctx.Discard(pResult); } }
void CMission::FireOnReward (ICCItem *pData) // FireOnReward // // Fire <OnReward> { SEventHandlerDesc Event; if (FindEventHandler(EVENT_ON_REWARD, &Event)) { CCodeChainCtx Ctx; Ctx.SaveAndDefineSourceVar(this); Ctx.SaveAndDefineDataVar(pData); ICCItem *pResult = Ctx.Run(Event); if (pResult->IsError()) ReportEventError(EVENT_ON_REWARD, pResult); Ctx.Discard(pResult); } }
void CAdventureDesc::FireOnGameEnd (const CGameRecord &Game, const SBasicGameStats &BasicStats) // FireOnGameEnd // // Fire OnGameEnd event { SEventHandlerDesc Event; if (FindEventHandler(ON_GAME_END_EVENT, &Event)) { CCodeChainCtx Ctx; // Initialize variables Ctx.DefineInteger(CONSTLIT("aScore"), Game.GetScore()); Ctx.DefineInteger(CONSTLIT("aResurrectCount"), Game.GetResurrectCount()); Ctx.DefineInteger(CONSTLIT("aSystemsVisited"), BasicStats.iSystemsVisited); Ctx.DefineInteger(CONSTLIT("aEnemiesDestroyed"), BasicStats.iEnemiesDestroyed); Ctx.DefineInteger(CONSTLIT("aBestEnemiesDestroyed"), BasicStats.iBestEnemyDestroyedCount); if (BasicStats.dwBestEnemyDestroyed) Ctx.DefineInteger(CONSTLIT("aBestEnemyClass"), BasicStats.dwBestEnemyDestroyed); else Ctx.DefineNil(CONSTLIT("aBestEnemyClass")); Ctx.DefineString(CONSTLIT("aEndGameReason"), Game.GetEndGameReason()); Ctx.DefineString(CONSTLIT("aEpitaph"), Game.GetEndGameEpitaph()); Ctx.DefineString(CONSTLIT("aEpitaphOriginal"), Game.GetEndGameEpitaph()); Ctx.DefineString(CONSTLIT("aTime"), Game.GetPlayTimeString()); // Invoke ICCItem *pResult = Ctx.Run(Event); if (pResult->IsError()) kernelDebugLogMessage("OnGameEnd error: %s", pResult->GetStringValue()); Ctx.Discard(pResult); } }
void CMission::FireOnStop (const CString &sReason, ICCItem *pData) // FireOnStop // // Fire <OnCompleted> { SEventHandlerDesc Event; if (FindEventHandler(EVENT_ON_COMPLETED, &Event)) { CCodeChainCtx Ctx; Ctx.SaveAndDefineSourceVar(this); Ctx.SaveAndDefineDataVar(pData); Ctx.DefineString(STR_A_REASON, sReason); ICCItem *pResult = Ctx.Run(Event); if (pResult->IsError()) ReportEventError(EVENT_ON_COMPLETED, pResult); Ctx.Discard(pResult); } }
bool CWeaponFireDesc::FireOnDamageShields (SDamageCtx &Ctx, int iDevice) // FireOnDamageShields // // Fire OnDamageShields event. Returns TRUE if we should skip further shields damage { SEventHandlerDesc Event; if (FindEventHandler(evtOnDamageShields, &Event)) { // Setup arguments CCodeChainCtx CCCtx; CItemListManipulator ItemList(Ctx.pObj->GetItemList()); CShip *pShip = Ctx.pObj->AsShip(); if (pShip) pShip->SetCursorAtDevice(ItemList, iDevice); CCCtx.SaveAndDefineSourceVar(Ctx.pObj); CCCtx.DefineInteger(CONSTLIT("aArmorSeg"), Ctx.iSectHit); CCCtx.DefineInteger(CONSTLIT("aDevice"), iDevice); CCCtx.DefineItem(CONSTLIT("aDeviceItem"), ItemList.GetItemAtCursor()); CCCtx.DefineSpaceObject(CONSTLIT("aCause"), Ctx.pCause); CCCtx.DefineSpaceObject(CONSTLIT("aAttacker"), Ctx.Attacker.GetObj()); CCCtx.DefineSpaceObject(CONSTLIT("aOrderGiver"), (Ctx.Attacker.GetObj() ? Ctx.Attacker.GetObj()->GetOrderGiver(Ctx.Attacker.GetCause()) : NULL)); CCCtx.DefineVector(CONSTLIT("aHitPos"), Ctx.vHitPos); CCCtx.DefineInteger(CONSTLIT("aHitDir"), Ctx.iDirection); CCCtx.DefineInteger(CONSTLIT("aDamageHP"), Ctx.iDamage); CCCtx.DefineString(CONSTLIT("aDamageType"), GetDamageShortName(Ctx.Damage.GetDamageType())); CCCtx.DefineItemType(CONSTLIT("aWeaponType"), Ctx.pDesc->GetWeaponType()); CCCtx.DefineInteger(CONSTLIT("aShieldHP"), Ctx.iHPLeft); CCCtx.DefineInteger(CONSTLIT("aShieldDamageHP"), Ctx.iShieldDamage); CCCtx.DefineInteger(CONSTLIT("aArmorDamageHP"), Ctx.iDamage - Ctx.iAbsorb); if (Ctx.bReflect) { CCCtx.DefineString(CONSTLIT("aShieldReflect"), STR_SHIELD_REFLECT); CCCtx.DefineInteger(CONSTLIT("aOriginalShieldDamageHP"), Ctx.iOriginalShieldDamage); CCCtx.DefineInteger(CONSTLIT("aOriginalArmorDamageHP"), Ctx.iDamage - Ctx.iOriginalAbsorb); } else { CCCtx.DefineNil(CONSTLIT("aShieldReflect")); CCCtx.DefineInteger(CONSTLIT("aOriginalShieldDamageHP"), Ctx.iShieldDamage); CCCtx.DefineInteger(CONSTLIT("aOriginalArmorDamageHP"), Ctx.iDamage - Ctx.iAbsorb); } ICCItem *pResult = CCCtx.Run(Event); // If we return Nil, then we continue processing bool bResult; if (pResult->IsNil()) bResult = false; // If this is an integer, we pass damage to armor else if (pResult->IsInteger()) { Ctx.iDamage = pResult->GetIntegerValue(); bResult = true; } // If we return a list, then modify variables else if (pResult->IsList()) { // A single value means we modified the damage to armor if (pResult->GetCount() == 1) { if (strEquals(pResult->GetElement(0)->GetStringValue(), STR_SHIELD_REFLECT)) { Ctx.bReflect = true; Ctx.iAbsorb = Ctx.iDamage; Ctx.iShieldDamage = 0; } else { Ctx.iShieldDamage = Max(0, Min(pResult->GetElement(0)->GetIntegerValue(), Ctx.iHPLeft)); if (Ctx.bReflect) { Ctx.bReflect = false; Ctx.iAbsorb = Ctx.iOriginalAbsorb; } } } // Two values mean we modified both damage to armor and shield damage else if (pResult->GetCount() == 2) { Ctx.bReflect = false; Ctx.iShieldDamage = Max(0, Min(pResult->GetElement(0)->GetIntegerValue(), Ctx.iHPLeft)); Ctx.iAbsorb = Max(0, Ctx.iDamage - Max(0, pResult->GetElement(1)->GetIntegerValue())); } // Otherwise, we deal with reflection else { Ctx.bReflect = strEquals(pResult->GetElement(0)->GetStringValue(), STR_SHIELD_REFLECT); Ctx.iShieldDamage = Max(0, Min(pResult->GetElement(1)->GetIntegerValue(), Ctx.iHPLeft)); Ctx.iAbsorb = Max(0, Ctx.iDamage - Max(0, pResult->GetElement(2)->GetIntegerValue())); } // Proceed with processing bResult = false; } // If this is the string "reflect" then we reflect else if (strEquals(pResult->GetStringValue(), STR_SHIELD_REFLECT)) { Ctx.bReflect = true; Ctx.iAbsorb = Ctx.iDamage; Ctx.iShieldDamage = 0; bResult = false; } // Otherwise, error else { Ctx.pObj->ReportEventError(ON_DAMAGE_OVERLAY_EVENT, pResult); bResult = true; } CCCtx.Discard(pResult); return bResult; } else return false; }
ALERROR CWeaponFireDesc::OnDesignLoadComplete (SDesignLoadCtx &Ctx) // OnDesignLoadComplete // // Done loading all design elements { ALERROR error; int i; if (error = m_Image.OnDesignLoadComplete(Ctx)) return error; if (error = m_ExhaustImage.OnDesignLoadComplete(Ctx)) return error; if (error = m_pAmmoType.Bind(Ctx)) return error; if (error = m_pEffect.Bind(Ctx)) return error; if (error = m_pHitEffect.Bind(Ctx)) return error; if (error = m_pFireEffect.Bind(Ctx)) return error; if (m_pEnhanced) if (error = m_pEnhanced->OnDesignLoadComplete(Ctx)) return error; // Load some events for efficiency for (i = 0; i < evtCount; i++) { if (!FindEventHandler(CString(CACHED_EVENTS[i], -1, true), &m_CachedEvents[i])) { m_CachedEvents[i].pExtension = NULL; m_CachedEvents[i].pCode = NULL; } } // If we have an OnFragment event, then we enable proximity blast if (HasOnFragmentEvent()) m_bProximityBlast = true; // Fragment SFragmentDesc *pNext = m_pFirstFragment; while (pNext) { if (error = pNext->pDesc->OnDesignLoadComplete(Ctx)) return error; pNext = pNext->pNext; } return NOERROR; }
ALERROR CEnergyFieldType::OnCreateFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc) // OnCreateFromXML // // Create from XML { ALERROR error; // Effect CXMLElement *pEffect = pDesc->GetContentElementByTag(EFFECT_TAG); if (pEffect) { if (error = CEffectCreator::CreateFromXML(Ctx, pEffect, strPatternSubst(CONSTLIT("%d:e"), GetUNID()), &m_pEffect)) { Ctx.sError = strPatternSubst(CONSTLIT("energy field %x: Unable to load effect"), GetUNID()); return error; } } pEffect = pDesc->GetContentElementByTag(HIT_EFFECT_TAG); if (pEffect == NULL) pEffect = pDesc->GetContentElementByTag(EFFECT_WHEN_HIT_TAG); if (pEffect) { if (error = CEffectCreator::CreateFromXML(Ctx, pEffect, strPatternSubst(CONSTLIT("%d:h"), GetUNID()), &m_pHitEffect)) { Ctx.sError = strPatternSubst(CONSTLIT("energy field %x: Unable to load hit effect"), GetUNID()); return error; } // For compatibility with previous versions, if we're using the old // <ShipEnergyFieldType> then altEffect defaults to TRUE. Otherwise, for new // <OverlayType> altEffect defaults to false. bool bAltEffect; if (pEffect->FindAttributeBool(ALT_EFFECT_ATTRIB, &bAltEffect)) m_bAltHitEffect = bAltEffect; else m_bAltHitEffect = strEquals(pDesc->GetTag(), SHIP_ENERGY_FIELD_TYPE_TAG); } else m_bAltHitEffect = false; // Rotation m_bRotateWithShip = !pDesc->GetAttributeBool(IGNORE_SHIP_ROTATION_ATTRIB); // Damage adjustment LoadDamageAdj(pDesc, ABSORB_ADJ_ATTRIB, m_iAbsorbAdj); // Bonus adjustment LoadDamageAdj(pDesc, BONUS_ADJ_ATTRIB, m_iBonusAdj); // Load the weapon suppress if (error = m_WeaponSuppress.InitFromXML(pDesc->GetAttribute(WEAPON_SUPPRESS_ATTRIB))) { Ctx.sError = CONSTLIT("Unable to load weapon suppress attribute"); return error; } // Keep track of the events that we have m_bHasOnUpdateEvent = FindEventHandler(ON_UPDATE_EVENT); // Done return NOERROR; }
bool Object::HasSubscribedToEvent(StringHash eventType) const { return FindEventHandler(eventType) != 0; }
ALERROR COverlayType::OnCreateFromXML (SDesignLoadCtx &Ctx, CXMLElement *pDesc) // OnCreateFromXML // // Create from XML { ALERROR error; // Effect CXMLElement *pEffect = pDesc->GetContentElementByTag(EFFECT_TAG); if (pEffect) { if (error = CEffectCreator::CreateFromXML(Ctx, pEffect, strPatternSubst(CONSTLIT("%d:e"), GetUNID()), &m_pEffect)) { Ctx.sError = strPatternSubst(CONSTLIT("energy field %x: Unable to load effect"), GetUNID()); return error; } } pEffect = pDesc->GetContentElementByTag(HIT_EFFECT_TAG); if (pEffect == NULL) pEffect = pDesc->GetContentElementByTag(EFFECT_WHEN_HIT_TAG); if (pEffect) { if (error = CEffectCreator::CreateFromXML(Ctx, pEffect, strPatternSubst(CONSTLIT("%d:h"), GetUNID()), &m_pHitEffect)) { Ctx.sError = strPatternSubst(CONSTLIT("energy field %x: Unable to load hit effect"), GetUNID()); return error; } // For compatibility with previous versions, if we're using the old // <ShipEnergyFieldType> then altEffect defaults to TRUE. Otherwise, for new // <OverlayType> altEffect defaults to false. bool bAltEffect; if (pEffect->FindAttributeBool(ALT_EFFECT_ATTRIB, &bAltEffect)) m_fAltHitEffect = bAltEffect; else m_fAltHitEffect = strEquals(pDesc->GetTag(), SHIP_ENERGY_FIELD_TYPE_TAG); } else m_fAltHitEffect = false; // Rotation m_fRotateWithShip = !pDesc->GetAttributeBool(IGNORE_SHIP_ROTATION_ATTRIB); // Damage adjustment int iAbsorbCount; LoadDamageAdj(pDesc, ABSORB_ADJ_ATTRIB, m_iAbsorbAdj, &iAbsorbCount); // Bonus adjustment LoadDamageAdj(pDesc, BONUS_ADJ_ATTRIB, m_iBonusAdj); // Load the weapon suppress if (error = m_WeaponSuppress.InitFromXML(pDesc->GetAttribute(WEAPON_SUPPRESS_ATTRIB))) { Ctx.sError = CONSTLIT("Unable to load weapon suppress attribute"); return error; } // Keep track of the events that we have m_fHasOnUpdateEvent = FindEventHandler(ON_UPDATE_EVENT); // Are we a field/shield overlay (or part of hull)? // By default, we are a shield overlay if we absorb damage. bool bValue; if (pDesc->FindAttributeBool(SHIELD_OVERLAY_ATTRIB, &bValue)) m_fShieldOverlay = bValue; else m_fShieldOverlay = (iAbsorbCount > 0); // Counter CXMLElement *pCounter = pDesc->GetContentElementByTag(COUNTER_TAG); if (pCounter) { CString sStyle = pCounter->GetAttribute(STYLE_ATTRIB); if (strEquals(sStyle, COUNTER_PROGRESS)) m_iCounterType = counterProgress; else if (strEquals(sStyle, COUNTER_RADIUS)) m_iCounterType = counterRadius; else { Ctx.sError = strPatternSubst(CONSTLIT("Unknown counter style: %s"), sStyle); return ERR_FAIL; } m_sCounterLabel = pCounter->GetAttribute(LABEL_ATTRIB); m_iCounterMax = pCounter->GetAttributeIntegerBounded(MAX_ATTRIB, 0, -1, 100); m_wCounterColor = ::LoadRGBColor(pCounter->GetAttribute(COLOR_ATTRIB)); } else { m_iCounterType = counterNone; m_iCounterMax = 0; m_wCounterColor = 0; } // Options m_fDisarmShip = pDesc->GetAttributeBool(DISARM_ATTRIB); m_fParalyzeShip = pDesc->GetAttributeBool(PARALYZE_ATTRIB); m_fDisableShipScreen = pDesc->GetAttributeBool(DISABLE_SHIP_SCREEN_ATTRIB); m_fSpinShip = pDesc->GetAttributeBool(SPIN_ATTRIB); int iDrag; if (pDesc->FindAttributeInteger(DRAG_ATTRIB, &iDrag)) m_rDrag = Min(Max(0, iDrag), 100) / 100.0; else m_rDrag = 1.0; // Done return NOERROR; }