So, I acquired a copy of the Graal 1.41 client I think maybe two years ago. Strictly offline, but it’s still pretty cool. Comes with all the levels and just about all of the weapons from Graal Classic in that era. Has the level editor, but it’s built into the client rather than coming as a separate executable. Poking around through all of the .graal files, came across ragnarok’s ice castle levels. Within was the Ice Bow. I thought “Oh, sweet man, never got to see this in action before.” I endowed myself with magic to make it usable. It fired off a shot and I thought “Whoa, nice. Custom arrow and everything”. Only thing was, it didn’t work against baddies/NPCs. I looked at the script…or rather scripts (it uses putnpc for each arrow shot direction…and each one of those uses putnpc to call the iceblock.txt script when it makes a hit). It’s only hit detection was playertouchsme conditions…so it seems this weapon was usable against other players only. I’m actually making my own offline adventure and thought an Ice Bow would be a cool weapon to feature. So, I redesigned it to only have to call the iceblock.txt script file via putnpc. Tried using showimg, but that won’t actually freeze the NPC. It is…chunky..but hey, works against baddies and custom NPCs now :). I’ll write a reply here to include the original script(s) made by Ragnarok.
Frost Bow In-Game Weapon Script
////Frost Bow Created by Kevin
if (playertouchsme) {
toweapons Frost Bow;
hidelocal;
}
if (weaponfired&&playerdarts>5&&magicendowed&&magicendowed&&playermp>10&&playerdir=0) {
playermp -= 10;
freezeplayer 0.6;
setbow wicebow1.gif;
playersprite = 33;
playerdarts -= 5;
sleep .5;
set iceboltactive;
while (iceboltactive) {
showimg 0, wicearru.gif, x, y-1;
sleep 0.05;
y -= 1.25;
// BADDIE HIT CHECK
for (i=0; i<compuscount; i++) {
if (abs(compus[i].x - x) < 1 && abs(compus[i].y - (y-1)) < 1) {
// spawn the iceblock image
putnpc wiceblock.gif,iceblock.txt,compus[i].x,compus[i].y;
unset iceboltactive;
hideimg 0;
hitcompu i,2,0,0;
break;
}
}
//NPC HIT CHECK
for (i=0; i<npcscount; i++) {
if (abs(npcs[i].x - x) < 1 &&abs(npcs[i].y - (y-1)) < 1) {
// spawn the iceblock image
putnpc wiceblock.gif,iceblock.txt, npcs[i].x, npcs[i].y;
unset iceboltactive;
hideimg 0;
npcs[i].hearts -= 2;
break;
}
}
if (!iceboltactive) break;
if (y < 2) {
unset iceboltactive; hideimg 0;
}
}
}
// ----------------------------------------------------
// FIRE LEFT
// ----------------------------------------------------
if (weaponfired&&playerdarts>5&&magicendowed&&magicendowed&&playermp>10&&playerdir == 1) {
playermp -= 10;
freezeplayer 0.6;
setbow wicebow1.gif;
playersprite = 33;
playerdarts -= 5;
sleep .5;
set iceboltactive;
while (iceboltactive) {
showimg 0, wicearrl.gif, x-1, y;
sleep 0.05;
x -= 1.25;
// BADDIE HIT CHECK
for (i=0; i<compuscount; i++) {
if (abs(compus[i].x - (x-1)) < 1 &&abs(compus[i].y - y) < 1) {
putnpc wiceblock.gif,iceblock.txt, compus[i].x, compus[i].y;
unset iceboltactive;
hideimg 0;
hitcompu i,2,0,0;
break;
}
}
// NPC HIT CHECK
for (i=0; i<npcscount; i++) {
if (abs(npcs[i].x - x) < 1 &&
abs(npcs[i].y - (y-1)) < 1) {
// spawn the iceblock image
putnpc wiceblock.gif,iceblock.txt, npcs[i].x, npcs[i].y;
unset iceboltactive;
hideimg 0;
npcs[i].hearts -= 2;
break;
}
}
if (!iceboltactive) break;
if (x < 2) { unset iceboltactive; hideimg 0; }
}
}
// ----------------------------------------------------
// FIRE DOWN
// ----------------------------------------------------
if (weaponfired&&playerdarts>5&&magicendowed&&magicendowed&&playermp>10&&playerdir == 2) {
playermp -= 10;
freezeplayer 0.6;
setbow wicebow1.gif;
playersprite = 33;
playerdarts -= 5;
sleep .5;
set iceboltactive;
while (iceboltactive) {
showimg 0, wicearrd.gif, x, y+1;
sleep 0.05;
y += 1.25;
// BADDIE HIT CHECK
for (i=0; i<compuscount; i++) {
if (abs(compus[i].x - x) < 1 &&
abs(compus[i].y - (y+1)) < 1) {
putnpc wiceblock.gif,iceblock.txt, compus[i].x, compus[i].y;
unset iceboltactive;
hideimg 0;
hitcompu i,2,,;
break;
}
}
//NPC HIT CHECK
for (i=0; i<npcscount; i++) {
if (abs(npcs[i].x - x) < 1 &&
abs(npcs[i].y - (y-1)) < 1) {
// spawn the iceblock image
putnpc wiceblock.gif,iceblock.txt, npcs[i].x, npcs[i].y;
unset iceboltactive;
hideimg 0;
npcs[i].hearts -= 2;
break;
}
}
if (!iceboltactive) break;
if (y > 62) { unset iceboltactive; hideimg 0; }
}
}
// ----------------------------------------------------
// FIRE RIGHT
// ----------------------------------------------------
if (weaponfired&&playerdarts>5&&magicendowed&&magicendowed&&playermp>10&&playerdir == 3) {
playermp -= 10;
freezeplayer 0.6;
setbow wicebow1.gif;
playersprite = 33;
playerdarts -= 5;
sleep .5;
set iceboltactive;
while (iceboltactive) {
showimg 0, wicearrr.gif, x+1, y;
sleep 0.05;
x += 1.25;
// BADDIE HIT CHECK
for (i=0; i<compuscount; i++) {
if (abs(compus[i].x - (x+1)) < 1 &&
abs(compus[i].y - y) < 1) {
putnpc wiceblock.gif,iceblock.txt, compus[i].x, compus[i].y;
unset iceboltactive;
hideimg 0;
hitcompu i,2,,;
break;
}
}
//NPC HIT CHECK
for (i=0; i<npcscount; i++) {
if (abs(npcs[i].x - x) < 1 &&
abs(npcs[i].y - (y-1)) < 1) {
// spawn the iceblock image
putnpc wiceblock.gif,iceblock.txt, npcs[i].x, npcs[i].y;
unset iceboltactive;
hideimg 0;
npcs[i].hearts -= 2;
break;
}
}
if (!iceboltactive) break;
if (x > 62) { unset iceboltactive; hideimg 0; }
}
}
iceblock.txt script file
if (created) {
sleep 3;
destroy;
}
![]()
![]()

![]()
![]()
The reason for the four separate weaponfired conditionals is because if it’s all wrapped in one, the arrow will change direction if the player moves after they shoot it. So, if you fire upward, arrow will go upward,..but as soon as you walk left, right, or down, it will change to that direction. So you would have to stay still until it hits a baddy or NPC, or disappears past the border coordinates.