2016-01-21 16:48:41 +01:00
-- story quests
quests = { }
quests.player_quests = { }
2016-01-31 12:18:27 +01:00
quests.file = minetest.get_worldpath ( ) .. " /quests "
2016-03-31 13:51:15 +02:00
quests.callback = nil
2016-09-20 17:32:55 +02:00
quests.hud = { }
2016-01-31 12:18:27 +01:00
2016-07-10 02:57:03 +01:00
function quests . load ( )
2016-01-31 12:18:27 +01:00
local input = io.open ( quests.file , " r " )
if input then
local str = input : read ( " *all " )
if str then
if minetest.deserialize ( str ) then
quests.player_quests = minetest.deserialize ( str )
end
2016-07-10 02:57:03 +01:00
else
2016-01-31 12:18:27 +01:00
print ( " [WARNING] quest file is empty " )
end
io.close ( input )
else
print ( " [ERROR] couldnt find quest file " )
end
end
2016-07-10 02:57:03 +01:00
function quests . save ( )
2016-01-31 12:18:27 +01:00
if quests.player_quests then
local output = io.open ( quests.file , " w " )
local str = minetest.serialize ( quests.player_quests )
output : write ( str )
io.close ( output )
end
end
2016-01-21 16:48:41 +01:00
2016-08-03 12:59:54 +02:00
function quests . show_text ( text , player )
local parts = text : split ( " \n " )
for i , txt in ipairs ( parts ) do
minetest.after ( 2.9 * i , function ( txt , player )
if not ( minetest.get_player_by_name ( player ) ) then return end
cmsg.push_message_player ( minetest.get_player_by_name ( player ) , txt )
end , txt , player )
end
end
2016-01-21 16:48:41 +01:00
function quests . add_quest ( player , quest )
if not quests.player_quests [ player ] then
quests.player_quests [ player ] = { }
end
2016-03-04 20:08:14 +01:00
print ( " [quests] add quest " )
2016-01-21 16:48:41 +01:00
table.insert ( quests.player_quests [ player ] , quest )
2016-07-10 02:57:03 +01:00
quests.save ( )
2016-09-20 17:32:55 +02:00
quests.update_hud ( minetest.get_player_by_name ( player ) , player )
2016-08-03 12:59:54 +02:00
if # quest.goals > 0 then
quests.show_text ( quest.text .. " \n " .. quest.goals [ 1 ] . description , player )
else
quests.show_text ( quest.text , player )
end
2016-03-31 13:51:15 +02:00
return # quests.player_quests [ player ]
2016-01-21 16:48:41 +01:00
end
2016-07-10 02:57:03 +01:00
function quests . finish_quest ( player , quest )
2016-07-12 19:41:00 +02:00
if not ( quest.done ) then
2016-08-03 12:59:54 +02:00
cmsg.push_message_player ( minetest.get_player_by_name ( player ) , " [quest] You completed " .. quest.title )
2016-07-12 19:41:00 +02:00
end
2016-07-10 04:02:26 +01:00
xp.add_xp ( minetest.get_player_by_name ( player ) , quest.xp )
2016-07-10 02:57:03 +01:00
quest.done = true
2016-07-10 04:02:26 +01:00
if quests.callback then
2016-07-11 15:50:40 +02:00
quests.callback ( minetest.get_player_by_name ( player ) )
2016-07-10 04:02:26 +01:00
end
end
function quests . finish_goal ( player , quest , goal )
2016-07-12 19:41:00 +02:00
if not ( goal.done ) then
2016-08-03 12:59:54 +02:00
for i = 1 , # quest.goals do
if quest.goals [ i ] . requires and quest.goals [ i ] . requires.title == goal.title then
if quest.goals [ i ] . description then
quests.show_text ( quest.goals [ i ] . description , player )
end
end
end
2016-09-06 12:14:28 +02:00
2016-08-03 12:59:54 +02:00
if goal.reward then
minetest.get_player_by_name ( player ) : get_inventory ( ) : add_item ( " main " , goal.reward )
cmsg.push_message_player ( minetest.get_player_by_name ( player ) , goal.ending or " [quest] You completed a goal and you got a reward! " )
else
cmsg.push_message_player ( minetest.get_player_by_name ( player ) , goal.ending or " [quest] You completed a goal! " )
end
2016-09-06 12:14:28 +02:00
if goal.xp then
xp.add_xp ( minetest.get_player_by_name ( player ) , goal.xp )
end
2016-07-12 19:41:00 +02:00
end
2016-08-03 12:59:54 +02:00
2016-07-10 04:02:26 +01:00
goal.done = true
if not quest.done then
local all_done = true
for i = 1 , # quest.goals do
if not quest.goals [ i ] . done then
all_done = false
break
end
end
if all_done then
quests.finish_quest ( player , quest )
end
end
quests.save ( )
end
2016-08-03 12:59:54 +02:00
function quests . new ( player , title , text )
2016-07-10 04:02:26 +01:00
local quest = {
title = title ,
done = false ,
goals = { } ,
2016-08-03 12:59:54 +02:00
xp = 0 ,
text = text or " " ,
2016-07-10 04:02:26 +01:00
}
return quest
end
2016-08-03 12:59:54 +02:00
function quests . add_dig_goal ( quest , title , node , number , description , ending )
2016-07-10 04:02:26 +01:00
local goal = {
title = title ,
type = " dig " ,
node = node ,
max = number ,
progress = 0 ,
2016-08-03 12:59:54 +02:00
done = false ,
2016-09-06 12:14:28 +02:00
xp = 0 ,
2016-08-03 12:59:54 +02:00
description = description or " " ,
ending = ending or nil
2016-07-10 04:02:26 +01:00
}
table.insert ( quest.goals , goal )
return goal
end
2016-08-03 12:59:54 +02:00
function quests . add_place_goal ( quest , title , node , number , description , ending )
2016-07-10 04:02:26 +01:00
local goal = {
title = title ,
type = " placenode " ,
node = node ,
max = number ,
progress = 0 ,
2016-08-03 12:59:54 +02:00
done = false ,
2016-09-06 12:14:28 +02:00
xp = 0 ,
2016-08-03 12:59:54 +02:00
description = description or " " ,
ending = ending or nil
2016-07-10 04:02:26 +01:00
}
table.insert ( quest.goals , goal )
return goal
end
2016-09-04 14:08:14 +02:00
function quests . add_craft_goal ( quest , title , item , number , description , ending )
local goal = {
title = title ,
type = " craft " ,
item = item ,
node = item ,
max = number ,
progress = 0 ,
done = false ,
2016-09-06 12:14:28 +02:00
xp = 0 ,
2016-09-04 14:08:14 +02:00
description = description or " " ,
ending = ending or nil
}
table.insert ( quest.goals , goal )
return goal
end
2016-09-05 09:40:54 +02:00
function quests . process_node_count_goals ( player , type , node , count )
count = count or 1
2016-07-10 04:02:26 +01:00
local player_quests = quests.player_quests [ player ]
2016-07-12 19:41:00 +02:00
if not ( player_quests ) or # player_quests == 0 then return end
2016-07-10 04:02:26 +01:00
table.foreach ( player_quests , function ( _ , quest )
2016-07-12 19:41:00 +02:00
if not ( quest.goals ) or # quest.goals == 0 then return end
2016-07-10 04:02:26 +01:00
table.foreach ( quest.goals , function ( _ , goal )
if ( not goal.requires or goal.requires . done ) and
2016-08-03 12:59:54 +02:00
goal.type == type then
for i = 1 , # goal.node do
if goal.node [ i ] == node then
2016-09-05 09:40:54 +02:00
goal.progress = goal.progress + count
2016-08-03 12:59:54 +02:00
if goal.progress >= goal.max then
goal.progress = goal.max
quests.finish_goal ( player , quest , goal )
goal.done = true
end
2016-09-20 17:32:55 +02:00
quests.update_hud ( minetest.get_player_by_name ( player ) , player )
2016-08-03 12:59:54 +02:00
quests.save ( )
2016-07-10 04:02:26 +01:00
end
end
end
end )
end )
2016-07-10 02:57:03 +01:00
end
quests.show_quests_form = " size[8,7.5;] " .. default.gui_colors ..
2016-09-11 13:15:13 +02:00
default.gui_bg .. " textlist[-0.1,-0.1;8,7.75;quests;%s] "
2016-02-09 13:13:44 +01:00
2016-07-10 04:02:26 +01:00
function quests . format_goal ( player , quest , goal )
-- TODO: support formatting for more than just digging and placing
if goal.done then
2016-09-11 13:15:13 +02:00
return " #999999 \\ [x \\ ] " .. ( goal.title or " \\ [NO TITLE \\ ] " ) .. " ( " .. tostring ( goal.progress ) ..
" / " .. tostring ( goal.max ) .. " ) "
2016-07-10 04:02:26 +01:00
else
2016-09-11 13:15:13 +02:00
return " \\ [ \\ ] " .. ( goal.title or " \\ [NO TITLE \\ ] " ) .. " ( " .. tostring ( goal.progress ) ..
" / " .. tostring ( goal.max ) .. " ) "
2016-07-10 04:02:26 +01:00
end
end
2016-09-20 17:32:55 +02:00
function quests . update_hud ( player , name )
if quests.hud [ name ] == nil then return end
local player_quests = quests.player_quests [ name ]
if not player_quests or # player_quests == 0 then
player : hud_change ( quests.hud [ name ] , " text " , " " )
return
end
local txt = " "
for _ , quest in pairs ( player_quests ) do
2016-11-19 13:21:34 +01:00
if not ( quest.done ) and not ( quest.hidden ) then
2016-09-20 17:32:55 +02:00
txt = txt .. " -> " .. ( quest.title or " [NO TITLE] " ) .. " \n "
for _ , goal in pairs ( quest.goals ) do
if ( not goal.requires or goal.requires . done ) and not ( goal.done ) then
txt = txt .. " [ ] " .. ( goal.title or " [NO TITLE] " ) .. " ( " .. tostring ( goal.progress ) ..
" / " .. tostring ( goal.max ) .. " ) \n "
end
end
end
end
player : hud_change ( quests.hud [ name ] , " text " , txt )
end
2016-08-20 13:00:27 +02:00
function quests . get_formspec ( name )
local player_quests = quests.player_quests [ name ]
if not player_quests or # player_quests == 0 then
local s = quests.show_quests_form
s = string.format ( s , " You have not got any quests yet. " )
return s
end
local s = quests.show_quests_form
local txt = " "
for _ , quest in pairs ( player_quests ) do
if quest.done then
2016-09-11 13:15:13 +02:00
txt = txt .. " #999999 -> " .. ( quest.title or " \\ [NO TITLE \\ ] " ) .. " (Completed), "
2016-08-20 13:00:27 +02:00
else
2016-09-11 13:15:13 +02:00
txt = txt .. " -> " .. ( quest.title or " \\ [NO TITLE \\ ] " ) .. " , "
2016-08-20 13:00:27 +02:00
for _ , goal in pairs ( quest.goals ) do
if not goal.requires or goal.requires . done then
2016-09-11 13:15:13 +02:00
txt = txt .. quests.format_goal ( name , quest , goal ) .. " , "
2016-08-20 13:00:27 +02:00
end
end
end
end
2016-09-11 13:15:13 +02:00
s = string.format ( s , txt )
2016-08-20 13:00:27 +02:00
return s
end
2016-02-09 13:13:44 +01:00
minetest.register_chatcommand ( " quests " , {
params = " " ,
description = " Shows your quests " ,
privs = { } ,
func = function ( name , text )
2016-08-20 13:00:27 +02:00
minetest.show_formspec ( name , " quests:show_quests " , quests.get_formspec ( name ) )
2016-02-09 13:13:44 +01:00
return true , " "
end ,
} )
2016-01-21 16:48:41 +01:00
minetest.register_on_dignode ( function ( pos , oldnode , digger )
2016-07-10 02:57:03 +01:00
if not digger or not digger : is_player ( ) or
not quests.player_quests [ digger : get_player_name ( ) ] then
2016-01-21 16:48:41 +01:00
return
end
2016-07-10 02:57:03 +01:00
2016-07-10 04:02:26 +01:00
quests.process_node_count_goals ( digger : get_player_name ( ) , " dig " , oldnode.name )
2016-01-21 16:48:41 +01:00
end )
minetest.register_on_placenode ( function ( pos , newnode , placer , oldnode , itemstack , pointed_thing )
2016-07-10 02:57:03 +01:00
if not placer or not placer : is_player ( ) or
not quests.player_quests [ placer : get_player_name ( ) ] then
2016-01-21 16:48:41 +01:00
return
end
2016-07-10 02:57:03 +01:00
2016-07-10 04:02:26 +01:00
quests.process_node_count_goals ( placer : get_player_name ( ) , " placenode " , newnode.name )
2016-01-21 16:48:41 +01:00
end )
2016-09-04 14:08:14 +02:00
minetest.register_on_craft ( function ( itemstack , player , old_craft_grid , craft_inv )
if not player or not player : is_player ( ) or
not quests.player_quests [ player : get_player_name ( ) ] then
return
end
2016-09-05 09:40:54 +02:00
quests.process_node_count_goals ( player : get_player_name ( ) , " craft " , itemstack : get_name ( ) , itemstack : get_count ( ) )
2016-09-04 14:08:14 +02:00
end )
2016-09-20 17:32:55 +02:00
minetest.register_on_joinplayer ( function ( player )
if not player then
return
end
local name = player : get_player_name ( )
quests.hud [ name ] = player : hud_add ( {
hud_elem_type = " text " ,
name = " quests " ,
text = " " ,
position = { x = 1 , y = 0 } ,
alignment = { x = - 1 , y = 1 } ,
offset = { x =- 10 , y = 10 } ,
number = " 0xFFFFFF " ,
} )
minetest.after ( 1 , function ( player , name )
quests.update_hud ( player , name )
end , player , name )
end )
2016-01-21 16:48:41 +01:00
minetest.register_on_newplayer ( function ( player )
2016-07-11 15:50:40 +02:00
if not player then
return
end
2016-01-21 16:48:41 +01:00
quests.player_quests [ player : get_player_name ( ) ] = { }
2016-07-10 04:02:26 +01:00
local name = player : get_player_name ( )
2016-08-03 12:59:54 +02:00
2016-09-04 14:08:14 +02:00
--tutorial
do
local quest = quests.new ( name , " Tutorial " , " Hey you! \n I didnt see you before. Are you new here? \n Oh, Ok. \n I will help you to find the city \" NAME HERE \" . \n You will be save there. \n But first you need some basic equipment! " )
local q1 = quests.add_dig_goal ( quest , " Harvest Dirt/Grass " , { " default:dirt " , " default:grass " , " default:wet_grass " } , 10 , " You need to harvest some Dirt to get stones! " )
2016-09-06 12:14:28 +02:00
local q2 = quests.add_dig_goal ( quest , " Harvest Grass " , { " default:plant_grass " , " default:plant_grass_2 " , " default:plant_grass_3 " , " default:plant_grass_4 " , " default:plant_grass_5 " , " default:liana " , " default:grass " , " default:wet_grass " } , 12 , " Now you need to get some Grass to craft strings. " )
2016-09-04 14:08:14 +02:00
local q3 = quests.add_dig_goal ( quest , " Harvest Leaves " , { " default:leaves_1 " , " default:leaves_2 " , " default:leaves_3 " , " default:leaves_4 " } , 6 , " Harvest some leaves to craft twigs. " )
local q4 = quests.add_place_goal ( quest , " Place Workbench " , { " default:workbench " } , 1 , " You should craft a workbench and place it in front of you! " , " If you want to know how to craft things, \n just open the crafting guide I gave you. \n You can find all craftable items there! " )
local q5 = quests.add_craft_goal ( quest , " Craft Stone Axe " , { " default:axe_stone " } , 1 , " Now you can craft a Stone Axe. " )
local q6 = quests.add_dig_goal ( quest , " Harvest Logs " , { " default:log " , " default:log_1 " , " default:log_2 " , " default:log_3 " , " default:jungle_tree " } , 20 , " You can use the Stone Axe to harvest logs. " )
local q7 = quests.add_dig_goal ( quest , " Mine Stone " , { " default:stone " } , 20 , " You can also mine Stone with your Stone Axe. " )
2016-09-11 13:15:13 +02:00
local q8 = quests.add_craft_goal ( quest , " Craft a Flint Pick " , { " default:flint_pick " } , 1 , " Craft a Flint Pick! " , " You can use the flint pick to dig harder blocks. " )
local q9 = quests.add_dig_goal ( quest , " Mine Iron " , { " default:stone_with_iron " } , 2 , " Your Flint Pick is strong enough to mine Iron. " , " Great! You should be on level 2 now. \n Every time you level up you can upgrade on of your skills. \n Try out /skill warrior or /skill miner \n " )
2016-09-04 14:08:14 +02:00
q3.reward = " default:wood 3 "
q4.reward = " crafting_guide:book "
q2.requires = q1
q3.requires = q2
q4.requires = q3
q5.requires = q4
q6.requires = q5
2016-09-11 13:15:13 +02:00
q7.requires = q6
2016-09-04 14:08:14 +02:00
q8.requires = q7
2016-09-11 13:15:13 +02:00
q9.requires = q8
2016-08-03 12:59:54 +02:00
2016-09-11 13:15:13 +02:00
q5.xp = 10
q9.xp = 10
2016-09-04 14:08:14 +02:00
quest.xp = 10
2016-08-03 12:59:54 +02:00
2016-09-04 14:08:14 +02:00
quests.add_quest ( name , quest )
end
2016-08-03 12:59:54 +02:00
2016-09-04 14:08:14 +02:00
do
local quest = quests.new ( name , " Lets mine! " , " " )
local q1 = quests.add_dig_goal ( quest , " Mine Stone " , { " default:stone " } , 10 , " " )
local q2 = quests.add_dig_goal ( quest , " Mine Coal " , { " default:stone_with_coal " } , 10 , " " )
local q3 = quests.add_dig_goal ( quest , " Mine Iron " , { " default:stone_with_iron " } , 10 , " " )
local q4 = quests.add_dig_goal ( quest , " Mine Copper " , { " default:stone_with_copper " } , 10 , " " )
local q5 = quests.add_dig_goal ( quest , " Mine Diamond " , { " default:stone_with_diamond " } , 10 , " " )
2016-09-05 14:52:25 +02:00
q1.reward = " torch:torch 10 "
2016-09-06 12:14:28 +02:00
q1.xp = 10
2016-09-05 14:52:25 +02:00
q2.reward = " farming:apple 30 "
2016-09-06 12:14:28 +02:00
q2.xp = 15
2016-09-04 14:08:14 +02:00
q3.reward = " default:pick "
2016-09-06 12:14:28 +02:00
q3.xp = 30
2016-09-04 14:08:14 +02:00
q4.reward = " default:torch 99 "
2016-09-06 12:14:28 +02:00
q4.xp = 40
2016-09-04 14:08:14 +02:00
q5.reward = " default:torch 99 "
2016-09-06 12:14:28 +02:00
q5.xp = xp.get_xp ( 5 , 1 )
2016-09-04 14:08:14 +02:00
quest.xp = 0
2016-11-19 13:21:34 +01:00
quest.hidden = true
2016-09-04 14:08:14 +02:00
quests.add_quest ( name , quest )
end
2016-01-21 16:48:41 +01:00
end )
2016-07-10 02:57:03 +01:00
quests.load ( )
2016-03-04 20:08:14 +01:00
2016-07-30 13:02:18 +02:00
2016-04-21 16:40:13 +02:00
-- exploring
2015-12-31 11:01:14 +01:00
minetest.register_node ( " quests:map " , {
description = " Map " ,
2016-07-10 02:57:03 +01:00
tiles = { " quests_map_top.png " , " quests_map_top.png " , " quests_map.png " , " quests_map.png " , " quests_map.png " , " quests_map.png " } ,
2015-12-31 11:01:14 +01:00
groups = { quest = 1 , cracky = 3 } ,
on_punch = function ( pos , node , player , pointed_thing )
2016-01-08 12:54:36 +01:00
xp.add_xp ( player , math.random ( 3 , 30 ) )
2015-12-31 11:01:14 +01:00
minetest.remove_node ( pos )
end ,
} )
minetest.register_node ( " quests:ray " , {
description = " Ray " ,
tiles = { " quests_glowing_ray.png " } ,
2016-04-21 16:40:13 +02:00
groups = { cracky = 1 , ray = 1 } ,
2015-12-31 11:01:14 +01:00
paramtype = " light " ,
paramtype2 = " facedir " ,
drawtype = " nodebox " ,
light_source = 7 ,
node_box = {
type = " fixed " ,
fixed = {
{ - 0.2 , - 0.5 , - 0.2 , 0.2 , 0.5 , 0.2 } ,
} ,
} ,
2016-04-21 16:40:13 +02:00
drop = " " ,
2015-12-31 11:01:14 +01:00
} )