-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAuHitRange.cs
More file actions
318 lines (269 loc) · 10.1 KB
/
AuHitRange.cs
File metadata and controls
318 lines (269 loc) · 10.1 KB
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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
using System.Text;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Networking;
// entities ////////////////////////////////////////////////////////////////////
public partial class Player {
//[SyncVar] int test;
public partial class PlayerLevel {
[Range(1, 100)] public float baseHitRange = 1;
}
// hitRange
public float baseHitRange { get { return levels[level-1].baseHitRange; } }
public override float hitRange {
get {
// calculate equipment bonus
float equipmentBonus =
(from item in equipment
where item.valid
select item.equipHitRangeBonus).Sum();
// calculate buff bonus
float buffBonus =
(from skill in skills
where skill.BuffTimeRemaining() > 0
select skill.buffsHitRange).Sum();
return baseHitRange + equipmentBonus + buffBonus;
}
}
public void CastSkill(Skill skill){
AuCastSkill (skill);
}
void Awake_AuHitRange() {}
void OnStartLocalPlayer_AuHitRange() {}
void OnStartServer_AuHitRange() {}
void Start_AuHitRange() {}
void UpdateClient_AuHitRange() {}
void LateUpdate_AuHitRange() {}
void OnDestroy_AuHitRange() {}
[Server] void OnDeath_AuHitRange() {}
[Client] void OnSelect_AuHitRange(Entity entity) {}
[Server] void OnLevelUp_AuHitRange() {}
[Server] void OnUseInventoryItem_AuHitRange(int index) {}
[Server] void DealDamageAt_AuHitRange(HashSet<Entity> entities, int amount) {}
// you can use the drag and drop system too:
void OnDragAndDrop_InventorySlot_AuHitRangeSlot(int[] slotIndices) {}
void OnDragAndClear_AuHitRangeSlot(int slotIndex) {}
// custom DealDamageAt function that also rewards experience if we killed
// the monster
[Server]
public override HashSet<Entity> DealDamageAt(Entity entity, int amount, float aoeRadius=0, float hitRange=1) {
// deal damage with the default function. get all entities that were hit
// in the AoE radius
var entities = base.DealDamageAt(entity, amount, aoeRadius, hitRange);
foreach (var e in entities) {
// a monster?
if (e is Monster) {
OnDamageDealtToMonster((Monster)e);
// a player?
// (see murder code section comments to understand the system)
} else if (e is Player) {
OnDamageDealtToPlayer((Player)e);
// a pet?
// (see murder code section comments to understand the system)
} else if (e is Pet) {
OnDamageDealtToPet((Pet)e);
}
}
// let pet know that we attacked something
if (activePet != null && activePet.autoAttack)
activePet.OnAggro(entity);
// addon system hooks
Utils.InvokeMany(typeof(Player), this, "DealDamageAt_", entities, amount);
return entities; // not really needed anywhere
}
}
public partial class Monster {
void Awake_AuHitRange() {}
void OnStartServer_AuHitRange() {}
void Start_AuHitRange() {}
void UpdateClient_AuHitRange() {}
void LateUpdate_AuHitRange() {}
[Server] void OnAggro_AuHitRange(Entity entity) {}
[Server] void OnDeath_AuHitRange() {}
public void CastSkill(Skill skill){
AuCastSkill (skill);
}
[Header("AuXtra HitRange")]
[SerializeField] float _hitRange = 1;
public override float hitRange { get { return _hitRange; } }
}
public partial class Npc {
void OnStartServer_AuHitRange() {}
void UpdateClient_AuHitRange() {}
public void CastSkill(Skill skill){
AuCastSkill (skill);
}
public override float hitRange { get { return 0; } }
}
public partial class Pet {
public partial class PetLevel {
}
void Awake_AuHitRange() {}
void OnStartServer_AuHitRange() {}
void Start_AuHitRange() {}
void UpdateClient_AuHitRange() {}
void LateUpdate_AuHitRange() {}
void OnDestroy_AuHitRange() {}
[Server] void OnLevelUp_AuHitRange() {}
[Server] void DealDamageAt_AuHitRange(HashSet<Entity> entities, int amount) {}
[Server] void OnAggro_AuHitRange(Entity entity) {}
[Server] void OnDeath_AuHitRange() {}
public void CastSkill(Skill skill){
AuCastSkill (skill);
}
[Header("AuXtra HitRange")]
[SerializeField] float _hitRange = 1;
public override float hitRange { get { return _hitRange; } }
}
public partial class Entity {
public abstract float hitRange { get; }
void Awake_AuHitRange() {}
void OnStartServer_AuHitRange() {}
void Update_AuHitRange() {}
[Server] void DealDamageAt_AuHitRange(HashSet<Entity> entities, int amount) {}
// deal damage at another entity
// (can be overwritten for players etc. that need custom functionality)
// (can also return the set of entities that were hit, just in case they are
// needed when overwriting it)
[Server]
public virtual HashSet<Entity> DealDamageAt(Entity entity, int amount, float aoeRadius=0, float hitRange=1) {
// build the set of entities that were hit within AoE range
var entities = new HashSet<Entity>();
// add main target in any case, because non-AoE skills have radius=0
entities.Add(entity);
// add all targets in AoE radius around main target
var colliders = Physics.OverlapSphere(entity.transform.position, aoeRadius); //, layerMask);
foreach (var co in colliders) {
var candidate = co.GetComponentInParent<Entity>();
// overlapsphere cast uses the collider's bounding volume (see
// Unity scripting reference), hence is often not exact enough
// in our case (especially for radius 0.0). let's also check the
// distance to be sure.
// => we also check CanAttack so that Npcs can't be killed by AoE
// damage etc.
if (candidate != null && candidate != this && CanAttack(candidate) &&
Vector3.Distance(entity.transform.position, candidate.transform.position) < aoeRadius)
entities.Add(candidate);
}
// now deal damage at each of them
foreach (var e in entities) {
int damageDealt = 0;
var popupType = PopupType.Normal;
// don't deal any damage if target is invincible
if (!e.invincible) {
float eFloat = Vector3.Distance(transform.position, e.transform.position);
//Debug.LogWarning("Look at eFloat ----------------> " + eFloat);
//Debug.LogWarning("Look at hitRange ----------------> " + hitRange);
if (eFloat < hitRange) {
// block? (we use < not <= so that block rate 0 never blocks)
if (UnityEngine.Random.value < e.blockChance) {
popupType = PopupType.Block;
// deal damage
} else {
// subtract defense (but leave at least 1 damage, otherwise
// it may be frustrating for weaker players)
damageDealt = Mathf.Max (amount - e.defense, 1);
// critical hit?
if (UnityEngine.Random.value < criticalChance) {
damageDealt *= 2;
popupType = PopupType.Crit;
}
// deal the damage
e.health -= damageDealt;
}
}
}
if (damageDealt > 0) {
// show damage popup in observers via ClientRpc
RpcShowDamagePopup (e.gameObject, popupType, damageDealt);
//todo add color values based on percentage of highest value.
}
// let's make sure to pull aggro in any case so that archers
// are still attacked if they are outside of the aggro range
e.OnAggro(this);
}
// addon system hooks
Utils.InvokeMany(typeof(Entity), this, "DealDamageAt_", entities, amount);
return entities;
}
// casts the skill. casting and waiting has to be done in the state machine
public void AuCastSkill(Skill skill) {
// check self again (alive, mana, weapon etc.). ignoring the skill cd
// and check target again
// note: we don't check the distance again. the skill will be cast even
// if the target walked a bit while we casted it (it's simply better
// gameplay and less frustrating)
if (CastCheckSelf(skill, false) && CastCheckTarget(skill)) {
// do the logic in here or let the skill effect take care of it?
if (skill.effectPrefab == null || skill.effectPrefab.isPurelyVisual) {
// attack
if (skill.category == "Attack") {
// deal damage directly
DealDamageAt(target, damage + skill.damage, skill.aoeRadius, hitRange);
// heal
} else if (skill.category == "Heal") {
// note: 'target alive' checks were done above already
target.health += skill.healsHealth;
target.mana += skill.healsMana;
// buff
} else if (skill.category == "Buff") {
// set the buff end time (the rest is done in .damage etc.)
skill.buffTimeEnd = Time.time + skill.buffTime;
}
}
// spawn the skill effect (if any)
SpawnSkillEffect(currentSkill, target);
// decrease mana in any case
mana -= skill.manaCosts;
// start the cooldown (and save it in the struct)
skill.cooldownEnd = Time.time + skill.cooldown;
// save any skill modifications in any case
skills[currentSkill] = skill;
} else {
// not all requirements met. no need to cast the same skill again
currentSkill = -1;
}
}
}
// items ///////////////////////////////////////////////////////////////////////
public partial class ItemTemplate {
//[Header("My Addon")]
//public int addonVariable = 0;
[Header("AuHitRange")]
public int equipHitRangeBonus;
}
// note: can't add variables yet without modifying original constructor
public partial struct Item {
//public int addonVariable {
// get { return template.addonVariable; }
//}
void ToolTip_AuHitRange(StringBuilder tip) {
tip.Replace("{EQUIPHITRANGEBONUS}", equipHitRangeBonus.ToString());
//tip.Append("");
}
public float equipHitRangeBonus {
get { return template.equipHitRangeBonus; }
}
}
// skills //////////////////////////////////////////////////////////////////////
public partial class SkillTemplate {
public partial struct SkillLevel {
// note: adding variables here will give lots of warnings, but it works.
//public int addonVariable;
[Header("AuHitRange")]
public float buffsHitRange;
}
}
// note: can't add variables yet without modifying original constructor
public partial struct Skill {
//public int addonVariable {
// get { return template.addonVariable; }
//}
public float buffsHitRange {
get { return template.levels[level-1].buffsHitRange; }
}
void ToolTip_AuHitRange(StringBuilder tip) {
tip.Replace("{BUFFSHITRANGE}", buffsHitRange.ToString());
}
}