Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/game/StarStatusController.hpp
blob: 039cc3bf5e038838aee22068ba23dfeb4752b8a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
#pragma once

#include "StarObserverStream.hpp"
#include "StarNetElementSystem.hpp"
#include "StarNetElementExt.hpp"
#include "StarStatCollection.hpp"
#include "StarStatusEffectDatabase.hpp"
#include "StarDamage.hpp"
#include "StarLuaComponents.hpp"
#include "StarLuaActorMovementComponent.hpp"
#include "StarNetworkedAnimator.hpp"
#include "StarEntityRenderingTypes.hpp"

namespace Star {

STAR_CLASS(StatusController);

class StatusController : public NetElement {
public:
  StatusController(Json const& config);

  Json diskStore() const;
  void diskLoad(Json const& store);

  Json statusProperty(String const& name, Json const& def = Json()) const;
  void setStatusProperty(String const& name, Json value);

  StringList statNames() const;
  float stat(String const& statName) const;
  // Returns true if the stat is strictly greater than zero
  bool statPositive(String const& statName) const;

  StringList resourceNames() const;
  bool isResource(String const& resourceName) const;
  float resource(String const& resourceName) const;
  // Returns true if the resource is strictly greater than zero
  bool resourcePositive(String const& resourceName) const;

  void setResource(String const& resourceName, float value);
  void modifyResource(String const& resourceName, float amount);

  float giveResource(String const& resourceName, float amount);

  bool consumeResource(String const& resourceName, float amount);
  bool overConsumeResource(String const& resourceName, float amount);

  bool resourceLocked(String const& resourceName) const;
  void setResourceLocked(String const& resourceName, bool locked);

  // Resetting a resource also clears any locked states
  void resetResource(String const& resourceName);
  void resetAllResources();

  Maybe<float> resourceMax(String const& resourceName) const;
  Maybe<float> resourcePercentage(String const& resourceName) const;
  float setResourcePercentage(String const& resourceName, float resourcePercentage);
  float modifyResourcePercentage(String const& resourceName, float resourcePercentage);

  List<PersistentStatusEffect> getPersistentEffects(String const& statEffectCategory) const;
  void addPersistentEffect(String const& statEffectCategory, PersistentStatusEffect const& persistentEffect);
  void addPersistentEffects(String const& statEffectCategory, List<PersistentStatusEffect> const& persistentEffects);
  void setPersistentEffects(String const& statEffectCategory, List<PersistentStatusEffect> const& persistentEffects);
  void clearPersistentEffects(String const& statEffectCategory);
  void clearAllPersistentEffects();

  void addEphemeralEffect(EphemeralStatusEffect const& effect, Maybe<EntityId> sourceEntityId = {});
  void addEphemeralEffects(List<EphemeralStatusEffect> const& effectList, Maybe<EntityId> sourceEntityId = {});
  // Will have no effect if the unique effect is not applied ephemerally
  bool removeEphemeralEffect(UniqueStatusEffect const& uniqueEffect);
  void clearEphemeralEffects();

  bool appliesEnvironmentStatusEffects() const;
  void setAppliesEnvironmentStatusEffects(bool appliesEnvironmentStatusEffects);

  // All unique stat effects, whether applied ephemerally or persistently, and
  // their remaining durations.
  ActiveUniqueStatusEffectSummary activeUniqueStatusEffectSummary() const;

  bool uniqueStatusEffectActive(String const& effectName) const;

  const Directives& primaryDirectives() const;
  void setPrimaryDirectives(Directives const& directives);

  // damage request and notification methods should only be called on the master controller.
  List<DamageNotification> applyDamageRequest(DamageRequest const& damageRequest);
  void hitOther(EntityId targetEntityId, DamageRequest damageRequest);
  void damagedOther(DamageNotification damageNotification);
  List<DamageNotification> pullSelfDamageNotifications();
  void applySelfDamageRequest(DamageRequest dr);

  // Pulls recent incoming and outgoing damage notifications.  In order for
  // multiple viewers keep track of notifications and avoid duplicates, the
  // damage notifications are indexed by a monotonically increasing 'step'
  // value.  Every call will return the recent damage notifications, along with
  // another step value to pass into the function on the next call to get
  // damage notifications SINCE the first call.  If since is 0, returns all
  // recent notifications available.
  pair<List<DamageNotification>, uint64_t> damageTakenSince(uint64_t since = 0) const;
  pair<List<pair<EntityId, DamageRequest>>, uint64_t> inflictedHitsSince(uint64_t since = 0) const;
  pair<List<DamageNotification>, uint64_t> inflictedDamageSince(uint64_t since = 0) const;

  void init(Entity* parentEntity, ActorMovementController* movementController);
  void uninit();

  void initNetVersion(NetElementVersion const* version = nullptr) override;

  void netStore(DataStream& ds, NetCompatibilityRules rules = {}) const override;
  void netLoad(DataStream& ds, NetCompatibilityRules rules) override;

  void enableNetInterpolation(float extrapolationHint = 0.0f) override;
  void disableNetInterpolation() override;
  void tickNetInterpolation(float dt) override;

  bool writeNetDelta(DataStream& ds, uint64_t fromVersion, NetCompatibilityRules rules = {}) const override;
  void readNetDelta(DataStream& ds, float interpolationTime = 0.0f, NetCompatibilityRules rules = {}) override;
  void blankNetDelta(float interpolationTime) override;

