Jump to content

daily quest structure in lua


Recommended Posts

Hello, I'm trying to make a daily quest and I wanted to ask you if the structure of this quest is correct or it is missing code or could have unexpected bug that i didn't calculate.

Is it correct to use set_state(start) at the end to make it repeatable? thank you

This is just an example

quest daily_quest begin
	state start begin
		when login or levelup with pc.get_level() >= 50 begin
			if get_time() > pc.getqf("daily_cd") then
				set_state(daily)
			end
		end

		when letter with pc.get_level() >= 50 begin
			send_letter("Daily QUest")
		end

		when button or info begin
			say_title("Daily QUesta")
			if ((get_global_time() - pc.getf("daily_cd","daily_wait_time")) < 60) then
				local remaining_wait_time = (pc.getf("daily_cd", "daily_wait_time") - get_global_time() + (60 * 60 * 24))
				say("You must wait for timer")
				say_reward("You can repeat in: "..get_time_remaining(remaining_wait_time)..'[ENTER]')
				return
			end
			say("Now you can repeat the quest.")
			set_state(daily)
		end
	end

	state daily begin
		when letter begin
			send_letter("Daily quest")
		end
		
		when button or info begin
			say_title("Daily quest")
			say("Daily quest active")
		end

		// mission
		when 101.kill begin
			chat("daily quest completed.")
			pc.setf("daily_cd", "daily_wait_time", get_global_time());
			pc.setqf("daily_cd", get_time() + 60 * 60 * 24);
			set_state(start)
		end
	end

end

 

Edited by Cripplez
Link to comment
Share on other sites

  • 1 year later...

There are few things that could be improved, I didn't test it, but it should be something like this:

 

quest daily_quest begin
	state start begin
		when login or levelup with pc.get_level() >= 50 begin
			if pc.getqf("daily_cd") < get_global_time() then
				set_state(daily)
			end
		end

		when letter with pc.get_level() >= 50 begin
			send_letter("Daily Quest")
		end

		when button or info begin
			say_title("Daily Quest")
			if (pc.getqf("daily_cd") + (60 * 60 * 24) - get_global_time() > 0) then
				local remaining_wait_time = (pc.getqf("daily_cd") + (60 * 60 * 24) - get_global_time())
				say("You must wait for timer")
				say_reward("You can repeat in: "..get_time_remaining(remaining_wait_time)..'[ENTER]')
				return
			end
			say("Now you can repeat the quest.")
			set_state(daily)
		end
	end

	state daily begin
		when letter begin
			send_letter("Daily Quest")
		end
		
		when button or info begin
			say_title("Daily Quest")
			say("Daily quest active")
		end

		// mission
		when 101.kill begin
			chat("daily quest completed.")
			pc.setqf("daily_cd", get_global_time() + (60 * 60 * 24));
			set_state(start)
		end
	end
end

Or even better, lets supposedly say that we have a given array with mobs and items from which we can randomly pick both the vnum of the monster and how many to be killed, and a random reward as well:

 

