// Fluffy hunting quest // initially by Jenalya // more by alastrim // broken by o11c, then fixed // Variables: // global $@Fluffy_Hunting - state of the quest // 0: nobody is hunting // 1: somebody is hunting. The script checks every second if there is food on the ground. // 2: not used anymore, was: food dropped but no spawn yet // 3: not used anymore, was: monsters have been spawned // global $@Fluffy_Time - the number of seconds since you entered the area // global $@Fluffy_Spawn - how many fluffies have been spawned // global $@Fluffy_Kills - how many fluffies you have killed so far // global $@Fluffy_Min - how many fluffies you have to kill to get a reward // global $@Fluffy_Alive - how many fluffies are currently alive // global $@Fluffy_PC_Deaths - used to keep track of whether the fluffies kill you // global $@Fluffy_Fighter$ - name of the person hunting fluffies (only used for ornamentation) // global $@Fluffy_FighterID - ID of the person hunting fluffies // nibble 0 of QUEST_Barbarians - state for this and adjacent NPCs // 0: haven't talked about it // 1: heard about it // 2: finished quest // 3: got reward // Note: if you're going to reenable the "drop multiple times" feature // 1: please do it every second, not just once you've killed everything - Done // 2: you should change $@Fluffy_Spawn to $@Fluffy_Alive and decrement it on kills // Kept $@Fluffy_Spawn and added $@Fluffy_Alive. The script spawns the amount related to what you drop at each specific time. // 3: add a variable to spawn more fluffies if you drop more than 100 apples, as you kill them // Also, the $@Fluffy_Extra behaviour should be reconsidered (hardly anything spawns ...) // that's the only reason I didn't make that one a local variable like it really is 033-1.gat,74,32,0|script|Kimarr|218,{ if ($@Fluffy_FighterID == getcharid(3)) goto L_Attention; set @Q_Barbarians_MASK, NIBBLE_0_MASK; set @Q_Barbarians_SHIFT, NIBBLE_0_SHIFT; set @state, ((QUEST_Barbarians & @Q_Barbarians_MASK) >> @Q_Barbarians_SHIFT); if (@state >= 3) goto L_Again; if (@state == 2) goto L_Reward; if (@state == 1) goto L_Ask; mes "[Barbarian]"; mes "\"Greetings, little person.\""; next; mes "\"I am Kimarr, hunter and warrior of the Mangarr.\""; next; mes "\"You are very small, better be careful in this snowy mountains. It is cold and dangerous monsters are here.\""; menu "Hello, my name is " + strcharinfo(0) + " and I'm not small. I'm a great warrior!",-, "I'm " + strcharinfo(0) + ", don't underestimate me. I'm an experienced adventurer!" ,-, "I'm the legendary " + strcharinfo(0) + ", I've fought countless battles.",-; mes "Kimarr seems to be amused."; mes "[Kimarr]"; mes "\"Really? Do you want to prove it?\""; menu "Sure! What shall I do?", -, "No, I don't need to prove anything.", L_Close; L_Explain: mes "[Kimarr]"; mes "\"Every young member of our tribe proves his or her worth by hunting monsters.\""; next; mes "\"The first monsters to hunt are fluffies. Fluffies give a good meal for a young person and the fur can be used to make clothes and blankets.\""; next; set @state, 1; callsub S_Update_Mask; L_Explain_Game: mes "[Kimarr]"; mes "\"In that cave there are living fluffies. They like to eat apples.\""; next; mes "\"I also saw one of them getting excited about one of that sweet things you call 'cake'.\""; next; mes "\"You should be careful, other monsters living here might like the food as well\""; next; mes "\"Go to the cave entrance and throw food on the floor to make them come out.\""; next; mes "\"Then hunt as many fluffies as you can until I tell you to stop.\""; next; mes "\"Drop more food when no fluffies are left.\""; next; // dialog starts here if you've asked about it but not done it (@state == 1) L_Ask: mes "[Kimarr]"; mes "\"So, are you going to try?\""; menu "Yeah, let's start!", L_Game, "Could you explain again?", L_Explain_Game, "Maybe later.", -; goto L_Close; L_AlreadyGotReward: callsub S_Clean; mes "Once again you prove you are worth as a hunter, " + strcharinfo(0) + "."; goto L_Close; L_Reward1: if (@state >= 2) goto L_AlreadyGotReward; set @state, 2; callsub S_Update_Mask; callsub S_Clean; // as far as I can tell, this fails because it won't resume from the "next" // when the script is executed via the "OnFluffyDeath" callback // (I haven't tried via the 301st call of OnTimer1000) message strcharinfo(0), "Kimarr: talk to me for your reward"; goto L_Close; // this label is reached on completion of the quest, or, if you inventory was // full at the time, when you next initiate dialog (with @state == 2) L_Reward: mes "[Kimarr]"; mes "\"That was very impressive - now you can call yourself a hunter, " + strcharinfo(0) + ".\""; next; getinventorylist; if (@inventorylist_count == 100) goto L_Full_Inv; set @inventorylist_count, 0; mes "[Kimarr]"; mes "\"Take this as a symbol of your strength. You're a member of our tribe now.\""; getitem "YetiSkinShirt", 1; set @state, 3; callsub S_Update_Mask; goto L_Close; L_Full_Inv: mes "[Kimarr]"; mes "\"You can't carry the reward I want to give you.\""; goto L_Close; // dialog starts here after you've completed this quest L_Again: mes "[Kimarr]"; mes "\"Does the hunter " + strcharinfo(0) + " want to hunt some fluffies again?\""; menu "Yeah!", L_Game, "Can you tell me who were the most successful fluffy hunters?", L_ShowRecord, "Not now.", L_Close; L_Game: if ($@Fluffy_Hunting) goto L_Someone_Else; set $@Fluffy_Hunting, 1; set $@Fluffy_Kills, 0; set $@Fluffy_PC_Deaths, PC_DIE_COUNTER; set $@Fluffy_Fighter$, strcharinfo(0); set $@Fluffy_FighterID, getcharid(3); set $@Fluffy_Time, 180; //TODO: set minimum number of killed fluffies (maybe based on level?) set $@Fluffy_Min, 2; warp "033-1.gat", 79, 34; initnpctimer; goto L_Close; L_Someone_Else: mes "[Kimarr]"; mes "\"At the moment someone else is hunting. Let's wait until that hunting has ended.\""; goto L_Close; L_Attention: message strcharinfo(0), "Kimarr: You should be focused on hunting fluffies, not talking."; end; OnTimer1000: // Checking if player is logged if (isloggedin($@Fluffy_FighterID) == 0) goto L_GotOut; attachrid($@Fluffy_FighterID); // Checking if player is still in the map or used a towell or spell to get out if (getareausers("033-1.gat", 79, 28, 88, 42) == 0) goto L_GotOut; if (PC_DIE_COUNTER > $@Fluffy_PC_Deaths) goto L_Died; // Checking if there is more than 1 player in the fight area if (getareausers("033-1.gat", 79, 28, 88, 42) > 1) areatimer "033-1.gat", 79, 28, 88, 42, 10, "Kimarr::OnTooMany"; if ($@Fluffy_Time == 180) npctalk strcharinfo(0) + ", you have 3 minutes."; if ($@Fluffy_Time == 120) npctalk "You have 2 minutes left."; if ($@Fluffy_Time == 60) npctalk "You have 1 minute left."; if ($@Fluffy_Time == 30) npctalk "You have 30 seconds left."; if ($@Fluffy_Time == 15) npctalk "You have 15 seconds left."; if ($@Fluffy_Time == 10) npctalk "You have 10 seconds left."; if ($@Fluffy_Time == 5) npctalk "You have 5 seconds left."; set $@Fluffy_Time, $@Fluffy_Time - 1; if ($@Fluffy_Time < 0) goto L_TimeOver; goto L_CheckDrops; L_ContinueTimer: setnpctimer 0; end; L_GotOut: // TODO: this is the only use of $@Fluffy_Fighter$, can we remove it? npctalk "What a strange thing... " + $@Fluffy_Fighter$ + " just disappeared!"; callsub S_Clean; end; OnTooMany: if (getcharid(3) == $@Fluffy_FighterID) end; npctalk "Hey " + strcharinfo(0) + "! What are you doing there? This hunt is for " + $@Fluffy_Fighter$ + " alone!"; warp "033-1.gat", 77, 34; end; L_Died: warp "033-1.gat", 77, 34; message strcharinfo(0), "You are dead."; callsub S_Clean; end; L_TimeOver: message strcharinfo(0), "Your time is over."; goto L_MaybeRecordScore; L_CheckDrops: if ($@Fluffy_Alive >= 100) goto L_TooManyFluffies; set @Fluffy_Toomany, 0; set @Fluffy_RedApple, getareadropitem("033-1.gat", 79, 29, 88, 42, "RedApple", 1); set @Fluffy_XmasCake, getareadropitem("033-1.gat", 79, 29, 88, 42, "XmasCake", 1); set @Fluffy_Cake, getareadropitem("033-1.gat", 79, 29, 88, 42, "Cake", 1); set @Fluffy_GreenApple, getareadropitem("033-1.gat", 79, 29, 88, 42, "GreenApple", 1); if (@Fluffy_RedApple || @Fluffy_XmasCake || @Fluffy_Cake || @Fluffy_GreenApple) goto L_BeginHunting; goto L_ContinueTimer; L_TooManyFluffies: if (@Fluffy_Toomany) goto L_ContinueTimer; message strcharinfo(0), "Wow, calm down, there are already too many fluffies around here."; set @Fluffy_Toomany, 1; goto L_ContinueTimer; L_BeginHunting: set $@Fluffy_Spawn, @Fluffy_RedApple + 5 * @Fluffy_XmasCake + 3 * @Fluffy_Cake + @Fluffy_GreenApple; // limit the number of monsters that can be spawned, to prevent people creating lag with massive amount of monsters if ($@Fluffy_Spawn > 100) set $@Fluffy_Spawn, 100; areamonster "033-1.gat", 79, 29, 88, 42, "", 1089, $@Fluffy_Spawn, "Kimarr::OnFluffyDeath"; set $@Fluffy_Extra, 5 * @Fluffy_XmasCake + 3 * @Fluffy_Cake + 10 * BaseLevel; if ((BaseLevel > 40) && (rand($@Fluffy_Extra) > 500)) // Ice Goblin areamonster "033-1.gat", 79, 29, 88, 42, "", 1058, 1, "Kimarr::OnIceGoblinDeath"; if ((BaseLevel > 60) && (rand($@Fluffy_Extra) > 550)) // Santa Slime areamonster "033-1.gat", 79, 29, 88, 42, "", 1015, 1, "Kimarr::OnSantaSlimeDeath"; // TODO: add the wolvern as well when it has been added if ((BaseLevel > 70) && (rand($@Fluffy_Extra) > 600)) // Yeti areamonster "033-1.gat", 79, 29, 88, 42, "", 1072, 1, "Kimarr::OnYetiDeath"; set $@Fluffy_Extra, 0; set @Fluffy_RedApple, 0; set @Fluffy_XmasCake, 0; set @Fluffy_Cake, 0; set @Fluffy_GreenApple, 0; set $@Fluffy_Alive, $@Fluffy_Alive + $@Fluffy_Spawn; goto L_ContinueTimer; OnIceGoblinDeath: set @MobID, 1058; if (getcharid(3) != $@Fluffy_FighterID) goto L_Punish; set @MobID, 0; end; OnSantaSlimeDeath: set @MobID, 1015; if (getcharid(3) != $@Fluffy_FighterID) goto L_Punish; set @MobID, 0; end; OnYetiDeath: set @MobID, 1072; if (getcharid(3) != $@Fluffy_FighterID) goto L_Punish; set @MobID, 0; end; OnFluffyDeath: set @MobID, 1089; if ($@Fluffy_Hunting == 0) end; if (getcharid(3) != $@Fluffy_FighterID) goto L_Punish; set @MobID, 0; set $@Fluffy_Kills, $@Fluffy_Kills + 1; set $@Fluffy_Alive, $@Fluffy_Alive - 1; //TODO: remove announce after debugging // message strcharinfo(0), "Fluffies alive: " + $@Fluffy_Alive; // message strcharinfo(0), "Fluffies killed: " + $@Fluffy_Kills; if ($@Fluffy_Alive != 0) end; if (attachrid($@Fluffy_FighterID)) goto L_Killedall; goto L_GotOut; end; L_Punish: if (@MobID == 1089) areamonster "033-1.gat", 79, 29, 88, 42, "", 1089, 1, "Kimarr::OnFluffyDeath"; if (@MobID == 1058) areamonster "033-1.gat", 79, 29, 88, 42, "", 1058, 1, "Kimarr::OnIceGoblinDeath"; if (@MobID == 1015) areamonster "033-1.gat", 79, 29, 88, 42, "", 1015, 1, "Kimarr::OnSantaSlimeDeath"; if (@MobID == 1072) areamonster "033-1.gat", 79, 29, 88, 42, "", 1072, 1, "Kimarr::OnYetiDeath"; npctalk strcharinfo(0) + "! This hunt is for " + $@Fluffy_Fighter$ + " alone!"; percentheal -100, 0; set @MobID, 0; end; L_Killedall: message strcharinfo(0), "Good job, but you still have time to throw more food on the ground."; end; S_Clean: stopnpctimer; set $@Fluffy_Hunting, 0; set $@Fluffy_Time, 0; set $@Fluffy_PC_Deaths, 0; set $@Fluffy_Fighter$, ""; set $@Fluffy_FighterID, 0; set $@Fluffy_Kills, 0; set $@Fluffy_Spawn, 0; set $@Fluffy_Alive, 0; killmonster "033-1.gat", "Kimarr::OnIceGoblinDeath"; killmonster "033-1.gat", "Kimarr::OnSantaSlimeDeath"; killmonster "033-1.gat", "Kimarr::OnYetiDeath"; killmonster "033-1.gat", "Kimarr::OnFluffyDeath"; return; L_MaybeRecordScore: warp "033-1.gat", 77, 34; if ($@Fluffy_Kills < $@Fluffy_Min) goto L_NotGoodEnough; set @rank, 0; L_MaybeInsertNext: if ($@Fluffy_Kills > $Record_Fluffy_Kills[@rank]) goto L_InsertScore; // you already had a better score if (strcharinfo(0) == $Record_Fluffy_Name$[@rank]) goto L_Reward1; set @rank, @rank + 1; if (@rank == MAX_HIGH_SCORES) goto L_Reward1; goto L_MaybeInsertNext; L_InsertScore: set @loop, @rank; L_FindLastScore: // comment this out to allow the player to be in the list more than once // though actually, it might be better just to assume the list is full if (strcharinfo(0) == $Record_Fluffy_Name$[@loop]) goto L_MoveStuff; set @loop, @loop + 1; if (@loop == MAX_HIGH_SCORES) goto L_MoveStuff; goto L_FindLastScore; L_MoveStuff: if (@loop == @rank) goto L_FinallyInsertMe; set $Record_Fluffy_Kills[@loop], $Record_Fluffy_Kills[@loop - 1]; set $Record_Fluffy_Name$[@loop], $Record_Fluffy_Name$[@loop - 1]; set $Record_Fluffy_Date$[@loop], $Record_Fluffy_Date$[@loop - 1]; set @loop, @loop - 1; goto L_MoveStuff; L_FinallyInsertMe: set $Record_Fluffy_Kills[@rank], $@Fluffy_Kills; set $Record_Fluffy_Name$[@rank], strcharinfo(0); callfunc "time_stamp"; set $Record_Fluffy_Date$[@rank], @ts_date$ + " " + @ts_time$; set @ts_date$, ""; set @ts_time$, ""; goto L_Reward1; L_NotGoodEnough: callsub S_Clean; L_ShowRecord: set @rank, 0; set @loop, 0; L_ShowNextRecord: if ($Record_Fluffy_Kills[@loop] == 0) goto L_Close; mes (@loop + 1) + " - " + $Record_Fluffy_Name$[@loop] + " - " + $Record_Fluffy_Kills[@loop] + " fluffies killed at " + $Record_Fluffy_Date$[@loop]; set @loop, @loop + 1; goto L_ShowNextRecord; L_Close: // clear all temporary player variables that are not otherwise cleared // it is not feasible to otherwise clear @loop // but, not all jumpers to L_Close have necessarily used it ... // still, I think it's a good precent to ALWAYS exit via L_Close set @loop, 0; // if you unset @state, @Q_Barbarians_MASK or @Q_Barbarians_SHIFT, it might break the script // If only we had the concept of "local constants" ... close; S_Update_Mask: set QUEST_Barbarians, (QUEST_Barbarians & ~(@Q_Barbarians_MASK)) | (@state << @Q_Barbarians_SHIFT); return; }