  void tickMaster(float dt);
  void tickSlave(float dt);

  const DirectivesGroup& parentDirectives() const;
  List<Drawable> drawables() const;
  List<LightSource> lightSources() const;
  List<OverheadBar> overheadBars();

  // new audios and particles will only be generated on the client
  List<AudioInstancePtr> pullNewAudios();
  List<Particle> pullNewParticles();

  Maybe<Json> receiveMessage(String const& message, bool localMessage, JsonArray const& args = {});

private:
  typedef LuaMessageHandlingComponent<LuaActorMovementComponent<LuaUpdatableComponent<LuaWorldComponent<LuaBaseComponent>>>> StatScript;

  struct EffectAnimator : public NetElement {
    EffectAnimator(Maybe<String> animationConfig = {});

    void initNetVersion(NetElementVersion const* version = nullptr) override;

    void netStore(DataStream& ds, NetCompatibilityRules rules = {}) const override;
    void netLoad(DataStream& ds, NetCompatibilityRules rules) override;

    void enableNetInterpolation(float extrapolationHint = 0.0f) override;
    void disableNetInterpolation() override;
    void tickNetInterpolation(float dt) override;

    bool writeNetDelta(DataStream& ds, uint64_t fromVersion, NetCompatibilityRules rules = {}) const override;
    void readNetDelta(DataStream& ds, float interpolationTime = 0.0f, NetCompatibilityRules rules = {}) override;
    void blankNetDelta(float interpolationTime) override;

    Maybe<String> animationConfig;
    NetworkedAnimator animator;
    NetworkedAnimator::DynamicTarget dynamicTarget;
  };
  typedef NetElementDynamicGroup<EffectAnimator> EffectAnimatorGroup;

  struct UniqueEffectMetadata : public NetElementSyncGroup {
    UniqueEffectMetadata();
    UniqueEffectMetadata(UniqueStatusEffect effect, Maybe<float> duration, Maybe<EntityId> sourceEntityId);

    void netElementsNeedLoad(bool full) override;
    void netElementsNeedStore() override;

    UniqueStatusEffect effect;
    Maybe<float> duration;
    NetElementFloat durationNetState;
    NetElementFloat maxDuration;

    // If the sourceEntityId is not set here, this implies that the cause of
    // the unique effect was the owning entity.
    NetElementData<Maybe<EntityId>> sourceEntityId;
  };
  typedef NetElementDynamicGroup<UniqueEffectMetadata> UniqueEffectMetadataGroup;

  struct PersistentEffectCategory {
    Maybe<StatModifierGroupId> modifierEffectsGroupId;
    List<StatModifier> statModifiers;
    HashSet<UniqueStatusEffect> uniqueEffects;
  };

  struct UniqueEffectInstance {
    UniqueStatusEffectConfig effectConfig;
    Directives parentDirectives;
    HashSet<StatModifierGroupId> modifierGroups;
    StatScript script;
    UniqueEffectMetadataGroup::ElementId metadataId;
    EffectAnimatorGroup::ElementId animatorId;
  };

  void updateAnimators(float dt);
  void updatePersistentUniqueEffects();

  float defaultUniqueEffectDuration(UniqueStatusEffect const& name) const;
  bool addUniqueEffect(UniqueStatusEffect const& effect, Maybe<float> duration, Maybe<EntityId> sourceEntityId);
  void removeUniqueEffect(UniqueStatusEffect const& name);

  void initPrimaryScript();
  void uninitPrimaryScript();

  void initUniqueEffectScript(UniqueEffectInstance& uniqueEffect);
  void uninitUniqueEffectScript(UniqueEffectInstance& uniqueEffect);

  LuaCallbacks makeUniqueEffectCallbacks(UniqueEffectInstance& uniqueEffect);

  NetElementGroup m_netGroup;
  StatCollection m_statCollection;
  NetElementOverride<NetElementHashMap<String, Json>> m_statusProperties;
  NetElementData<DirectivesGroup> m_parentDirectives;

  UniqueEffectMetadataGroup m_uniqueEffectMetadata;
  EffectAnimatorGroup m_effectAnimators;

  Entity* m_parentEntity;
  ActorMovementController* m_movementController;

  // Members below are only valid on the master entity

  // there are two magic keys used for this map: 'entities' and 'environment' for StatusEffectEntity
  // and environmentally applied persistent status effects, respectively
  StringMap<PersistentEffectCategory> m_persistentEffects;
  StableHashMap<UniqueStatusEffect, UniqueEffectInstance> m_uniqueEffects;
  float m_minimumLiquidStatusEffectPercentage;
  bool m_appliesEnvironmentStatusEffects;
  bool m_appliesWeatherStatusEffects;
  GameTimer m_environmentStatusEffectUpdateTimer;

  Maybe<String> m_primaryAnimationConfig;
  StatScript m_primaryScript;
  Directives m_primaryDirectives;
  EffectAnimatorGroup::ElementId m_primaryAnimatorId;

  List<DamageNotification> m_pendingSelfDamageNotifications;

  ObserverStream<pair<EntityId, DamageRequest>> m_recentHitsGiven;
  ObserverStream<DamageNotification> m_recentDamageGiven;
  ObserverStream<DamageNotification> m_recentDamageTaken;
};

}