quest daily_quest begin
	state start begin
		when login or levelup with pc.get_level() >= 50 begin
			if pc.getqf("daily_cd") < get_global_time() then
				set_state(daily)
			end
		end

		when letter with pc.get_level() >= 50 begin
			send_letter("Daily Quest")
		end

		when button or info begin
			say_title("Daily Quest")
			if (pc.getqf("daily_cd") + (60 * 60 * 24) - get_global_time() > 0) then
				local remaining_wait_time = (pc.getqf("daily_cd") + (60 * 60 * 24) - get_global_time())
				say("You must wait for timer")
				say_reward("You can repeat in: "..get_time_remaining(remaining_wait_time)..'[ENTER]')
				return
			end
			say("Now you can repeat the quest.")
			set_state(daily)
		end
	end

	state daily begin
		// define the array of monsters and rewards
		local monsters = {101, 102, 103, 104, 105};
		local rewards = {{"itemVnum", 19, 1}, {"itemVnum", 19, 2}, {"itemVnum", 19, 3}, {"itemVnum", 19, 4}, {"itemVnum", 19, 5}};

		// pick a random monster and reward. By using math.random() function, this will randomly select a monster and reward from the defined arrays every time the quest is taken, making the quest different each time it is taken.
		local random_monster = monsters[math.random(1, #monsters)];
		local random_reward = rewards[math.random(1, #rewards)];

		when letter begin
			send_letter("Daily Quest", "Kill "..random_monster.." monsters and receive "..random_reward[1].." "..random_reward[2].." x"..random_reward[3])
		end

		when button or info begin
			say_title("Daily Quest")
			say("Kill "..random_monster.." monsters and receive "..random_reward[1].." "..random_reward[2].." x"..random_reward[3])
		end

		// mission
		when random_monster.kill with pc.count_item(random_reward[2]) < random_reward[3] begin
			pc.give_item2(random_reward[2], random_reward[3])
			chat("daily quest completed.")
			pc.setqf("daily_cd", get_global_time() + (60 * 60 * 24));
			set_state(start)
		end
	end
end

Again, not sure it will work. Maybe @ VegaS™ can spare few minutes to shade some light for both of us 🙂

Edited by SussyFlore96
Link to comment
Share on other sites

  • Premium

Some suggestions and heads-up for both of you.

1. Handle your states better, and also the when conditions. Players always need to be able to see the reason(s) why they can't do a quest at that moment.

2. Simplify your time checks.

3. Defining variables inside of a state is not possible, the only accepted things inside of a state are "when" triggers and "function"s. Currently, we have 3 types of variables at our disposal:

  1. local variables.
  2. quest-bound, also known as "defines", their scope is the whole quest.
  3. globals, non-local variables valid throughout the whole env.

4. "when" statements need their triggers to be specific, meaning even if you could assign a random npc to a variable named "A", writing "when A.kill" won't work. At most you can assign a specific vnum to a variable (use the questnpc.txt file for reference on how that works); or, you can use a "define" to achieve the same result, but again only on a static vnum, not a random or dynamic one. The only exception to this is the "when kill with" method, which creates a "notarget" folder and allows the trigger to work with dynamic code, but you still need to save your randomly generated vnum somehow in order to call it later and work with it.

 

Following all my suggestions and decent knowledge of the language should end you up with something like this:

This is the hidden content, please

Edited by Syreldar
  • Metin2 Dev 21
  • Eyes 1
  • Good 4
  • Love 3

 

"Nothing's free in this life.

Ignorant people have an obligation to make up for their ignorance by paying those who help them.

Either you got the brains or cash, if you lack both you're useless."

Syreldar

Link to comment
Share on other sites

Thanks, Syreldar. It indeed seems to be very nicely done and I have tried to test it, maybe I could enhance and use it in the future.

Few things I have noticed: global variables did not work for me, even with ./pre_qc, so I had to put them directly in the functions that uses them, as I got an error stating the quest must start with quest...

Furthermore, I found one little bug - the counter of the mobs killed did not work. I've tried multiple things, and what did the trick was to edit the when statement within "in_mission".

From:

        when kill with not npc.is_pc() and npc.get_race() == pc.getqf("to_kill") begin
            pc.setqf("killed", pc.getqf("killed")+1);

To:

	when kill with not npc.is_pc() and pc.getqf("to_kill") begin
		notice_all(string.format("to_kill: %d, killed: %d", pc.getqf("to_kill"), pc.getqf("killed"))); -- test how many monsters you have to kill, and how many you have killed so far
		pc.setqf("killed", pc.getqf("killed")+1);


Not sure why did you use npc.get-race() = pc.getqf("to_kill), yet I'm more than open to learn and understand the logic, if you're down and willing to detail a little.

Edited by SussyFlore96
Link to comment
Share on other sites

  • Premium
18 minutes ago, SussyFlore96 said:

I had to put them directly in the functions that uses them, as I got an error stating the quest must start with quest...

It means your qc does not support defines.

18 minutes ago, SussyFlore96 said:


Furthermore, I found one little bug - the counter of the mobs killed did not work. I've tried multiple things, and what did the trick was to edit the when statement within the "in_mission".

Keep in mind that I wrote that in 5 minutes spare, didn't even doublecheck.

The statement's structure is fine, the error was that I wrote "to_kill" (the flag we use to store the AMOUNT of monsters to kill), instead of "mob_vnum" (the flag we use to store the vnum of the monster to kill).

so the correct statement is:

when kill with not npc.is_pc() and npc.get_race() == pc.getqf("mob_vnum") begin

which translates to: "When you kill an entity which is not a character and its vnum is equal to the vnum of the monster we need to kill, trigger the code inside of the statement"

I have edited the original message.

Your "fix"

Quote

when kill with not npc.is_pc() and pc.getqf("to_kill") begin

Makes no sense, it works because effectively the second part of the condition just returns "true" since it's a value > 0, so it's like it's not even there; but you're not checking for the vnum at all, meaning that code will trigger on any entity which is not a character, so every monster or metinstone.

Edited by Syreldar
  • Good 1

 

"Nothing's free in this life.

Ignorant people have an obligation to make up for their ignorance by paying those who help them.

Either you got the brains or cash, if you lack both you're useless."

Syreldar

Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

Announcements



×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.