Survivalcraft API 1.8.2.3 v1.8.2.3
Survivalcraft 2.4
载入中...
搜索中...
未找到
ComponentHealth.cs
浏览该文件的文档.
1using Engine;
4
5namespace Game {
17
18 //public Block ExperienceOrbBlock;
19
21 public float m_lastHealth;
22 public bool m_wasStanding;
23 public float m_redScreenFactor;
24 public Random m_random = new();
25 public bool m_regenerateLifeEnabled = true; //生命再生
26 public float? RedScreenFactorInCrush = 1f;
27 public const string fName = "ComponentHealth";
28 public virtual float VoidDamageFactor { get; set; } //y轴过高或者过低造成的伤害系数
29 public virtual float AirLackResilience { get; set; } //溺水伤害抗性
30 public virtual float MagmaResilience { get; set; } //熔岩伤害抗性
31 public virtual float CrushResilience { get; set; } //挤压伤害抗性
32 public virtual float SpikeResilience { get; set; } //尖刺伤害抗性
33 public virtual float ExplosionResilience { get; set; } //爆炸伤害抗性
34
35 public virtual void OnSpiked(SubsystemBlockBehavior spikeBlockBehavior,
36 float damage,
37 CellFace cellFace,
38 float velocity,
39 ComponentBody componentBody,
40 string causeOfDeath) {
41 Injury blockInjury = new BlockInjury(damage, cellFace, causeOfDeath, componentBody.m_subsystemTerrain);
43 "OnCreatureSpiked",
44 loader => {
45 loader.OnCreatureSpiked(this, spikeBlockBehavior, cellFace, velocity, ref blockInjury);
46 return false;
47 }
48 );
49 Injure(blockInjury);
50 }
51
52 public virtual float CalculateFallDamage() {
53 float velocityChange = MathF.Abs(m_componentCreature.ComponentBody.CollisionVelocityChange.Y);
54 if (!m_wasStanding
55 && velocityChange > FallResilience
56 && !m_componentCreature.ComponentLocomotion.IsCreativeFlyEnabled) {
57 float num4 = MathUtils.Sqr(MathUtils.Max(velocityChange - FallResilience, 0f)) / 15f;
58 num4 /= m_componentFactors?.ResilienceFactor ?? 1;
59 return num4;
60 }
61 return 0f;
62 }
63
64 public virtual bool StackExperienceOnKill { get; set; }
65
66 public virtual string CauseOfDeath { get; set; }
67
68 public virtual bool IsInvulnerable { get; set; }
69
70 public virtual float Health { get; set; }
71
72 public virtual float HealthChange { get; set; }
73
74 public virtual BreathingMode BreathingMode { get; set; }
75
76 public virtual float Air { get; set; }
77
78 public virtual float AirCapacity { get; set; }
79
80 public virtual bool CanStrand { get; set; }
81 public float m_attackResilience;
82 public float m_fallResilience;
83 public float m_fireResilience;
84
88 public virtual float AttackResilience {
90 set => m_attackResilience = value;
91 }
92
96 public virtual float FallResilience {
98 set => m_fallResilience = value;
99 }
100
104 public virtual float FireResilience {
106 set => m_fireResilience = value;
107 }
108
109 public virtual double? DeathTime { get; set; }
110
111 public virtual float CorpseDuration { get; set; }
112
116 public virtual float AttackResilienceFactor { get; set; }
117
121 public virtual float FallResilienceFactor { get; set; }
122
126 public virtual float FireResilienceFactor { get; set; }
127
131 public virtual float HealFactor { get; set; }
132
134
135 [Obsolete("Use ComponentHealth.Injured instead of attacked.")]
136 public virtual Action<ComponentCreature> Attacked { get; set; }
137
138 public virtual Action<Injury> Injured { get; set; }
139
140 public virtual void Heal(float amount) {
141 lock (this) {
142 if (amount > 0f
143 && Health < 1f) {
145 }
146 }
147 }
148
149 public virtual void Injure(float amount, ComponentCreature attacker, bool ignoreInvulnerability, string cause) {
150 Injury injury = new(amount, attacker, ignoreInvulnerability, cause);
151 Injure(injury);
152 }
153
154 public virtual void Injure(Injury injury) {
155 if (injury == null) {
156 return;
157 }
158 injury.ComponentHealth ??= this;
159 if (Health > 0f) {
160 lock (this) {
161 injury.Process();
162 if (Health <= 0f) {
164 "OnCreatureDying",
165 loader => {
166 loader.OnCreatureDying(this, injury);
167 return false;
168 }
169 );
170 }
171 if (Health <= 0f) {
172 Die(injury);
173 }
174 }
175 }
176 }
177
178 public virtual void Die(Injury injury) {
179 Health = 0f;
180 ComponentCreature attacker = injury?.Attacker;
181 int experienceOrbDropCount = (int)MathF.Ceiling(m_componentCreature.ComponentHealth.AttackResilience / 12f);
182 bool calculateInKill = true;
184 "OnCreatureDied",
185 loader => {
186 loader.OnCreatureDied(this, injury, ref experienceOrbDropCount, ref calculateInKill);
187 return false;
188 }
189 );
190 CauseOfDeath = injury?.Cause;
191 if (m_componentCreature.PlayerStats != null && calculateInKill) {
192 m_componentCreature.PlayerStats.AddDeathRecord(
194 Day = m_subsystemTimeOfDay.Day, Location = m_componentCreature.ComponentBody.Position, Cause = CauseOfDeath
195 }
196 );
197 }
198 ComponentPlayer componentPlayer = attacker?.Entity.FindComponent<ComponentPlayer>();
199 if (componentPlayer != null) {
200 if (calculateInKill) {
201 if (m_componentPlayer != null) {
202 componentPlayer.PlayerStats.PlayerKills++;
203 }
204 else if (m_componentCreature.Category == CreatureCategory.LandPredator
205 || m_componentCreature.Category == CreatureCategory.LandOther) {
206 componentPlayer.PlayerStats.LandCreatureKills++;
207 }
208 else if (m_componentCreature.Category == CreatureCategory.WaterPredator
209 || m_componentCreature.Category == CreatureCategory.WaterOther) {
210 componentPlayer.PlayerStats.WaterCreatureKills++;
211 }
212 else {
213 componentPlayer.PlayerStats.AirCreatureKills++;
214 }
215 }
217 for (int i = 0; i < Math.Min(100, experienceOrbDropCount); i++) //调整经验球的掉落逻辑,多于100个时则成组掉落防止卡顿
218 {
219 Vector2 vector = m_random.Vector2(2.5f, 3.5f);
220 int dropInWave = experienceOrbDropCount / 100;
221 if (i < experienceOrbDropCount % 100) {
222 dropInWave++;
223 }
224 m_subsystemPickables.AddPickable(
226 dropInWave,
227 m_componentCreature.ComponentBody.Position,
228 new Vector3(vector.X, 6f, vector.Y),
229 null,
230 Entity
231 );
232 }
233 }
234 else {
235 for (int i = 0; i < experienceOrbDropCount; i++) {
236 Vector2 vector = m_random.Vector2(2.5f, 3.5f);
237 m_subsystemPickables.AddPickable(
239 1,
240 m_componentCreature.ComponentBody.Position,
241 new Vector3(vector.X, 6f, vector.Y),
242 null,
243 Entity
244 );
245 }
246 }
247 }
248 }
249
250 public virtual void Update(float dt) {
251 lock (this) {
252 Vector3 position = m_componentCreature.ComponentBody.Position;
254 && Health > 0f
255 && Health < 1f) {
256 float num = 0f;
257 if (m_componentPlayer != null) {
258 if (m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Harmless) {
259 num = 0.0166666675f;
260 }
261 else if (m_componentPlayer.ComponentSleep.SleepFactor == 1f
262 && m_componentPlayer.ComponentVitalStats.Food > 0f) {
263 num = 0.00166666671f;
264 }
265 else if (m_componentPlayer.ComponentVitalStats.Food > 0.5f) {
266 num = 0.00111111114f;
267 }
268 }
269 else {
270 num = 0.00111111114f;
271 }
272 Heal(m_subsystemGameInfo.TotalElapsedGameTimeDelta * num);
273 }
274 //溺水空气值
275 if (BreathingMode == BreathingMode.Air) {
276 int cellContents = m_subsystemTerrain.Terrain.GetCellContents(
277 Terrain.ToCell(position.X),
278 Terrain.ToCell(m_componentCreature.ComponentCreatureModel.EyePosition.Y),
279 Terrain.ToCell(position.Z)
280 );
281 Air = BlocksManager.Blocks[cellContents] is FluidBlock || position.Y > 259f ? MathUtils.Saturate(Air - dt / AirCapacity) : 1f;
282 }
283 else if (BreathingMode == BreathingMode.Water) {
284 Air = m_componentCreature.ComponentBody.ImmersionFactor > 0.25f || m_componentCreature.ComponentBody.IsEmbeddedInIce
285 ? 1f
287 }
288 //岩浆伤害
289 if (m_componentCreature.ComponentBody.ImmersionFactor > 0f
290 && m_componentCreature.ComponentBody.ImmersionFluidBlock is MagmaBlock) {
291 Injure(
292 1f / MagmaResilience * m_componentCreature.ComponentBody.ImmersionFactor * dt,
293 null,
294 false,
296 );
297 float num2 = 1.1f + 0.1f * (float)Math.Sin(12.0 * m_subsystemTime.GameTime);
300 num2 * 0.75f * m_componentCreature.ComponentBody.ImmersionFactor / MagmaResilience
301 );
302 }
303 //跌落伤害
304 float fallDamage = CalculateFallDamage();
306 "CalculateFallDamage",
307 loader => {
308 loader.CalculateFallDamage(this, ref fallDamage);
309 return false;
310 }
311 );
312 if (fallDamage > 0f) {
313 Injure(fallDamage, null, false, LanguageControl.Get(fName, 2));
314 }
315 m_wasStanding = m_componentCreature.ComponentBody.StandingOnValue.HasValue
316 || m_componentCreature.ComponentBody.StandingOnBody != null;
317 //虚空伤害
318 if (VoidDamageFactor > 0f
319 && (position.Y < 0f || position.Y > 296f)
320 && m_subsystemTime.PeriodicGameTimeEvent(2.0, 0.0)) {
321 Injure(VoidDamageFactor * 0.1f, null, true, LanguageControl.Get(fName, 3));
322 m_componentPlayer?.ComponentGui.DisplaySmallMessage(LanguageControl.Get(fName, 4), Color.White, true, false);
323 }
324 //溺水伤害
325 bool num5 = m_subsystemTime.PeriodicGameTimeEvent(1.0, 0.0);
326 if (num5 && Air == 0f) {
327 float num6 = 1f / AirLackResilience;
328 num6 /= m_componentFactors?.ResilienceFactor ?? 1;
329 Injure(num6, null, false, LanguageControl.Get(fName, 7));
330 }
331 //火焰伤害
332 if (num5 && (m_componentOnFire.IsOnFire || m_componentOnFire.TouchesFire)) {
333 float num7 = 1f / FireResilience;
334 num7 /= m_componentFactors?.ResilienceFactor ?? 1;
335 Injure(new FireInjury(num7, m_componentOnFire.Attacker));
336 }
337 //挤压伤害
338 if (m_componentCreature.ComponentBody.CrushedTime > 0f) {
339 if (m_subsystemTime.PeriodicGameTimeEvent(1.0, 0.0)
340 && m_componentCreature.ComponentBody.CrushedTime > 0.2f) {
341 Injure(1 / CrushResilience, null, true, LanguageControl.Get("ComponentMiner", "crushed"));
342 }
343 if (RedScreenFactorInCrush.HasValue) {
345 }
346 }
347 //鱼类搁浅伤害
348 if (num5
349 && CanStrand
350 && m_componentCreature.ComponentBody.ImmersionFactor < 0.25f
351 && (m_componentCreature.ComponentBody.StandingOnValue != 0 || m_componentCreature.ComponentBody.StandingOnBody != null)) {
352 Injure(1f / AirLackResilience, null, false, LanguageControl.Get(fName, 6));
353 }
354 //伤害结算
355 float lastHealth = m_lastHealth;
358 float redScreenFactorCalculated = m_redScreenFactor;
359 float creatureModelRedFactorCalculated = MathUtils.Saturate(m_componentCreature.ComponentCreatureModel.m_injuryColorFactor - 3f * dt);
360 bool playPainSound = true;
361 int healthBarFlashCount = Math.Clamp((int)((0f - HealthChange) * 30f), 0, 10);
362 if (redScreenFactorCalculated > 0.01f) {
363 redScreenFactorCalculated *= MathF.Pow(0.2f, dt);
364 }
365 else {
366 redScreenFactorCalculated = 0f;
367 }
368 if (HealthChange < 0f) {
369 redScreenFactorCalculated += -4f * HealthChange;
370 creatureModelRedFactorCalculated = 1f;
371 }
373 "ChangeVisualEffectOnInjury",
374 loader => {
375 loader.ChangeVisualEffectOnInjury(
376 this,
377 lastHealth,
378 ref redScreenFactorCalculated,
379 ref playPainSound,
380 ref healthBarFlashCount,
381 ref creatureModelRedFactorCalculated
382 );
383 return false;
384 }
385 );
386 if (HealthChange < 0f) {
387 if (playPainSound) {
388 m_componentCreature.ComponentCreatureSounds.PlayPainSound();
389 }
390 m_componentPlayer?.ComponentGui.HealthBarWidget.Flash(healthBarFlashCount);
391 }
392 m_redScreenFactor = redScreenFactorCalculated;
393 m_componentCreature.ComponentCreatureModel.m_injuryColorFactor = creatureModelRedFactorCalculated;
394 if (m_componentPlayer != null) {
395 m_componentPlayer.ComponentScreenOverlays.RedoutFactor = MathUtils.Max(
396 m_componentPlayer.ComponentScreenOverlays.RedoutFactor,
398 );
399 }
400 if (m_componentPlayer != null) {
401 m_componentPlayer.ComponentGui.HealthBarWidget.Value = Health;
402 }
403 if (Health == 0f
404 && (HealthChange < 0f || !DeathTime.HasValue)) {
405 DeathTime = m_subsystemGameInfo.TotalElapsedGameTime;
406 Vector3 position2 = m_componentCreature.ComponentBody.Position
407 + new Vector3(0f, m_componentCreature.ComponentBody.StanceBoxSize.Y / 2f, 0f);
408 float x = m_componentCreature.ComponentBody.StanceBoxSize.X;
409 KillParticleSystem killParticleSystem = new(m_subsystemTerrain, position2, x);
410 bool dropAllItems = true;
412 "DeadBeforeDrops",
413 loader => {
414 loader.DeadBeforeDrops(this, ref killParticleSystem, ref dropAllItems);
415 return false;
416 }
417 );
418 if (killParticleSystem != null) {
419 m_subsystemParticles.AddParticleSystem(killParticleSystem);
420 }
421 if (dropAllItems) {
422 Vector3 position3 = (m_componentCreature.ComponentBody.BoundingBox.Min + m_componentCreature.ComponentBody.BoundingBox.Max)
423 / 2f;
424 foreach (IInventory item in Entity.FindComponents<IInventory>()) {
425 item.DropAllItems(position3);
426 }
427 }
428 }
429 if (Health <= 0f
430 && CorpseDuration > 0f
431 && m_subsystemGameInfo.TotalElapsedGameTime - DeathTime > CorpseDuration) {
432 m_componentCreature.ComponentSpawn.Despawn();
433 }
434 }
435 }
436
437 public override void Load(ValuesDictionary valuesDictionary, IdToEntityMap idToEntityMap) {
438 m_subsystemTime = Project.FindSubsystem<SubsystemTime>(true);
439 m_subsystemTimeOfDay = Project.FindSubsystem<SubsystemTimeOfDay>(true);
440 m_subsystemTerrain = Project.FindSubsystem<SubsystemTerrain>(true);
441 m_subsystemParticles = Project.FindSubsystem<SubsystemParticles>(true);
442 m_subsystemGameInfo = Project.FindSubsystem<SubsystemGameInfo>(true);
443 m_subsystemPickables = Project.FindSubsystem<SubsystemPickables>(true);
444 m_componentCreature = Entity.FindComponent<ComponentCreature>(true);
445 m_componentPlayer = Entity.FindComponent<ComponentPlayer>();
446 m_componentOnFire = Entity.FindComponent<ComponentOnFire>(true);
447 m_componentFactors = Entity.FindComponent<ComponentFactors>(true);
448 AttackResilience = valuesDictionary.GetValue<float>("AttackResilience");
449 FallResilience = valuesDictionary.GetValue<float>("FallResilience");
450 FireResilience = valuesDictionary.GetValue<float>("FireResilience");
451 CorpseDuration = valuesDictionary.GetValue<float>("CorpseDuration");
452 BreathingMode = valuesDictionary.GetValue<BreathingMode>("BreathingMode");
453 CanStrand = valuesDictionary.GetValue<bool>("CanStrand");
454 Health = valuesDictionary.GetValue<float>("Health");
455 Air = valuesDictionary.GetValue<float>("Air");
456 AirCapacity = valuesDictionary.GetValue<float>("AirCapacity");
457 double value = valuesDictionary.GetValue<double>("DeathTime");
461 HealFactor = valuesDictionary.GetValue<float>("HealFactor");
462 VoidDamageFactor = valuesDictionary.GetValue<float>("VoidDamageFactor");
463 AirLackResilience = valuesDictionary.GetValue<float>("AirLackResilience");
464 MagmaResilience = valuesDictionary.GetValue<float>("MagmaResilience");
465 CrushResilience = valuesDictionary.GetValue<float>("CrushResilience");
466 SpikeResilience = valuesDictionary.GetValue<float>("SpikeResilience");
467 ExplosionResilience = valuesDictionary.GetValue<float>("ExplosionResilience");
469 DeathTime = value >= 0.0 ? new double?(value) : null;
470 CauseOfDeath = valuesDictionary.GetValue<string>("CauseOfDeath");
472 if (m_subsystemGameInfo.WorldSettings.GameMode == GameMode.Creative
473 && Entity.FindComponent<ComponentPlayer>() != null) {
474 IsInvulnerable = true;
475 }
476 }
477
478 public override void Save(ValuesDictionary valuesDictionary, EntityToIdMap entityToIdMap) {
479 valuesDictionary.SetValue("Health", Health);
480 valuesDictionary.SetValue("Air", Air);
481 if (DeathTime.HasValue) {
482 valuesDictionary.SetValue("DeathTime", DeathTime);
483 }
484 if (!string.IsNullOrEmpty(CauseOfDeath)) {
485 valuesDictionary.SetValue("CauseOfDeath", CauseOfDeath);
486 }
487 }
488 }
489}
Engine.Vector3 Vector3
static float Saturate(float x)
static int Max(int x1, int x2)
static int Sqr(int x)
static int GetBlockIndex(string BlockName, bool throwIfNotFound=false)
通过方块名称来获取方块的Index
SubsystemTerrain m_subsystemTerrain
virtual float FallResilienceFactor
掉落抗性加成系数
virtual void Injure(float amount, ComponentCreature attacker, bool ignoreInvulnerability, string cause)
virtual float AttackResilienceFactor
攻击抗性加成系数
ComponentFactors m_componentFactors
ComponentCreature m_componentCreature
virtual float FireResilience
火焰抗性
virtual void Heal(float amount)
ComponentPlayer m_componentPlayer
virtual void Update(float dt)
SubsystemTerrain m_subsystemTerrain
virtual float HealFactor
生命恢复速度系数
virtual float CalculateFallDamage()
virtual void Die(Injury injury)
SubsystemPickables m_subsystemPickables
virtual void Injure(Injury injury)
virtual float AttackResilience
攻击抗性
ComponentOnFire m_componentOnFire
override void Load(ValuesDictionary valuesDictionary, IdToEntityMap idToEntityMap)
virtual Action< ComponentCreature > Attacked
virtual float FireResilienceFactor
火焰伤害抗性系数
virtual void OnSpiked(SubsystemBlockBehavior spikeBlockBehavior, float damage, CellFace cellFace, float velocity, ComponentBody componentBody, string causeOfDeath)
virtual BreathingMode BreathingMode
virtual float FallResilience
掉落抗性
virtual Action< Injury > Injured
SubsystemTimeOfDay m_subsystemTimeOfDay
SubsystemGameInfo m_subsystemGameInfo
override void Save(ValuesDictionary valuesDictionary, EntityToIdMap entityToIdMap)
SubsystemParticles m_subsystemParticles
virtual void Process()
string Cause
virtual ComponentCreature Attacker
static string Get(string className, int key)
获取在当前语言类名键对应的字符串
static int ToCell(float x)
ValuesDictionary ValuesDictionary
Component FindComponent(Type type, string name, bool throwOnError)
static void HookAction(string HookName, Func< ModLoader, bool > action)
执行Hook
void DropAllItems(Vector3 position)
static Color White