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
|
-|script|rain|32767
{
// we can not start here because for the puppets this is OnClick
end;
OnCast:
if(call("magic_checks")) end;
if (getskilllv(.school) < .level) end;
if (getskilllv(SKILL_MAGIC) < .level) end;
if (getskilllv(.school) < 4 && countitem("BottleOfWater") < 1) end;
if (Sp < 17) end;
explode .@map_ext[0], getmap(), "-";
if (.@map_ext[1] != 1 && getmap() != "099-5") end; // XXX this is fugly, in the future let's use MF_OUTSIDE to detect if a map is "outside" or "inside"
if (getmapflag(getmap(), MF_TOWN)) end;
if (getmap() == "033-1") goto L_SpecialRules6;
goto L_Pay;
L_Pay:
if (getskilllv(.school) < 4) delitem "BottleOfWater", 1;
set Sp, Sp - 17;
set CASTS, CASTS + 1;
if (CASTS < 0) set CASTS, 1; // overflow
set @_M_BLOCK, 1; // block casting, until the timer clears it
addtimer 3000, "Magic Timer::OnClear"; // set the new debuff
sc_start SC_COOLDOWN, 3000, 0, BL_ID;
sc_start SC_COOLDOWN_R, 30000, 0, BL_ID; // Set it to lenght of timeout
callfunc "adjust_spellpower";
set @krad, min(.max_radius,(min(@spellpower,200)/30)+3); // kaflosh radius
set @nearby, 0;
foreach 1, getmap(), POS_X - .max_radius, POS_Y - .max_radius, POS_X + .max_radius, POS_Y + .max_radius,
strnpcinfo(0) + "::OnNearbyNpc";
if (@nearby) goto L_Absorb;
set @new_npc_name$, "#" + strnpcinfo(0) + "#" + getcharid(3); // make a unique puppet name for every player
callfunc "magic_exp";
misceffect FX_MAGIC_RAIN_CAST, strcharinfo(0);
set @spell_npc, puppet(getmap(), POS_X, POS_Y, @new_npc_name$, 127); // clone npc => get puppet id
if (@spell_npc < 1) end;
set .caster, getcharid(3), @spell_npc; // tell the puppet who controls it
set .radius, @krad, @spell_npc; // this is also used by ingrav, don't rename
set .initial_x, POS_X, @spell_npc;
set .initial_y, POS_Y, @spell_npc;
set .max, @spellpower/3, @spell_npc;
set .max_launch, min(200,@spellpower/2)/100, @spell_npc;
donpcevent @new_npc_name$+"::OnLaunch"; // start
addnpctimer 30000, @new_npc_name$+"::OnDestroy"; // this is just a failsafe in case the npc is not properly destroyed
if(isin("011-1", 85, 31, 103, 45)) goto L_Pumpkins;
end;
L_Absorb:
message strcharinfo(0), "##3Rain : ##BA nearby raincloud absorbs your magic.";
end;
OnNearbyNpc:
explode .@nearby$[0], strnpcinfo(0,@target_id), "#";
if(.@nearby$[0] == "DruidTree0" || .@nearby$[1] == "DruidTree0") goto L_Tree;
if(.@nearby$[0] == "rain" || .@nearby$[1] == "rain")
set @nearby, @nearby + 1;
end;
L_Pumpkins:
callfunc "HalloweenQuestWaterPumpkins";
end;
L_Tree:
set .@x, get(POS_X, @target_id); set .@y, get(POS_Y, @target_id);
if (.@x < POS_X-@krad || .@y < POS_Y-@krad || .@x > POS_X+@krad || .@y > POS_Y+@krad) end; // in max radius but not in puppet area
set @flag, 1;
callfunc "QuestTreeTrigger";
close;
OnLaunch:
if (!(isloggedin(.caster))) destroy;
if(get(Hp, .caster) < 1) destroy; // destroy if caster is missing
if(getmap(.caster) != strnpcinfo(3)) destroy; // destroy if caster left the map
set .count, .count + 1;
if(.count > .max) goto L_Destroy;
goto L_Launch;
L_Launch:
set .launch, 0;
callsub S_Launch;
addnpctimer 400 + rand(100), strnpcinfo(0)+"::OnLaunch"; // loop until max
end;
S_Launch:
npcareawarp .initial_x - .radius, .initial_y - .radius, .initial_x + .radius, .initial_y + .radius, 0, strnpcinfo(0);
misceffect FX_RAIN;
foreach 2, strnpcinfo(3), getnpcx()-1, getnpcy()-1, getnpcx()+1, getnpcy()+1, strnpcinfo(0) + "::OnHit", .caster;
set .launch, .launch + 1;
if(.launch < .max_launch) goto S_Launch;
return;
L_Destroy:
if (attachrid(.caster)) sc_end SC_COOLDOWN_R;
destroy;
OnHit:
if (!(isloggedin(.caster))) destroy;
if(get(Hp, .caster) < 1) destroy; // destroy if caster is missing
if(getmap(.caster) != strnpcinfo(3)) destroy; // destroy if caster left the map
if(target(.caster, @target_id, 16) != 16 && .caster != @target_id) end;
if((get(BL_TYPE, @target_id) & 1) == 0) end; // either mob or pc
if(get(ELTTYPE, @target_id) == ELT_FIRE)
injure .caster, @target_id, ((rand((@spellpower/15)+5)+2) * (100 - get(MDEF1, @target_id))) / 100;
if ($NO_RAIN_SPAWNS) end; // server-wide killswitch for rain pranks if spawns logic would backfire.
if (mobcount(getmap(), "rain::OnRainSpawnDeath") > 30) end; // Abort if too crowded.
if(get(Class, @target_id) == EntAbomination) // Rain hit Ent? This scores little perk!
monster getmap(), getnpcx(), getnpcy(), "", LogHead, 1+rand(1+(.max/150)), "rain::OnRainSpawnDeath";
if((get(Class, @target_id) == LogHead) && (rand(5) == 3)) // Rain hit LogHead? Little perk as well (plants)
monster getmap(), getnpcx(), getnpcy(), "", MauvePlant+rand(5), 1, "rain::OnRainSpawnDeath";
end;
OnRainSpawnDeath:
end;
OnDestroy:
debugmes "kaflosh timeout! [this shouldn't happen]"; // XXX: looks like this CAN happen with higher levels of magic, so we might want to cap max charges
destroy;
L_SpecialRules6:
if ($@KIMARR_EVENT < 1) goto L_Pay;
if ($@Fluffy_FighterID == BL_ID) goto L_Pay;
message strcharinfo(0), "You can't use this spell here unless hunting fluffies.";
end;
OnInit:
set .school, SKILL_MAGIC_NATURE;
set .invocation$, chr(MAGIC_SYMBOL) + "kaflosh"; // used in npcs that refer to this spell
void call("magic_register", "OnCast");
set .level, 2;
set .exp_gain, 1;
set .max_radius, 15;
end;
}
|