单败重构
This commit is contained in:
parent
5aabaddc31
commit
292d913305
545
public/AlliedAntiAirShip.xml
Normal file
545
public/AlliedAntiAirShip.xml
Normal file
@ -0,0 +1,545 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AssetDeclaration xmlns="uri:ea.com:eala:asset" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xai="uri:ea.com:eala:asset:instance">
|
||||
<Tags></Tags>
|
||||
<Includes>
|
||||
<Include type="all" source="DATA:GlobalData/GlobalDefines.xml" />
|
||||
<Include
|
||||
type="all"
|
||||
source="ART:AUAntiAirShip_D.xml" />
|
||||
<Include
|
||||
type="all"
|
||||
source="ART:AUAntiAirShip_FX.w3x" />
|
||||
<Include
|
||||
type="all"
|
||||
source="ART:AUAntiAirShip_FPZ.w3x" />
|
||||
<Include
|
||||
type="all"
|
||||
source="ART:AUAntiAirShip_SKN.w3x" />
|
||||
<Include
|
||||
type="all"
|
||||
source="ART:FXGradient01.xml" />
|
||||
<Include
|
||||
type="all"
|
||||
source="ART:FXTracer.xml" />
|
||||
<Include
|
||||
type="all"
|
||||
source="ART:FXTracerHeroic.xml" />
|
||||
<!-- needed for temp laserEndParticleSystemFX? -->
|
||||
<Include
|
||||
type="all"
|
||||
source="ART:SUAntiVehicleVehicleTech3_FX.w3x" />
|
||||
<Include
|
||||
type="instance"
|
||||
source="ART:FXGrid_3.xml" />
|
||||
<Include
|
||||
type="instance"
|
||||
source="ART:FXHarpoonBeam.xml" />
|
||||
<!-- Base Object -->
|
||||
<Include
|
||||
type="instance"
|
||||
source="DATA:BaseObjects/BaseVehicle.xml" />
|
||||
</Includes>
|
||||
<!-- aka The Hydrofoil -->
|
||||
<GameObject
|
||||
id="AlliedAntiAirShip"
|
||||
inheritFrom="BaseVehicle"
|
||||
SelectPortrait="Portrait_AlliedAntiAirShip"
|
||||
ButtonImage="Button_AlliedAntiAirShip_on"
|
||||
Side="Allies"
|
||||
SubGroupPriority="440"
|
||||
EditorSorting="UNIT"
|
||||
HealthBoxHeightOffset="30"
|
||||
TransportSlotCount="10"
|
||||
BuildTime="10"
|
||||
CommandSet="AlliedAntiAirShipCommandSet"
|
||||
KindOf="SELECTABLE CAN_ATTACK CAN_CAST_REFLECTIONS SCORE VEHICLE SHIP CAN_BE_FAVORITE_UNIT"
|
||||
RadarPriority="UNIT"
|
||||
ProductionQueueType="WATERCRAFT"
|
||||
UnitCategory="VEHICLE"
|
||||
WeaponCategory="CANNON"
|
||||
VoicePriority="188"
|
||||
EditorName="AlliedAntiAirShip"
|
||||
Description="Desc:AlliedAntiAirShip"
|
||||
TypeDescription="Type:AlliedAntiAirShip"
|
||||
UnitIntro="Allied_Hydrofoil_UnitIntro">
|
||||
<DisplayName
|
||||
xai:joinAction="Replace" xmlns:xai="uri:ea.com:eala:asset:instance">Name:AlliedAntiAirShip</DisplayName>
|
||||
<ObjectResourceInfo>
|
||||
<BuildCost Account="=$ACCOUNT_ORE" Amount="900"/>
|
||||
</ObjectResourceInfo>
|
||||
<ArmorSet
|
||||
Armor="AlliedAntiAirShipArmor"
|
||||
DamageFX="VehicleDamageFX" />
|
||||
<LocomotorSet
|
||||
id="DefaultWaterLocomotorSet"
|
||||
Locomotor="AlliedAntiAirShipWaterLocomotor"
|
||||
Condition="NORMAL"
|
||||
Speed="125.0" />
|
||||
<LocomotorSet
|
||||
Locomotor="AlliedAntiAirShipWaterLocomotor_LeavingFactory"
|
||||
Condition="EXITING_PRODUCTION_STRUCTURE"
|
||||
Speed="125.0" />
|
||||
<SkirmishAIInformation
|
||||
UnitBuilderStandardCombatUnit="true" />
|
||||
<Draws>
|
||||
<ScriptedModelDraw
|
||||
id="ModuleTag_Draw"
|
||||
OkToChangeModelColor="true"
|
||||
InitialRecoilSpeed="0.1"
|
||||
MaxRecoilDistance="0.1"
|
||||
RecoilDamping="2.0"
|
||||
RecoilSettleSpeed="3.0"
|
||||
ExtraPublicBone="FX_Weapon_01 FX_Weapon_02" >
|
||||
<ModelConditionState
|
||||
ParseCondStateType="PARSE_DEFAULT"
|
||||
RetainSubObjects="true">
|
||||
<Model
|
||||
Name="AUAntiAirShip_SKN" />
|
||||
<WeaponFireFXBone
|
||||
WeaponSlotID="1"
|
||||
WeaponSlotType="PRIMARY_WEAPON"
|
||||
BoneName="FX_Weapon_01" />
|
||||
<WeaponRecoilBone
|
||||
WeaponSlotID="1"
|
||||
WeaponSlotType="PRIMARY_WEAPON"
|
||||
BoneName="FX_Weapon_01" />
|
||||
<WeaponLaunchBone
|
||||
WeaponSlotID="1"
|
||||
WeaponSlotType="PRIMARY_WEAPON"
|
||||
BoneName="FX_Weapon_01" />
|
||||
|
||||
<WeaponFireFXBone
|
||||
WeaponSlotID="1"
|
||||
WeaponSlotType="SECONDARY_WEAPON"
|
||||
BoneName="FX_Weapon_02" />
|
||||
<WeaponRecoilBone
|
||||
WeaponSlotID="1"
|
||||
WeaponSlotType="SECONDARY_WEAPON"
|
||||
BoneName="FX_Weapon_02" />
|
||||
<WeaponLaunchBone
|
||||
WeaponSlotID="1"
|
||||
WeaponSlotType="SECONDARY_WEAPON"
|
||||
BoneName="FX_Weapon_02" />
|
||||
<Turret
|
||||
TurretNameKey="turret"
|
||||
TurretPitch="Turret_Pitch"
|
||||
TurretID="1" />
|
||||
</ModelConditionState>
|
||||
|
||||
<ModelConditionState
|
||||
ParseCondStateType="PARSE_NORMAL"
|
||||
ConditionsYes="FORMATION_PREVIEW">
|
||||
<Model
|
||||
Name="AUAntiAirShip_SKN" />
|
||||
<Material
|
||||
ShaderName="FX_FormPreview.fx"
|
||||
TechniqueName="Default">
|
||||
<Constants>
|
||||
<Texture Name="SpecMap">
|
||||
<Value>FXGradient01</Value>
|
||||
</Texture>
|
||||
</Constants>
|
||||
</Material>
|
||||
</ModelConditionState>
|
||||
<ModelConditionState
|
||||
ParseCondStateType="PARSE_NORMAL"
|
||||
RetainSubObjects="true"
|
||||
ConditionsYes="REALLYDAMAGED">
|
||||
<Model
|
||||
Name="AUAntiAirShip_SKN" />
|
||||
<Texture
|
||||
Original="AUAntiAirShip"
|
||||
New="AUAntiAirShip_D" />
|
||||
</ModelConditionState>
|
||||
|
||||
<AnimationState
|
||||
ParseCondStateType="PARSE_DEFAULT">
|
||||
<Script>
|
||||
CurDrawableShowSubObjectPermanently("GUN")
|
||||
CurDrawableHideSubObjectPermanently("BEAM")
|
||||
</Script>
|
||||
<ParticleSysBone
|
||||
BoneName="None"
|
||||
FXParticleSystemTemplate="SmallShipWakeIdle"
|
||||
FollowBone="false" />
|
||||
</AnimationState>
|
||||
|
||||
<AnimationState
|
||||
ParseCondStateType="PARSE_NORMAL"
|
||||
ConditionsYes="MOVING">
|
||||
<ParticleSysBone
|
||||
BoneName="NONE"
|
||||
FXParticleSystemTemplate="AUHydrofoilWaterWake"
|
||||
FollowBone="false" />
|
||||
</AnimationState>
|
||||
<AnimationState
|
||||
ParseCondStateType="PARSE_NORMAL"
|
||||
ConditionsYes="WEAPONSTATE_TWO">
|
||||
<Script>
|
||||
CurDrawableHideSubObjectPermanently("GUN")
|
||||
CurDrawableShowSubObjectPermanently("BEAM")
|
||||
</Script>
|
||||
</AnimationState>
|
||||
</ScriptedModelDraw>
|
||||
|
||||
<ScriptedModelDraw
|
||||
id="ModuleTag_DrawZ"
|
||||
OkToChangeModelColor="true"
|
||||
InitialRecoilSpeed="0.1"
|
||||
MaxRecoilDistance="0.1"
|
||||
RecoilDamping="2.0"
|
||||
RecoilSettleSpeed="3.0"
|
||||
ExtraPublicBone="FX_Weapon_01 FX_Weapon_02">
|
||||
<ModelConditionState
|
||||
ParseCondStateType="PARSE_DEFAULT"
|
||||
RetainSubObjects="true">
|
||||
<Model
|
||||
Name="" />
|
||||
</ModelConditionState>
|
||||
|
||||
<ModelConditionState
|
||||
ParseCondStateType="PARSE_NORMAL"
|
||||
ConditionsYes="FORMATION_PREVIEW">
|
||||
<Model
|
||||
Name="AUAntiAirShip_FPZ" />
|
||||
</ModelConditionState>
|
||||
|
||||
<AnimationState
|
||||
ParseCondStateType="PARSE_DEFAULT">
|
||||
<Script>
|
||||
CurDrawableShowSubObjectPermanently("GUN")
|
||||
CurDrawableHideSubObjectPermanently("BEAM")
|
||||
</Script>
|
||||
</AnimationState>
|
||||
</ScriptedModelDraw>
|
||||
|
||||
<!-- Used in the Weapon Scramble Beam -->
|
||||
<LaserDraw
|
||||
id="ModuleTag_LaserDraw"
|
||||
Texture1_UTile="1"
|
||||
Texture1_VTile="1"
|
||||
Texture1_UScrollRate="0"
|
||||
Texture1_VScrollRate="0"
|
||||
Texture1_NumFrames="1"
|
||||
Texture1_FrameRate="30"
|
||||
Texture2_UTile="1"
|
||||
Texture2_VTile="1"
|
||||
Texture2_UScrollRate="0"
|
||||
Texture2_VScrollRate="1"
|
||||
Texture2_NumFrames="1"
|
||||
Texture2_FrameRate="30"
|
||||
LaserWidth="40"
|
||||
LaserStateID="1">
|
||||
<FXShader
|
||||
ShaderName="Laser.fx"
|
||||
TechniqueIndex="0">
|
||||
<Constants>
|
||||
<Texture
|
||||
Name="Texture1">
|
||||
<Value>FXGrid_3</Value>
|
||||
</Texture>
|
||||
<Texture
|
||||
Name="Texture2">
|
||||
<Value>FXInterlacedMask2</Value>
|
||||
</Texture>
|
||||
<Float Name="ColorEmissive">
|
||||
<Value>0.00000</Value>
|
||||
<Value>2.00000</Value>
|
||||
<Value>1.000000</Value>
|
||||
</Float>
|
||||
</Constants>
|
||||
</FXShader>
|
||||
</LaserDraw>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Used for the Phalanx Gun -->
|
||||
<TracerModelDraw
|
||||
id="ModuleTag_TracerModelDraw"
|
||||
MinLength="10.0"
|
||||
MaxLength="25.0"
|
||||
Width="15.0"
|
||||
MinSpeed="22"
|
||||
MaxSpeed="32"
|
||||
SweepSpeed="3.0"
|
||||
SpreadAngle="5.0"
|
||||
MinTracersPerFrame="0.4"
|
||||
MaxTracersPerFrame="0.4"
|
||||
FrameLifeTime="25"
|
||||
WeaponSlotType="PRIMARY_WEAPON"
|
||||
Texture="FXTracer"
|
||||
UseAdditiveBlending="true" >
|
||||
<HeadColor
|
||||
r="1.0"
|
||||
g="1.0"
|
||||
b="1.0"
|
||||
a="1.0" />
|
||||
<TailColor
|
||||
r="1.0"
|
||||
g="0.75"
|
||||
b="0.65"
|
||||
a="0.0" />
|
||||
<ObjectStatusValidation
|
||||
ForbiddenStatus="WEAPON_UPGRADED_01 GENERIC_TOGGLE_STATE" />
|
||||
</TracerModelDraw>
|
||||
<TracerModelDraw
|
||||
id="ModuleTag_TracerModelDrawVeterancy"
|
||||
MinLength="10.0"
|
||||
MaxLength="25.0"
|
||||
Width="15.0"
|
||||
MinSpeed="30"
|
||||
MaxSpeed="30"
|
||||
SweepSpeed="0.5"
|
||||
SpreadAngle="0.5"
|
||||
MinTracersPerFrame="0.4"
|
||||
MaxTracersPerFrame="0.4"
|
||||
FrameLifeTime="35"
|
||||
WeaponSlotType="PRIMARY_WEAPON"
|
||||
Texture="FXTracerHeroic"
|
||||
UseAdditiveBlending="true" >
|
||||
<HeadColor
|
||||
r="1.0"
|
||||
g="0.0"
|
||||
b="0.0"
|
||||
a="1.0" />
|
||||
<TailColor
|
||||
r="1.0"
|
||||
g="0.75"
|
||||
b="0.65"
|
||||
a="0.0" />
|
||||
<ObjectStatusValidation
|
||||
RequiredStatus="WEAPON_UPGRADED_01"
|
||||
ForbiddenStatus="GENERIC_TOGGLE_STATE" />
|
||||
</TracerModelDraw>
|
||||
<!-- DRAW PARTICLES -->
|
||||
|
||||
<ScriptedModelDraw
|
||||
id="ModuleTag_Draw_FX"
|
||||
OkToChangeModelColor="true">
|
||||
<ModelConditionState
|
||||
ParseCondStateType="PARSE_DEFAULT">
|
||||
<Model
|
||||
Name="AUAntiAirShip_FX" />
|
||||
</ModelConditionState>
|
||||
<ModelConditionState
|
||||
ParseCondStateType="PARSE_NORMAL"
|
||||
ConditionsYes="DAMAGED">
|
||||
<Model
|
||||
Name="AUAntiAirShip_FX" />
|
||||
<ParticleSysBone
|
||||
BoneName="FX_BONE01"
|
||||
FXParticleSystemTemplate="VehicleDamageSmoke"
|
||||
FollowBone="true" />
|
||||
|
||||
</ModelConditionState>
|
||||
<ModelConditionState
|
||||
ParseCondStateType="PARSE_NORMAL"
|
||||
ConditionsYes="REALLYDAMAGED">
|
||||
<Model
|
||||
Name="AUAntiAirShip_FX" />
|
||||
<ParticleSysBone
|
||||
BoneName="FX_BONE01"
|
||||
FXParticleSystemTemplate="VehicleDamageSmoke"
|
||||
FollowBone="true" />
|
||||
<ParticleSysBone
|
||||
BoneName="FX_BONE01"
|
||||
FXParticleSystemTemplate="VehicleDamageFire"
|
||||
FollowBone="true" />
|
||||
<ParticleSysBone
|
||||
BoneName="FX_BONE01"
|
||||
FXParticleSystemTemplate="VehicleDamageFire02"
|
||||
FollowBone="true" />
|
||||
|
||||
</ModelConditionState>
|
||||
</ScriptedModelDraw>
|
||||
|
||||
|
||||
</Draws>
|
||||
<Behaviors>
|
||||
<WeaponSetUpdate
|
||||
id="ModuleTag_WeaponSetUpdate">
|
||||
<WeaponSlotTurret
|
||||
ID="1">
|
||||
<!-- This weapon is always around, but the weapon template itself prevents it
|
||||
from being able to be fired once it's upgraded. -->
|
||||
<Weapon
|
||||
Ordering="PRIMARY_WEAPON"
|
||||
Template="AlliedAntiAirShipPhalanxGun"
|
||||
ForbiddenObjectStatus="GENERIC_TOGGLE_STATE"
|
||||
/>
|
||||
<Weapon
|
||||
Ordering="SECONDARY_WEAPON"
|
||||
Template="AlliedAntiAirShipWeaponScrambler"
|
||||
ObjectStatus="GENERIC_TOGGLE_STATE"/>
|
||||
<TurretSettings
|
||||
TurretTurnRate="360"
|
||||
MinimumPitch="0d"
|
||||
AllowsPitch="true"
|
||||
TurretPitchRate="180"
|
||||
MinIdleScanTime="1.0s"
|
||||
MaxIdleScanTime="5.0s"
|
||||
MinIdleScanAngle="10.0"
|
||||
MaxIdleScanAngle="90.0"
|
||||
ComeToHaltJiggle="3d">
|
||||
<TurretAITargetChooserData
|
||||
IdleScanDelay="=$FAST_IDLE_SCAN_DELAY"
|
||||
CanAcquireDynamicIfAssignedOutOfRange="true" />
|
||||
</TurretSettings>
|
||||
</WeaponSlotTurret>
|
||||
</WeaponSetUpdate>
|
||||
<Physics
|
||||
id="ModuleTag_Physics" />
|
||||
<CreateObjectDie
|
||||
id="ModuleTag_CreateObjectDie"
|
||||
CreationList="AUAntiAirShip_Die_OCL">
|
||||
<DieMuxData
|
||||
DeathTypes="ALL"
|
||||
DeathTypesForbidden="FLOODED"/>
|
||||
</CreateObjectDie>
|
||||
<CreateObjectDie
|
||||
id="ModuleTag_CreateObjectDieWhole"
|
||||
CreationList="AUAntiAirShip_Die_OCL">
|
||||
<DieMuxData
|
||||
DeathTypes="FLOODED" />
|
||||
</CreateObjectDie>
|
||||
<DynamicsUpdate
|
||||
id="ModuleTag_DefaultDynamicsUpdate"
|
||||
xai:joinAction="Remove" />
|
||||
<DestroyDie
|
||||
id="ModuleTag_Die">
|
||||
<DieMuxData
|
||||
DeathTypes="ALL" />
|
||||
</DestroyDie>
|
||||
<FXListBehavior
|
||||
id="ModuleTag_FXList">
|
||||
<DieMuxData
|
||||
DeathTypes="ALL" />
|
||||
<Event
|
||||
Index="onDeath"
|
||||
FX="FX_ALL_HydrofoilDie" />
|
||||
</FXListBehavior>
|
||||
|
||||
<!-- The toggle for the Weapon Scrambler -->
|
||||
<SpecialPower
|
||||
id="ModuleTag_ActivateWeaponScrambler"
|
||||
SpecialPowerTemplate="SpecialPower_ToggleWeaponScrambler"
|
||||
UpdateModuleStartsAttack="true" />
|
||||
<ToggleStatusSpecialAbilityUpdate
|
||||
id="ModuleTag_ActivateWeaponScramblerUpdate"
|
||||
SpecialPowerTemplate="SpecialPower_ToggleWeaponScrambler"
|
||||
Options="RECONSTITUTE_STORED_COMMAND">
|
||||
|
||||
<ToggleState
|
||||
EnterStateSound="ALL_HydroFoil_ScramblerToggleOffMS">
|
||||
<SkirmishAiInfo
|
||||
ToggleHint="TOGGLE_DEFAULT">
|
||||
<StateWeapon
|
||||
Weapon="AlliedAntiAirShipPhalanxGun" />
|
||||
</SkirmishAiInfo>
|
||||
</ToggleState>
|
||||
|
||||
<ToggleState
|
||||
ObjectStatus="GENERIC_TOGGLE_STATE"
|
||||
ModelConditions="WEAPONSTATE_TWO"
|
||||
EnterStateSound="ALL_HydroFoil_ScramblerToggleOnMS">
|
||||
<SkirmishAiInfo
|
||||
ToggleHint="TOGGLE_LOCKDOWN"
|
||||
NeverUseInState="RETREAT">
|
||||
<StateWeapon
|
||||
Weapon="AlliedAntiAirShipWeaponScrambler" />
|
||||
</SkirmishAiInfo>
|
||||
</ToggleState>
|
||||
|
||||
</ToggleStatusSpecialAbilityUpdate>
|
||||
|
||||
<!-- The special power that is used by the weapon -->
|
||||
<SpecialPower
|
||||
id="ModuleTag_WeaponScrambler"
|
||||
SpecialPowerTemplate="SpecialPower_WeaponScrambler"
|
||||
TriggerFX="FX_None"
|
||||
UpdateModuleStartsAttack="false" />
|
||||
|
||||
<LaserState
|
||||
id="ModuleTag_LaserState"
|
||||
LaserId="1" >
|
||||
<LaserEndParticleSystem>AlliedHydroScrambler_Sparks</LaserEndParticleSystem>
|
||||
<LaserStartParticleSystem>AlliedHydroScrambler_Start</LaserStartParticleSystem>
|
||||
</LaserState>
|
||||
<StatusBitsUpgrade
|
||||
id="ModuleTag_VeterancyUpgrade"
|
||||
StatusToSet="WEAPON_UPGRADED_01">
|
||||
<TriggeredBy>Upgrade_Veterancy_HEROIC</TriggeredBy>
|
||||
</StatusBitsUpgrade>
|
||||
</Behaviors>
|
||||
<AI>
|
||||
<AIUpdate
|
||||
id="ModuleTag_AI"
|
||||
AutoAcquireEnemiesWhenIdle="YES"
|
||||
StateMachine="UnitAIStateMachine">
|
||||
<UnitAITargetChooserData
|
||||
CanPickDynamicTargets="false"/>
|
||||
</AIUpdate>
|
||||
</AI>
|
||||
<Body>
|
||||
<ActiveBody
|
||||
id="ModuleTag_02"
|
||||
MaxHealth="400" />
|
||||
</Body>
|
||||
<ClientBehaviors>
|
||||
<ModelConditionAudioLoopClientBehavior id="ModuleTag_ShrunkenVoice">
|
||||
<ModelConditionSound Sound="ALL_Hydrofoil_VoiceShrunken" RequiredFlags="SHRINK_EFFECT" />
|
||||
</ModelConditionAudioLoopClientBehavior>
|
||||
<ModelConditionSoundSelectorClientBehavior id="ModuleTag_VoiceAttackWeaponJammer">
|
||||
<Override RequiredFlags="WEAPONSTATE_TWO">
|
||||
<AudioArrayVoice>
|
||||
<AudioEntry Sound="ALL_Hydrofoil_VoiceAttackSpecial" AudioType="voiceAttack" />
|
||||
<AudioEntry Sound="ALL_Hydrofoil_VoiceSelectMS" AudioType="voiceSelectBattle" />
|
||||
</AudioArrayVoice>
|
||||
</Override>
|
||||
</ModelConditionSoundSelectorClientBehavior>
|
||||
<ModelConditionAudioLoopClientBehavior xai:joinAction="Replace" xmlns:xai="uri:ea.com:eala:asset:instance" id="ModuleTag_MagneticSatelliteSuckedAway">
|
||||
<ModelConditionSound Sound="SOV_MagneticSatellite_SuckedAwayWater" RequiredFlags="SUCKED_UP_HIGH" />
|
||||
</ModelConditionAudioLoopClientBehavior>
|
||||
</ClientBehaviors>
|
||||
<Geometry>
|
||||
<Shape
|
||||
Type="BOX"
|
||||
MajorRadius="30.0"
|
||||
MinorRadius="18.0"
|
||||
Height="20.0"
|
||||
ContactPointGeneration="VEHICLE"/>
|
||||
</Geometry>
|
||||
<AudioArrayVoice>
|
||||
<AudioEntry Sound="ALL_Hydrofoil_VoiceAttack" AudioType="voiceAttack" />
|
||||
<AudioEntry Sound="ALL_Hydrofoil_VoiceMoveAttack" AudioType="voiceAttackAfterMoving" />
|
||||
<AudioEntry Sound="ALL_Hydrofoil_VoiceCreate" AudioType="voiceCreated" />
|
||||
<AudioEntry Sound="ALL_Hydrofoil_VoiceMove" AudioType="voiceMove" />
|
||||
<AudioEntry Sound="ALL_Hydrofoil_VoiceRetreat" AudioType="voiceRetreatToCastle" />
|
||||
<AudioEntry Sound="ALL_Hydrofoil_VoiceSelectMS" AudioType="voiceSelect" />
|
||||
<AudioEntry Sound="ALL_Hydrofoil_VoiceSelectBattleMS" AudioType="voiceSelectBattle" />
|
||||
<AudioEntry Sound="ALL_Hydrofoil_VoiceSelectUnderFireMS" AudioType="voiceSelectUnderFire" />
|
||||
<!-- <NamedEntry Sound="ALL_Hydrofoil_VoiceAttackSpecial" Name="VoiceWeaponScrambler" /> oops plays on toggle -->
|
||||
</AudioArrayVoice>
|
||||
<AudioArraySound>
|
||||
<AudioEntry
|
||||
Sound="ALL_Hydrofoil_MoveStart"
|
||||
AudioType="soundMoveStart" />
|
||||
<AudioEntry
|
||||
Sound="VehicleCrush"
|
||||
AudioType="soundCrushing" />
|
||||
<AudioEntry
|
||||
Sound="Ship_Small_MoveLoopWater"
|
||||
AudioType="soundMoveLoop" />
|
||||
</AudioArraySound>
|
||||
<VisionInfo
|
||||
VisionRange="325"
|
||||
ShroudClearingRange="=$STANDARD_SHROUD_CLEAR" />
|
||||
<CrusherInfo
|
||||
id="id_CrusherInfo"
|
||||
CrusherLevel="1"
|
||||
CrushableLevel="20" />
|
||||
</GameObject>
|
||||
</AssetDeclaration>
|
1577
public/ButtonStateDataCommon.xml
Normal file
1577
public/ButtonStateDataCommon.xml
Normal file
File diff suppressed because it is too large
Load Diff
3253
public/Locomotor.xml
Normal file
3253
public/Locomotor.xml
Normal file
File diff suppressed because it is too large
Load Diff
2291
public/LogicCommand.xml
Normal file
2291
public/LogicCommand.xml
Normal file
File diff suppressed because it is too large
Load Diff
1097
public/LogicCommandSet.xml
Normal file
1097
public/LogicCommandSet.xml
Normal file
File diff suppressed because it is too large
Load Diff
1649
public/SpecialPowerTemplates.xml
Normal file
1649
public/SpecialPowerTemplates.xml
Normal file
File diff suppressed because it is too large
Load Diff
1088
public/UnitAbilityButtonTemplates.xml
Normal file
1088
public/UnitAbilityButtonTemplates.xml
Normal file
File diff suppressed because it is too large
Load Diff
@ -73,7 +73,7 @@ const fetchRankData = async () => {
|
||||
if (!playerStats[playerName]) {
|
||||
playerStats[playerName] = {
|
||||
username: playerName,
|
||||
faction: player.faction || player.team_name || '',
|
||||
faction: player.faction || player.team_name || '',
|
||||
totalWin: 0,
|
||||
totalLose: 0,
|
||||
totalPoints: 0,
|
||||
@ -113,7 +113,7 @@ const fetchRankData = async () => {
|
||||
bracket_type: 'winners',
|
||||
score: `${player.totalWin}胜${player.totalLose}负 (${player.totalPoints.toFixed(1)}分)`,
|
||||
rounds: player.rounds.join(',')
|
||||
}))
|
||||
}))
|
||||
|
||||
console.log('RankContestant 最终排名结果:', sortedPlayers)
|
||||
rankData.value = sortedPlayers
|
||||
|
@ -165,16 +165,16 @@ const generateSingleEliminationBracket = async () => {
|
||||
// 获取所有存在的轮次
|
||||
const existingRounds = Object.keys(roundsData).map(Number).sort((a, b) => a - b);
|
||||
console.log('存在的轮次:', existingRounds);
|
||||
|
||||
|
||||
// 生成所有轮次的比赛
|
||||
for (const round of existingRounds) {
|
||||
if (round === 0) {
|
||||
if (round === 0) {
|
||||
await generateRound0Matches(roundsData[round] || []);
|
||||
} else {
|
||||
} else {
|
||||
await generateRoundMatches(round, roundsData[round] || []);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 更新总轮数为实际存在的最大轮次
|
||||
if (existingRounds.length > 0) {
|
||||
tournament.value.rounds = Math.max(...existingRounds);
|
||||
@ -182,131 +182,176 @@ const generateSingleEliminationBracket = async () => {
|
||||
};
|
||||
|
||||
const generateRound0Matches = async (round0Data) => {
|
||||
const matches = [];
|
||||
const usedPlayers = new Set();
|
||||
|
||||
const matches = [];
|
||||
const usedPlayers = new Set();
|
||||
|
||||
// 处理正常配对
|
||||
for (const player of round0Data) {
|
||||
if (usedPlayers.has(player.id)) continue;
|
||||
|
||||
const rivalName = player.rival_name;
|
||||
const isBye = rivalName === '轮空' || rivalName === 'bye' || rivalName === 'BYE' || rivalName === 'Bye';
|
||||
const isPending = rivalName === '待定' || rivalName === 'pending' || rivalName === 'PENDING' || rivalName === 'Pending';
|
||||
|
||||
if (usedPlayers.has(player.id)) continue;
|
||||
|
||||
const rivalName = player.rival_name;
|
||||
const isBye = rivalName === '轮空' || rivalName === 'bye' || rivalName === 'BYE' || rivalName === 'Bye';
|
||||
const isPending = rivalName === '待定' || rivalName === 'pending' || rivalName === 'PENDING' || rivalName === 'Pending';
|
||||
|
||||
if (isBye || isPending) continue;
|
||||
|
||||
// 寻找对手
|
||||
// 寻找对手
|
||||
const rival = round0Data.find(p =>
|
||||
p.sign_name === rivalName && p.id !== player.id && !usedPlayers.has(p.id)
|
||||
);
|
||||
|
||||
if (rival) {
|
||||
const matchNumber = matches.length + 1;
|
||||
matches.push({
|
||||
p.sign_name === rivalName && p.id !== player.id && !usedPlayers.has(p.id)
|
||||
);
|
||||
|
||||
if (rival) {
|
||||
const matchNumber = matches.length + 1;
|
||||
matches.push({
|
||||
id: `0-${matchNumber}`,
|
||||
round: 0,
|
||||
matchNumber: matchNumber,
|
||||
matchNumber: matchNumber,
|
||||
participant1: { id: player.id, name: player.sign_name },
|
||||
participant2: { id: rival.id, name: rival.sign_name },
|
||||
winner: null,
|
||||
score1: parseInt(player.win || 0),
|
||||
score2: parseInt(rival.win || 0),
|
||||
decided: false
|
||||
});
|
||||
usedPlayers.add(player.id);
|
||||
usedPlayers.add(rival.id);
|
||||
}
|
||||
}
|
||||
|
||||
winner: null,
|
||||
score1: parseInt(player.win || 0),
|
||||
score2: parseInt(rival.win || 0),
|
||||
decided: false
|
||||
});
|
||||
usedPlayers.add(player.id);
|
||||
usedPlayers.add(rival.id);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理轮空
|
||||
for (const player of round0Data) {
|
||||
if (usedPlayers.has(player.id)) continue;
|
||||
|
||||
const rivalName = player.rival_name;
|
||||
const isBye = rivalName === '轮空' || rivalName === 'bye' || rivalName === 'BYE' || rivalName === 'Bye';
|
||||
|
||||
if (isBye) {
|
||||
const matchNumber = matches.length + 1;
|
||||
matches.push({
|
||||
if (usedPlayers.has(player.id)) continue;
|
||||
|
||||
const rivalName = player.rival_name;
|
||||
const isBye = rivalName === '轮空' || rivalName === 'bye' || rivalName === 'BYE' || rivalName === 'Bye';
|
||||
|
||||
if (isBye) {
|
||||
const matchNumber = matches.length + 1;
|
||||
matches.push({
|
||||
id: `0-${matchNumber}`,
|
||||
round: 0,
|
||||
matchNumber: matchNumber,
|
||||
matchNumber: matchNumber,
|
||||
participant1: { id: player.id, name: player.sign_name },
|
||||
participant2: null,
|
||||
participant2: null,
|
||||
winner: { id: player.id, name: player.sign_name },
|
||||
score1: 1,
|
||||
score2: 0,
|
||||
decided: true
|
||||
});
|
||||
usedPlayers.add(player.id);
|
||||
}
|
||||
}
|
||||
|
||||
tournament.value.matches.push(...matches);
|
||||
score1: 1,
|
||||
score2: 0,
|
||||
decided: true
|
||||
});
|
||||
usedPlayers.add(player.id);
|
||||
}
|
||||
}
|
||||
|
||||
tournament.value.matches.push(...matches);
|
||||
};
|
||||
|
||||
const generateRoundMatches = async (round, roundData) => {
|
||||
const matches = [];
|
||||
const usedPlayers = new Set();
|
||||
|
||||
const matches = [];
|
||||
const usedPlayers = new Set();
|
||||
|
||||
console.log(`生成第${round}轮比赛,数据:`, roundData);
|
||||
console.log(`第${round}轮详细数据:`, roundData.map(p => ({
|
||||
id: p.id,
|
||||
sign_name: p.sign_name,
|
||||
rival_name: p.rival_name,
|
||||
status: p.status,
|
||||
win: p.win,
|
||||
lose: p.lose
|
||||
})));
|
||||
|
||||
// 处理已有数据的比赛
|
||||
for (const player of roundData) {
|
||||
if (usedPlayers.has(player.id)) continue;
|
||||
|
||||
const rivalName = player.rival_name;
|
||||
const isBye = rivalName === '轮空' || rivalName === 'bye' || rivalName === 'BYE' || rivalName === 'Bye';
|
||||
const isPending = rivalName === '待定' || rivalName === 'pending' || rivalName === 'PENDING' || rivalName === 'Pending';
|
||||
|
||||
if (isBye || isPending) continue;
|
||||
|
||||
// 寻找对手
|
||||
const rival = roundData.find(p =>
|
||||
p.sign_name === rivalName && p.id !== player.id && !usedPlayers.has(p.id)
|
||||
);
|
||||
|
||||
if (rival) {
|
||||
const matchNumber = matches.length + 1;
|
||||
matches.push({
|
||||
id: `${round}-${matchNumber}`,
|
||||
round: round,
|
||||
matchNumber: matchNumber,
|
||||
participant1: { id: player.id, name: player.sign_name },
|
||||
participant2: { id: rival.id, name: rival.sign_name },
|
||||
winner: null,
|
||||
score1: parseInt(player.win || 0),
|
||||
score2: parseInt(rival.win || 0),
|
||||
decided: false
|
||||
});
|
||||
usedPlayers.add(player.id);
|
||||
usedPlayers.add(rival.id);
|
||||
if (usedPlayers.has(player.id)) {
|
||||
console.log(`玩家 ${player.sign_name} (ID: ${player.id}) 已被使用,跳过`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const rivalName = player.rival_name;
|
||||
const isBye = rivalName === '轮空' || rivalName === 'bye' || rivalName === 'BYE' || rivalName === 'Bye';
|
||||
const isPending = rivalName === '待定' || rivalName === 'pending' || rivalName === 'PENDING' || rivalName === 'Pending';
|
||||
|
||||
if (isBye || isPending) {
|
||||
console.log(`玩家 ${player.sign_name} 的对手是 ${rivalName},跳过正常比赛处理`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 寻找对手
|
||||
const rival = roundData.find(p =>
|
||||
p.sign_name === rivalName && p.id !== player.id && !usedPlayers.has(p.id)
|
||||
);
|
||||
|
||||
if (rival) {
|
||||
const matchNumber = matches.length + 1;
|
||||
|
||||
// 判断比赛是否已完成
|
||||
const playerStatus = player.status;
|
||||
const rivalStatus = rival.status;
|
||||
const playerWin = parseInt(player.win || 0);
|
||||
const rivalWin = parseInt(rival.win || 0);
|
||||
|
||||
// 如果任一玩家有胜场,说明比赛已完成
|
||||
const isDecided = playerWin > 0 || rivalWin > 0 ||
|
||||
playerStatus === 'win' || playerStatus === 'lose' ||
|
||||
rivalStatus === 'win' || rivalStatus === 'lose';
|
||||
|
||||
// 确定获胜者
|
||||
let winner = null;
|
||||
if (playerStatus === 'win' || playerWin > rivalWin) {
|
||||
winner = { id: player.id, name: player.sign_name };
|
||||
} else if (rivalStatus === 'win' || rivalWin > playerWin) {
|
||||
winner = { id: rival.id, name: rival.sign_name };
|
||||
}
|
||||
|
||||
console.log(`创建比赛 ${matchNumber}: ${player.sign_name} vs ${rival.sign_name}`, {
|
||||
playerStatus,
|
||||
rivalStatus,
|
||||
isDecided,
|
||||
winner: winner?.name,
|
||||
playerData: { id: player.id, name: player.sign_name, status: player.status, win: player.win, lose: player.lose },
|
||||
rivalData: { id: rival.id, name: rival.sign_name, status: rival.status, win: rival.win, lose: rival.lose }
|
||||
});
|
||||
|
||||
matches.push({
|
||||
id: `${round}-${matchNumber}`,
|
||||
round: round,
|
||||
matchNumber: matchNumber,
|
||||
participant1: { id: player.id, name: player.sign_name },
|
||||
participant2: { id: rival.id, name: rival.sign_name },
|
||||
winner: winner,
|
||||
score1: parseInt(player.win || 0),
|
||||
score2: parseInt(rival.win || 0),
|
||||
decided: isDecided
|
||||
});
|
||||
usedPlayers.add(player.id);
|
||||
usedPlayers.add(rival.id);
|
||||
} else {
|
||||
console.log(`未找到玩家 ${player.sign_name} 的对手 ${rivalName}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理轮空
|
||||
for (const player of roundData) {
|
||||
if (usedPlayers.has(player.id)) continue;
|
||||
|
||||
const rivalName = player.rival_name;
|
||||
const isBye = rivalName === '轮空' || rivalName === 'bye' || rivalName === 'BYE' || rivalName === 'Bye';
|
||||
|
||||
if (isBye) {
|
||||
const matchNumber = matches.length + 1;
|
||||
matches.push({
|
||||
id: `${round}-${matchNumber}`,
|
||||
round: round,
|
||||
matchNumber: matchNumber,
|
||||
participant1: { id: player.id, name: player.sign_name },
|
||||
participant2: null,
|
||||
winner: { id: player.id, name: player.sign_name },
|
||||
score1: 1,
|
||||
score2: 0,
|
||||
decided: true
|
||||
});
|
||||
usedPlayers.add(player.id);
|
||||
}
|
||||
}
|
||||
|
||||
const rivalName = player.rival_name;
|
||||
const isBye = rivalName === '轮空' || rivalName === 'bye' || rivalName === 'BYE' || rivalName === 'Bye';
|
||||
|
||||
if (isBye) {
|
||||
const matchNumber = matches.length + 1;
|
||||
matches.push({
|
||||
id: `${round}-${matchNumber}`,
|
||||
round: round,
|
||||
matchNumber: matchNumber,
|
||||
participant1: { id: player.id, name: player.sign_name },
|
||||
participant2: null,
|
||||
winner: { id: player.id, name: player.sign_name },
|
||||
score1: 1,
|
||||
score2: 0,
|
||||
decided: true
|
||||
});
|
||||
usedPlayers.add(player.id);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理待定的玩家(单独显示)
|
||||
for (const player of roundData) {
|
||||
@ -317,43 +362,84 @@ const generateRoundMatches = async (round, roundData) => {
|
||||
|
||||
if (isPending) {
|
||||
const matchNumber = matches.length + 1;
|
||||
|
||||
// 判断比赛是否已完成(如果玩家状态是win或lose,或者有胜场,说明比赛已完成)
|
||||
const playerWin = parseInt(player.win || 0);
|
||||
const isDecided = player.status === 'win' || player.status === 'lose' || playerWin > 0;
|
||||
let winner = null;
|
||||
if (player.status === 'win' || playerWin > 0) {
|
||||
winner = { id: player.id, name: player.sign_name };
|
||||
}
|
||||
|
||||
console.log(`创建待定比赛 ${matchNumber}: ${player.sign_name} vs 待定`, {
|
||||
playerStatus: player.status,
|
||||
isDecided,
|
||||
winner: winner?.name
|
||||
});
|
||||
|
||||
matches.push({
|
||||
id: `${round}-${matchNumber}`,
|
||||
round: round,
|
||||
matchNumber: matchNumber,
|
||||
participant1: { id: player.id, name: player.sign_name },
|
||||
participant2: null,
|
||||
winner: null,
|
||||
winner: winner,
|
||||
score1: parseInt(player.win || 0),
|
||||
score2: 0,
|
||||
decided: false
|
||||
decided: isDecided
|
||||
});
|
||||
usedPlayers.add(player.id);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`第${round}轮生成比赛:`, matches);
|
||||
tournament.value.matches.push(...matches);
|
||||
tournament.value.matches.push(...matches);
|
||||
};
|
||||
|
||||
|
||||
|
||||
// 检查比赛顺序是否合法
|
||||
const isMatchOrderValid = (match) => {
|
||||
console.log('检查比赛顺序:', {
|
||||
matchId: match.id,
|
||||
round: match.round,
|
||||
matchNumber: match.matchNumber
|
||||
});
|
||||
|
||||
const currentRoundMatches = tournament.value.matches
|
||||
.filter(m => m.round === match.round)
|
||||
.sort((a, b) => a.matchNumber - b.matchNumber);
|
||||
|
||||
console.log('当前轮次所有比赛:', currentRoundMatches.map(m => ({
|
||||
id: m.id,
|
||||
matchNumber: m.matchNumber,
|
||||
decided: m.decided,
|
||||
participant1: m.participant1?.name,
|
||||
participant2: m.participant2?.name,
|
||||
winner: m.winner?.name,
|
||||
score1: m.score1,
|
||||
score2: m.score2
|
||||
})));
|
||||
|
||||
const currentMatchIndex = currentRoundMatches.findIndex(m => m.id === match.id);
|
||||
console.log('当前比赛索引:', currentMatchIndex);
|
||||
|
||||
// 检查是否有更小编号的比赛未完成
|
||||
for (let i = 0; i < currentMatchIndex; i++) {
|
||||
const previousMatch = currentRoundMatches[i];
|
||||
console.log(`检查第${i + 1}场比赛:`, {
|
||||
id: previousMatch.id,
|
||||
matchNumber: previousMatch.matchNumber,
|
||||
decided: previousMatch.decided
|
||||
});
|
||||
|
||||
if (!previousMatch.decided) {
|
||||
console.log(`第${previousMatch.matchNumber}场比赛未完成,阻止进行第${match.matchNumber}场比赛`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('比赛顺序验证通过');
|
||||
return true;
|
||||
};
|
||||
|
||||
@ -474,6 +560,14 @@ const handlePlayerAdvancement = async (match) => {
|
||||
};
|
||||
|
||||
const confirmScore = async (match) => {
|
||||
console.log('确认比分,比赛信息:', {
|
||||
id: match.id,
|
||||
round: match.round,
|
||||
matchNumber: match.matchNumber,
|
||||
participant1: match.participant1?.name,
|
||||
participant2: match.participant2?.name
|
||||
});
|
||||
|
||||
// 检查比赛顺序
|
||||
if (!isMatchOrderValid(match)) {
|
||||
const currentRoundMatches = tournament.value.matches
|
||||
@ -483,6 +577,12 @@ const confirmScore = async (match) => {
|
||||
const currentMatchIndex = currentRoundMatches.findIndex(m => m.id === match.id);
|
||||
const previousMatch = currentRoundMatches[currentMatchIndex - 1];
|
||||
|
||||
console.log('比赛顺序验证失败,阻止的比赛:', {
|
||||
currentMatch: match.matchNumber,
|
||||
previousMatch: previousMatch?.matchNumber,
|
||||
previousMatchId: previousMatch?.id
|
||||
});
|
||||
|
||||
errorDialog.value = {
|
||||
visible: true,
|
||||
message: `请先完成第${previousMatch.matchNumber}场比赛`
|
||||
@ -531,16 +631,16 @@ const confirmScore = async (match) => {
|
||||
await addSignUpResult(newRecord);
|
||||
console.log(`轮空玩家 ${p1Data.sign_name} 晋级到第${nextRound}轮`);
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (error) {
|
||||
console.error('处理轮空晋级失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
nextTick(() => drawD3Bracket());
|
||||
await loadTournamentData();
|
||||
emit('refreshPlayers');
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 验证比分
|
||||
const s1 = Number(match.score1);
|
||||
const s2 = Number(match.score2);
|
||||
@ -670,9 +770,9 @@ const drawD3Bracket = () => {
|
||||
const roundMatches = tournament.value.matches
|
||||
.filter(m => m.round === round)
|
||||
.sort((a, b) => a.matchNumber - b.matchNumber);
|
||||
|
||||
|
||||
console.log(`绘制第${round}轮比赛:`, roundMatches);
|
||||
|
||||
|
||||
const matchesInRound = roundMatches.length;
|
||||
const roundX = round * (matchWidth + roundGap);
|
||||
const roundStartY = (maxMatchesInRound * (matchHeight + matchGap) - matchesInRound * (matchHeight + matchGap)) / 2;
|
||||
|
@ -49,13 +49,15 @@ const routes = [
|
||||
path: 'weapon-match',
|
||||
name: 'WeaponMatch',
|
||||
component: () => import('@/views/weapon/WeaponMatch.vue'),
|
||||
meta: { requiresAuth: true, requiredPrivilege: ['lv-admin','lv-mod'] }
|
||||
// meta: { requiresAuth: true, requiredPrivilege: ['lv-admin','lv-mod'] }
|
||||
meta: { requiresAuth: true}
|
||||
},
|
||||
{
|
||||
path: 'configEditor',
|
||||
name: 'ConfigEditor',
|
||||
component: () => import('@/views/index/ConfigEditor.vue'),
|
||||
meta: { requiresAuth: true, requiredPrivilege: ['lv-admin','lv-mod'] }
|
||||
// meta: { requiresAuth: true, requiredPrivilege: ['lv-admin','lv-mod'] }
|
||||
meta: { requiresAuth: true}
|
||||
},
|
||||
{
|
||||
path: 'competition',
|
||||
@ -102,13 +104,13 @@ const routes = [
|
||||
path: 'PIC2TGA',
|
||||
name: 'PIC2TGA',
|
||||
component: () => import('@/views/index/PIC2TGA.vue'),
|
||||
meta: { requiredPrivilege: ['lv-admin','lv-mod','lv-map','lv-competitor'] }
|
||||
// meta: { requiredPrivilege: ['lv-admin','lv-mod','lv-map','lv-competitor'] }
|
||||
},
|
||||
{
|
||||
path: 'terrainGenerate',
|
||||
name: 'TerrainGenerate',
|
||||
component: () => import('@/views/index/TerrainGenerate.vue'),
|
||||
meta: { requiredPrivilege: ['lv-admin','lv-mod','lv-map','lv-competitor'] }
|
||||
// meta: { requiredPrivilege: ['lv-admin','lv-mod','lv-map','lv-competitor'] }
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -437,12 +437,12 @@ function handlePasswordChangeError(errorMessage) {
|
||||
:message="errorDialogMessage"
|
||||
@close="errorDialogVisible = false"
|
||||
/>
|
||||
<PrivilegeRequestDialog
|
||||
:visible="privilegeDialogVisible"
|
||||
:privilegeName="privilegeDialogName"
|
||||
@close="privilegeDialogVisible = false"
|
||||
@apply="handlePrivilegeApply"
|
||||
/>
|
||||
<!-- <PrivilegeRequestDialog-->
|
||||
<!-- :visible="privilegeDialogVisible"-->
|
||||
<!-- :privilegeName="privilegeDialogName"-->
|
||||
<!-- @close="privilegeDialogVisible = false"-->
|
||||
<!-- @apply="handlePrivilegeApply"-->
|
||||
<!-- />-->
|
||||
<SuccessDialog
|
||||
:visible="successDialog.visible"
|
||||
:message="successDialog.message"
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user