// TMW2 Script
// Evol functions.
// Authors:
// gumi
// omatt
// Travolta
// Jesusalva
// Description:
// Fishing functions.
// Variable
// .dir
// DOWN Never try or pulled too late
// UP Bait dropped
// LEFT Fish bite bait
//
// player log on .dir is DOWN, start by choose bait menu
// player chooses bait, script addtimer in npc .dir is UP
// if player pulls before signal npc, bait is lost, set .bait to DOWN goto choose bait
// if player pulls after pull delay max, bait is lost, set .bait to DOWN goto choose bait
// npc signal .dir is LEFT
// player pulls between npc signal and pulls delay max, got the fish, set .dir to DOWN goto choose bait
function script fishing_cleanup {
.@npc$ = getarg(0, "");
if (.@npc$ == "") end;
set getvariableofnpc(.char_id, .@npc$), 0; // clean acc id
set getvariableofnpc(.account_id, .@npc$), 0; // clean char id
set getvariableofnpc(.last_used, .@npc$), gettimetick(2); // set last used time
setnpcdir .@npc$, DOWN; // reset direction
return;
}
- script global fishing handler 32767,{
end;
OnBite:
if (getnpcdir(@fishing_spot$) != UP)
end;
setnpcdir @fishing_spot$, LEFT;
@fishing_tick = gettimetick(0);
.@bite_fx=getvariableofnpc(.bite_fx, @fishing_spot$);
specialeffect(.@bite_fx ? .@bite_fx : 30, SELF, playerattached());
end;
OnCleanUp:
dispbottom l("You waited too long and lost the bait...");
specialeffect(getvariableofnpc(.failure_fx, @fishing_spot$), SELF, playerattached()); // event fail
OnPCLogoutEvent:
fishing_cleanup @fishing_spot$;
@fishing_spot$ = ""; // unbind fishing npc
end;
}
// Syntax: fishing()
// Syntax: fishing ( OFFSET, COMMON FISHES, RARE FISHES )
// OFFSET: How many fishes are common
function script fishing {
///////////////////////////////////////////
// Var initialization
if (getarg(0, 0) == 0) {
setarray .@common_fish,
CommonCarp;
setarray .@rare_fish,
GrassCarp;
} else {
.@i=0;
freeloop(true);
for (.@i=1; .@i < getargcount(); .@i++) {
if (.@i <= getarg(0)) {
.@common_fish[.@i-1]=getarg(.@i);
} else {
.@rare_fish[.@i-1-getarg(0)]=getarg(.@i);
}
};
freeloop(false);
}
//debugmes("[FISH] Initialized with %d common and %d rare fishes", getarraysize(.@common_fish), getarraysize(.@rare_fish));
.@npc$ = strnpcinfo(0); // the full name of the fishing spot
.@account_id = getvariableofnpc(.account_id, .@npc$); // the account id of the player using the fishing spot
.@char_id = getvariableofnpc(.char_id, .@npc$); // the char id of the player using the fishing spot
.@dir = getnpcdir(.@npc$); // direction of the fishing spot
.@last_used = getvariableofnpc(.last_used, .@npc$); // when this fishing spot was last used
.@baits = getvariableofnpc(.baits, .@npc$); // bait count
.@rod = getvariableofnpc(.fishing_rod, .@npc$); // the fishing rod required for this spot
.@rod = (.@rod ? .@rod : FishingRod);
.@net_ratio = getvariableofnpc(.net_ratio, .@npc$); // How many fishes and baits are required?
.@net_ratio = max(1, (.@net_ratio ? .@net_ratio : 1));
.@regen_time = getvariableofnpc(.cooldown, .@npc$); // cooldown for the fishing spot
.@regen_time = (.@regen_time ? .@regen_time : 20);
.@bp_chance = getvariableofnpc(.bp_chance, .@npc$); // Blueprint chance
.@bp_chance = (.@bp_chance ? .@bp_chance : 1);
.@success_fx = getvariableofnpc(.success_fx, .@npc$); // effect to show on success
.@success_fx = (.@success_fx ? .@success_fx : FX_SUCCESS);
.@failure_fx = getvariableofnpc(.failure_fx, .@npc$); // effect to show on failure
if (.@failure_fx < 1)
{
.@failure_fx = FX_FAILURE;
set getvariableofnpc(.failure_fx, .@npc$), .@failure_fx; // needed by global handler
}
.@initial_fx = getvariableofnpc(.initial_fx, .@npc$); // effect to show when throwing the bait
.@initial_fx = (.@initial_fx ? .@initial_fx : 29);
.@bite_fx = getvariableofnpc(.bite_fx, .@npc$); // effect to show when something bites
if (.@bite_fx < 1)
{
.@bite_fx = 30;
set getvariableofnpc(.bite_fx, .@npc$), .@bite_fx; // needed by global handler
}
.@wait_time_min = getvariableofnpc(.wait_time_min, .@npc$); // min amount of time to wait for the line to sink
.@wait_time_min = (.@wait_time_min ? .@wait_time_min : 4000);
.@wait_time_max = getvariableofnpc(.wait_time_max, .@npc$); // max amount of time to wait for the line to sink
.@wait_time_max = (.@wait_time_max ? .@wait_time_max : 18000);
// During night time there are more fishes, and therefore, it is easier to fish
// This will make they reply at most 30% faster. Default is a 6 second max delay gain
if (is_night())
.@wait_time_max = min(.@wait_time_min, .@wait_time_max*7/10);
.@catch_time = getvariableofnpc(.catch_time, .@npc$); // the player must catch the fish within X ms after the line sinks
.@catch_time = (.@catch_time ? .@catch_time : 5000);
.@pull_rand_max = getvariableofnpc(.pull_rand_max, .@npc$);
.@pull_rand_max = (.@pull_rand_max ? .@pull_rand_max : 800);
.@fish_id = CommonCarp; // failsafe
if (getvariableofnpc(.bait_ids[0], .@npc$) < 1)
{
// default baits (bait, chance booster) rand(0, 100)
setarray getvariableofnpc(.bait_ids[0], .@npc$),
SmallTentacles, 4,
Bread, 4,
Aquada, 8,
Tentacles, 10,
BugLeg, 2,
CaveSnakeTongue, 6,
LettuceLeaf, 1,
Cheese, 3,
RoastedMaggot, 6;
}
if (.@baits < 1)
{
// only count it once
.@baits = getarraysize(getvariableofnpc(.bait_ids[0], .@npc$));
set getvariableofnpc(.baits, .@npc$), .@baits;
}
///////////////////////////////////////////
// Logic below
if (countitem(.@rod) < 1)
{
dispbottom l("You don't have any @@.", getitemlink(.@rod));
return -1;
}
if (.@account_id > 0 && !isloggedin(.@account_id, .@char_id))
{
fishing_cleanup .@npc$; // reset
.@dir = DOWN;
}
if (.@char_id != getcharid(CHAR_ID_CHAR) && .@dir != DOWN)
{
dispbottom l("This fishing spot is already being used!");
return -2;
}
// pull too soon
if (.@dir == UP)
{
deltimer "global fishing handler::OnCleanUp"; // cancel auto cleanup
deltimer "global fishing handler::OnBite";
specialeffect(.@failure_fx, SELF, playerattached()); // event fail
fishing_cleanup .@npc$; // do it manually instead
dispbottom l("You pulled too soon and lost the bait.");
return -3;
}
// pull maybe on time
else if (.@dir == LEFT)
{
deltimer "global fishing handler::OnCleanUp"; // cancel auto cleanup
fishing_cleanup .@npc$; // do it manually instead
getmapxy .@mapbis$, .@xbis, .@ybis, UNITTYPE_PC; // get current char location
// Leave spot, lost the bait
if (.@mapbis$ != @fishing_loc$[0] || .@xbis != @fishing_loc[0] || .@ybis != @fishing_loc[1] || @fishing_spot$ != .@npc$)
{
dispbottom l("You left your fishing spot!");
return -4;
}
// RNG to obtain a fish
if (rand2(gettimetick(0) - @fishing_tick) <= .@pull_rand_max)
{
for (.@i=0 ; .@i < .@net_ratio ; .@i++) {
// RNG to obtain a rare fish or common fish
// Luck can increase up to 5% when it is at 100.
// Level can increase up to 10% when it is at 100.
.@boost=(readparam2(bLuk)/20)+(BaseLevel/10);
.@bai=getvariableofnpc(.bait_ids[@bait_d+1], .@npc$);
// Ancient Blueprint: 0.05% per bait bonus (no luck)
if (rand2(2000) < .@bp_chance*.@bai) {
.@fish_id = AncientBlueprint;
} else if (rand2(0, 100) < .@bai+.@boost) {
.@fish_id = any_of(.@rare_fish);
} else {
.@fish_id = any_of(.@common_fish);
}
specialeffect(.@success_fx, SELF, playerattached());
getexp getvariableofnpc(.bait_ids[@bait_d+1], .@npc$)+(BaseLevel/10), 0; // xp gain is equivalent to bait rarity + BaseLevel boost
// MobPt gain is equivalent to bait rarity.
if (MPQUEST)
Mobpt+=.@bai*limit(1, BaseLevel/10, 10);
if(!checkweight(.@fish_id, 1))
{
dispbottom l("You caught a @@ but had no room in your inventory to carry it.", getitemlink(.@fish_id));
makeitem .@fish_id, 1, .@mapbis$, .@xbis, .@ybis; // drop on the ground
return 0;
}
getitem .@fish_id, 1;
}
}
else
{
dispbottom l("You pulled too late and lost the bait...");
specialeffect(.@failure_fx, SELF, playerattached()); // event fail
.@fish_id = 0;
}
@fishing_spot$="";
return .@fish_id;
}
if (gettimetick(2) - .@last_used < .@regen_time)
{
dispbottom l("This fishing spot has just been used, give it a rest.");
return -5;
}
// This "hack" will prevent you from fishing at two spots (buggy)
// It'll cancel the previous fishing too, per logical rule.
if (@fishing_spot$ != "") {
deltimer "global fishing handler::OnCleanUp"; // cancel auto cleanup
deltimer "global fishing handler::OnBite";
fishing_cleanup(@fishing_spot$); // clean up manually
@fishing_spot$="";
dispbottom l("You left your fishing spot!");
return -4;
}
// begin fishing
narrator S_LAST_NEXT,
l("You see some fish reflecting the sun on the surface of the water."),
(.@net_ratio == 1 ? l("What will be the bait for the fish?") : l("You need @@ units of bait for this fishing spot. What will you use?", .@net_ratio));
mes "##B" + l("Drag and drop an item from your inventory.") + "##b";
.@bait = requestitem();
.@bait_c = false;
if (.@bait < .@net_ratio) {
narrator S_FIRST_BLANK_LINE,
l("You take your @@ and leave.", getitemlink(.@rod));
return -6;
}
if (countitem(.@bait) < .@net_ratio) {
mesc l("You do not have enough bait for fishing here.");
return -6;
}
for (.@i = 0; .@i < .@baits; .@i += 2) {
if (getvariableofnpc(.bait_ids[.@i], .@npc$) == .@bait)
{
.@bait_c = true;
@bait_d = .@i;
break;
}
}
if (.@bait_c != true)
{
narrator S_FIRST_BLANK_LINE,
l("This item cannot be used as bait here.");
return -6;
}
if (getvariableofnpc(.char_id, .@npc$) > 0)
{
narrator S_FIRST_BLANK_LINE,
l("Somebody took your place on this spot!"),
l("You take your fishing rod and leave.");
return -8;
}
@fishing_spot$ = .@npc$; // bind player to fishing spot
set getvariableofnpc(.account_id, .@npc$), getcharid(CHAR_ID_ACCOUNT); // record account id
set getvariableofnpc(.char_id, .@npc$), getcharid(CHAR_ID_CHAR); // record char id
set getvariableofnpc(.last_used, .@npc$), gettimetick(2);
getmapxy(@fishing_loc$[0], @fishing_loc[0], @fishing_loc[1], 0); // record char pos
delitem .@bait, .@net_ratio;
// The player uses this spot, his bait is ready, he just has to wait for the signal.
closedialog;
specialeffect(.@initial_fx, SELF); // throw the bait
sleep2 800; // wait 0.8s for synchronize the sound of "plop" in water with the npc dir UP.
setnpcdir .@npc$, UP;
dispbottom l("Wait for the bait to sink underwater.");
.@delay = rand(.@wait_time_min, .@wait_time_max);
addtimer .@delay, "global fishing handler::OnBite"; // bite logic
addtimer (.@delay + .@catch_time), "global fishing handler::OnCleanUp"; // auto clean up
return 0;
}