-
Notifications
You must be signed in to change notification settings - Fork 18
/
Magic.c
313 lines (244 loc) · 9.78 KB
/
Magic.c
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
#strict
/* Checkt ab ob genug magische Energie für den Zauber vorhanden ist */
static const MCLK_ManaTrainRate = 10; // Zauber geben Wert/x Magiephysicaltraining
static const MCLK_UnlimitedCast = 100; // Endloszauberei
global func CheckMana(idMagic,pCaster)
{
var iMagicReq = Value(idMagic);
// Keine Zauberenergie benötigt: Kann immer zaubern
if (!iMagicReq || ObjectCount(NMGE)) return(MCLK_UnlimitedCast);
// Ansonsten zurückgeben, wie oft gezaubert werden kann
return (GetMagicEnergy(pCaster) / iMagicReq);
}
// Globaler Aufruf, wenn ein Zauber erfolgreich war: Magie trainieren
global func OnClonkSucceededSpell(id idSpell, object pClonk)
{
if (!pClonk) if (!(pClonk = this())) return(_inherited(idSpell));
// Zauberkraft trainieren (plus 1/10 des Zauberwerts)
if (!ObjectCount(NMGE))
{
var iMaxTrain, idInfo;
// Maximales Training bei Infoobjekten: Nach Ursprungsdefinition richten
if (idInfo = GetObjectInfoCoreVal("id", "ObjectInfo", pClonk)) iMaxTrain = idInfo->~MaxMagicPhysical();
// Infodefinition hat kein MaxMagicPhysical (d.h., kein Zauberclonk) oder kein Infoobjekt vorhanden:
// Training wird eh nicht permanent gesichert; nach aktueller Definition richten
if (!iMaxTrain) iMaxTrain = pClonk->~MaxMagicPhysical();
// Trainieren
TrainPhysical("Magic", Value(idSpell)/MCLK_ManaTrainRate, iMaxTrain, pClonk);
}
// Gegebenenfalls weitere Hooks erlauben
return (_inherited(idSpell, pClonk));
}
/* Zaubermenü erzeugen und mit verfügbaren Zaubern eines Spielers füllen */
global func OpenSpellMenu(object clonk, object command_target, string itemtext, string cbfunc, int player, object magic_source, string emptytext, id select_spell)
{
OpenEmptySpellMenu(MCMS, clonk, command_target, magic_source, emptytext);
var idMagic, i = 0;
while (idMagic = GetPlrMagic(player, 0, i++))
{
AddMenuItem(itemtext, cbfunc, idMagic, clonk,0,clonk);
if(select_spell == idMagic) SelectMenuItem(i-1);
}
return true;
}
/* Leeres Zaubermenü erstellen */
global func OpenEmptySpellMenu(id symbol, object clonk, object command_target, object magic_source, string emptytext)
{
var extra;
if(ObjectCount(ALCO)) { if(ObjectCount(NMGE)) extra=C4MN_Extra_Components; else extra=C4MN_Extra_ComponentsLiveMagic; }
else { if(ObjectCount(NMGE)) extra=C4MN_Extra_None; else extra=C4MN_Extra_LiveMagicValue; }
return CreateMenu(symbol, clonk, command_target, extra, emptytext, ObjectNumber(magic_source));
}
/* Checkt ob genug Zutaten für dne Zauber da sind; wenn ja, wird zurückgegeben wie oft er gezaubert werden kann */
global func CheckAlchem(id idMagic) { // Par(1)-Par(x): Zaubernde, [Zauberturm], [weitere...]
// Regel aktiviert?
if(!ObjectCount(ALCO)) return(MCLK_UnlimitedCast);
// Par(1) = this() wenn =0
if(!Par(1)) Par(1)=this();
var idAlchem,iDesire,iHave, iMin=MCLK_UnlimitedCast, i, m;
// Components in der Defcore einmal durchgehen...
for(i=0;GetComponent(0,i,0,idMagic);++i) {
// Von jedem Eintrag ID und Anzahl merken
idAlchem = GetComponent(0,i,0,idMagic);
iDesire = GetComponent(idAlchem,0,0,idMagic);
if (!iDesire) continue;
iHave = 0;
// Alle Objekte der Parameterliste nach der gesuchten Zutat durchsuchen...
for(m=1;Par(m);++m) {
iHave += GetAlchem(idAlchem,0,Par(m));
}
// Es kann nur so oft gezaubert werden, wie es die wenigstvorhandene Zutat vorgibt
iMin = Min(iMin, iHave / iDesire);
}
return(iMin);
}
/* Gibt einen String zurück, was zum Zaubern eines Zaubers noch fehlt */
global func GetNeededAlcStr(id idMagic) { // Par(1)-Par(x): Zaubernde, [Zauberturm], [weitere...]
// Par(1) = this() wenn =0
if(!Par(1)) Par(1)=this();
var idAlchem,iDesire, i, m, szString, szSplit;
szString = "";
// Components in der Defcore einmal durchgehen...
for(i=0; GetComponent(0,i,0,idMagic); ++i) {
// Von jedem Eintrag ID und Anzahl merken
idAlchem = GetComponent(0,i,0,idMagic);
iDesire = GetComponent(idAlchem,0,0,idMagic);
// Alle Objekte der Parameterliste nach der gesuchten Zutat durchsuchen...
for(m=1;Par(m);++m) {
iDesire -= GetAlchem(idAlchem,0,Par(m));
if(iDesire <= 0) break;
}
// Alle Objekte durchsucht aber nicht genug da? String anhängen
if(iDesire > 0) {
// erstes Mal keinen Separator
if(szString ne "") szSplit = ",|";
else szSplit = "";
szString = Format("%s%s%dx{{%i}}%s",szString,szSplit,iDesire,idAlchem,GetName(0,idAlchem));
}
}
return(szString);
}
/* Löscht die Zutaten aus den Objekten benötigt für den Zauber: Checkt nicht ob genug da sind! */
global func ReduceAlchem(id idMagic) { // Par(1)-Par(x): Zaubernde, [Zauberturm], [weitere...]
// Regel aktiviert?
if(!ObjectCount(ALCO)) return(true);
// Par(1) = this() wenn =0
if(!Par(1)) Par(1)=this();
var idAlchem,iDesire, i, j, m, iAlchemCount;
// Components in der Defcore einmal durchgehen...
for(i=0;GetComponent(0,i,0,idMagic);++i) {
// Von jedem Eintrag ID und Anzahl merken
idAlchem = GetComponent(0,i,0,idMagic);
iDesire = GetComponent(idAlchem,0,0,idMagic);
// Alle Objekte der Parameterliste nach der gesuchten Zutat durchsuchen...
for(m=1;Par(m);++m) {
iAlchemCount = GetAlchem(idAlchem,0,Par(m));
DoAlchem(idAlchem,-iDesire,Par(m));
iDesire -= iAlchemCount;
if(iDesire <= 0) break;
}
// Alle Objekte durchsucht aber nicht genug da? Entwickler sollte das doch prüfen!
if(iDesire > 0) return(false, Log("Warning: Some required alchemic components could not be found!"));
}
return(true);
}
/* Übergibt die Zutaten für den Zauber an das Objekt */
global func IncreaseAlchem(id idMagic, object pTarget) {
// Regel aktiviert?
if(!ObjectCount(ALCO)) return(true);
// Local call/safety
if (!pTarget) if (!(pTarget = this())) return();
// Components in der Defcore einmal durchgehen...
for(var i=0,idAlchem;idAlchem=GetComponent(0,i,0,idMagic);++i)
// ...und als Alchemieobjekte dem Target übergeben
DoAlchem(GetComponent(0,i,0,idMagic), GetComponent(idAlchem,0,0,idMagic), pTarget);
return(true);
}
/* ++++ Alchemiebehälter ++++ */
global func AlchemContainerCount(object pContainer) { // Anzahl der Alchemiebehälter im Objekt
var pAlchem,j;
for(var i;pAlchem=Contents(i,pContainer);++i)
if(pAlchem->~IsAlchemContainer())
++j;
return(j);
}
global func AlchemContainer(int iIndex, object pContainer) { // iIndex'ter Alchemiebehälter im Objekt
// für dumme Entwickler
iIndex = Max(iIndex,0);
var pAlchem;
for(var i;pAlchem=Contents(i,pContainer);++i)
if(pAlchem->~IsAlchemContainer()) {
if(!iIndex) return(pAlchem);
--iIndex;
}
return(false);
}
global func TransferAlchem(object pStart, object pEnd) { // transferiert alles alchemische aus Start nach End
if(!AlchemBag(pStart)) return(false);
if(!AlchemBag(pEnd,true)) return(false);
var idAlchem, iAlchem;
// alle Komponenten, deren Index höher 0 ist, übergeben
while(idAlchem=GetAlchem(0,0,pStart)) {
iAlchem = GetAlchem(idAlchem,0,pStart);
// tatsächlich gar keine Zutat sondern ein weiterer Behälter?
if(idAlchem->~IsAlchemContainer()) {
for(var i=0; i<iAlchem; ++i) {
var pObj = CreateObject(idAlchem,0,0,-1);
TransferAlchem(pObj,pEnd);
}
}
// ansonsten normal transferieren
else {
DoAlchem(idAlchem,+iAlchem,pEnd);
}
// Container wurde gelöscht, abbrechen
if(!DoAlchem(idAlchem,-iAlchem,pStart)) break;
}
}
/* ++++ Alchemische Komponenten ++++ */
global func GetAlchem(id idType, int iIndex, object pContainer) { // idType anggb: Anzahl dieser Zutat
// iIndex anggb: Id der Zutat dieses Indexes
if(!AlchemBag(pContainer)) return(false);
// überspringt C4ID==0 Fälle
var iIndexAfter=0, idContent;
if(!idType)
while(idContent=GetComponent(0,iIndexAfter,pContainer)) {
if(!GetComponent(idContent,0,pContainer)) { ++iIndexAfter; continue; }
// C4ID>0 und iIndex erreicht, fertig
if(!iIndex) break;
// ansonsten an den gewünschten Index ranrücken
--iIndex;
++iIndexAfter;
}
return(GetComponent(idType,iIndexAfter,pContainer));
}
global func DoAlchem(id idType, int iNumber, object pContainer) { // Ändert die Anzahl von idType um iNumber
if(!AlchemBag(pContainer,true)) return(false);
SetComponent(idType,Max(0,GetComponent(idType,0,pContainer)+iNumber),pContainer);
// wenn Beutel und leer: löschen
if(!AlchemCount(pContainer)) {
if(!(pContainer->~Exhaustion()))
RemoveObject(pContainer);
return(false);
}
return(true);
}
global func AlchemCount(object pContainer) { // zählt alle Zutaten
if(!AlchemBag(pContainer)) return(0);
var idAlchem, iCount;
for(var i;idAlchem=GetAlchem(0,i,pContainer);++i)
iCount += GetAlchem(idAlchem,0,pContainer);
return(iCount);
}
/* ++++ Alchemiebeutel ++++ */
global func AlchemBag(&pObject, bool fCreate) { // Alchemiebeutel, fCreate=true für Erstellen wenn nötig
if(!pObject) pObject=this();
// brauch keinen
if(pObject->~IsAlchemContainer()) return(true);
pObject = GetAlchemBag(pObject);
// nicht gefunden
if(!pObject) {
// abbrechen
if(!fCreate) return(false);
// neu erzeugen
pObject = CreateAlchemBag(pObject);
if(!(pObject->~IsAlchemContainer())) return(false);
}
return(true);
}
global func GetAlchemBag(object pObject) { // Alchemiebeutel
var pBag;
if(!pObject) pObject = this();
if(pBag=FindObject(ALC_,0,0,0,0,0,0,pObject)) return(pBag);
// FindObject findet nicht das Kontextobjekt
if(GetID()==ALC_) if(GetActionTarget()==pObject) return(this());
return(false);
}
global func CreateAlchemBag(object pObject) { // Alchemiebeutel erzeugen
if(!pObject) pObject = this();
var pBag;
pBag = CreateObject(ALC_,AbsX(GetX(pObject)),AbsY(GetY(pObject)),-1);
if(!pBag) return(pObject);
pBag->~BelongTo(pObject);
return(pBag);
}