1-- Auto-create instance of NPCs binding 2-- (This avoid the need to explicitely it in the dialog scripts) 3-- The dialog's name of the NPC is used to create the Lua instance. 4-- It must univoquely identify one single NPC. Failing to respect 5-- that constraint can lead to some strange behaviors... 6-- You were warned ! 7setmetatable(_G, { 8 __index = function(t, name) 9 if rawget(_G, name) == nil then 10 -- script_helpers.lua is also loaded in the 'config' 11 -- context, without the FDrpg module being loaded. 12 if rawget(_G, "FDrpg") == nil then 13 return nil 14 end 15 local rtn, npc = pcall(FDrpg.get_npc, name) 16 if not rtn then 17 return nil 18 end 19 -- print("Creating " .. name) 20 rawset(_G, name, npc) 21 return npc 22 end 23 return rawget(_G, name) 24 end, 25}) 26 27-- set the random seed 28math.randomseed(os.time()) 29 30-- aliases for dialogs 31get_program = get_program_revision 32 33-- "_" is used as a gettext marker in dialogs as well as in config files. 34-- 35-- For dialog files, it is bound to a C function which translates text using 36-- the freedroidrpg-dialog domain. 37-- 38-- For config files, "_" is just used to declare i18n texts, but does not 39-- involve immediat translation. This thus has to be a 'void' function. 40-- 41-- So, if _() was not defined when the lua thread was created (config files use 42-- case), it is set to a 'void' function. 43_ = _ or function(t) return t end 44 45-- compute the "town score" to determine whether the player can become 46-- a red guard 47function get_town_score() 48 local town_score = 0 49 50 if (has_quest("Deliverance")) then 51 if (data_cube_lost) then 52 town_score = town_score - 5 53 elseif (done_quest("Deliverance")) then 54 town_score = town_score + 5 55 end 56 end 57 58 if (done_quest("Bender's problem")) then 59 town_score = town_score + 10 60 end 61 62 if (done_quest("The yellow toolkit")) then 63 town_score = town_score + 15 64 end 65 66 if (done_quest("Anything but the army snacks, please!")) then 67 town_score = town_score + 10 68 end 69 70 if (done_quest("Novice Arena")) then 71 town_score = town_score + 10 72 end 73 74 if (done_quest("Time to say goodnight")) then 75 town_score = town_score + 20 76 end 77 78 if (done_quest("Opening a can of bots...")) then 79 town_score = town_score + 15 80 end 81 82 if (KevinMurderCongratulation) then 83 town_score = town_score + 20 84 end 85 86 return town_score 87end 88 89-- this table describes obstacle states 90obstacle_states = { 91 [3] = {["opened"] = -1, ["closed"] = 3,}, 92 [4] = {["opened"] = -1, ["closed"] = 4,}, 93 [6] = {["opened"] = 6, ["closed"] = 26,}, 94 [7] = {["opened"] = 6, ["closed"] = 26,}, 95 [8] = {["opened"] = 6, ["closed"] = 26,}, 96 [9] = {["opened"] = 6, ["closed"] = 26,}, 97 [10] = {["opened"] = 6, ["closed"] = 26,}, 98 99 [11] = {["opened"] = 11, ["closed"] = 27,}, 100 [12] = {["opened"] = 11, ["closed"] = 27,}, 101 [13] = {["opened"] = 11, ["closed"] = 27,}, 102 [14] = {["opened"] = 11, ["closed"] = 27,}, 103 [15] = {["opened"] = 11, ["closed"] = 27,}, 104 105 [26] = {["closed"] = 26, ["opened"] = 6,}, 106 [27] = {["closed"] = 27, ["opened"] = 11,}, 107 108 [32] = {["enabled"] = 32, ["disabled"] = 324,}, 109 [33] = {["enabled"] = 33, ["disabled"] = 325,}, 110 [34] = {["enabled"] = 34, ["disabled"] = 326,}, 111 [35] = {["enabled"] = 35, ["disabled"] = 327,}, 112 113 [181] = {["opened"] = 181, ["closed"] = 191,}, 114 [182] = {["opened"] = 181, ["closed"] = 191,}, 115 [183] = {["opened"] = 181, ["closed"] = 191,}, 116 [184] = {["opened"] = 181, ["closed"] = 191,}, 117 [185] = {["opened"] = 181, ["closed"] = 191,}, 118 119 [186] = {["opened"] = 186, ["closed"] = 192,}, 120 [187] = {["opened"] = 186, ["closed"] = 192,}, 121 [188] = {["opened"] = 186, ["closed"] = 192,}, 122 [189] = {["opened"] = 186, ["closed"] = 192,}, 123 [190] = {["opened"] = 186, ["closed"] = 192,}, 124 125 [191] = {["closed"] = 191, ["opened"] = 181,}, 126 [192] = {["closed"] = 192, ["opened"] = 186,}, 127 128 [235] = {["broken"] = 237,}, 129 [236] = {["broken"] = 237,}, 130 [237] = {["broken"] = 237,}, 131 [323] = {["broken"] = 237,}, 132 133 [324] = {["disabled"] = 324, ["enabled"] = 32,}, 134 [325] = {["disabled"] = 325, ["enabled"] = 33,}, 135 [326] = {["disabled"] = 326, ["enabled"] = 34,}, 136 [327] = {["disabled"] = 327, ["enabled"] = 35,}, 137 138 [351] = {["closed"] = 351, ["opened"] = 353,}, 139 [352] = {["closed"] = 352, ["opened"] = 358,}, 140 141 [353] = {["opened"] = 353, ["closed"] = 351,}, 142 [354] = {["opened"] = 353, ["closed"] = 351,}, 143 [355] = {["opened"] = 353, ["closed"] = 351,}, 144 [356] = {["opened"] = 353, ["closed"] = 351,}, 145 [357] = {["opened"] = 353, ["closed"] = 351,}, 146 147 [358] = {["opened"] = 358, ["closed"] = 352,}, 148 [359] = {["opened"] = 358, ["closed"] = 352,}, 149 [360] = {["opened"] = 358, ["closed"] = 352,}, 150 [361] = {["opened"] = 358, ["closed"] = 352,}, 151 [362] = {["opened"] = 358, ["closed"] = 352,}, 152 153 [388] = {["enabled"] = 388, ["disabled"] = 407,}, 154 [407] = {["disabled"] = 407, ["enabled"] = 388,}, 155 156 -- glass walls 157 [281] = {["intact"] = 281, ["broken"] = 348,}, 158 [282] = {["intact"] = 282, ["broken"] = 446,}, 159 160 [348] = {["broken"] = 348, ["intact"] = 281,}, 161 [446] = {["broken"] = 446, ["intact"] = 282,}, 162 163 -- chests 164 [28] = {["locked"] = 28, ["unlocked"] = 30,}, 165 [29] = {["locked"] = 29, ["unlocked"] = 31,}, 166 167 [30] = {["unlocked"] = 30, ["locked"] = 28,}, 168 [31] = {["unlocked"] = 31, ["locked"] = 29,}, 169 170 [372] = {["locked"] = 372, ["unlocked"] = 374,}, 171 [373] = {["locked"] = 373, ["unlocked"] = 375,}, 172 173 [374] = {["unlocked"] = 374, ["locked"] = 372,}, 174 [375] = {["unlocked"] = 375, ["locked"] = 373,}, 175 176 177 [376] = {["locked"] = 376, ["unlocked"] = 378,}, 178 [377] = {["locked"] = 377, ["unlocked"] = 379,}, 179 180 [378] = {["unlocked"] = 378, ["locked"] = 376,}, 181 [379] = {["unlocked"] = 379, ["locked"] = 377,}, 182 183 -- lootable shelves 184 [466] = {["unlooted"] = 466, ["looted"] = 467,}, 185 [467] = {["looted"] = 467, ["unlooted"] = 466,}, 186 187 [468] = {["unlooted"] = 468, ["looted"] = 469,}, 188 [469] = {["looted"] = 469, ["unlooted"] = 468,}, 189 190 [470] = {["unlooted"] = 470, ["looted"] = 471,}, 191 [471] = {["looted"] = 471, ["unlooted"] = 470,}, 192 193 [472] = {["unlooted"] = 472, ["looted"] = 473,}, 194 [473] = {["looted"] = 473, ["unlooted"] = 472,}, 195 196 [474] = {["unlooted"] = 474, ["looted"] = 475,}, 197 [475] = {["looted"] = 475, ["unlooted"] = 474,}, 198 199 [476] = {["unlooted"] = 476, ["looted"] = 477,}, 200 [477] = {["looted"] = 477, ["unlooted"] = 476,}, 201 202 [478] = {["unlooted"] = 478, ["looted"] = 479,}, 203 [479] = {["looted"] = 479, ["unlooted"] = 478,}, 204 205 [480] = {["unlooted"] = 480, ["looted"] = 481,}, 206 [481] = {["looted"] = 481, ["unlooted"] = 480,}, 207 208 -- trapdoors 209 [150] = {["opened"] = 150, ["closed"] = 482,}, 210 [482] = {["closed"] = 482, ["opened"] = 150,}, 211 212 [149] = {["opened"] = 149, ["closed"] = 483,}, 213 [483] = {["closed"] = 483, ["opened"] = 149,}, 214 215 [24] = {["opened"] = 24, ["closed"] = 61,}, 216 [61] = {["closed"] = 61, ["opened"] = 24,}, 217 218 [23] = {["opened"] = 23, ["closed"] = 62,}, 219 [62] = {["closed"] = 62, ["opened"] = 23,}, 220 221 -- teleporter 222 [16] = {["purple"] = 16, ["blue"] = 17,}, 223 [17] = {["blue"] = 17, ["purple"] = 16,}, 224}; 225 226function get_obstacle_state_id(id, state) 227 local a = rawget(obstacle_states, id); 228 if (a == nil) then 229 error("Obstacle number " .. id .. " does not have any states defined.", 2); 230 end 231 232 a = rawget(a, state) 233 if (a == nil) then 234 error("State \"" .. state .. "\" is not defined for obstacle type " .. id .. ".", 2); 235 end 236 237 return a 238end 239 240function change_obstacle_state(label, state) 241 local id = get_obstacle_type(label); 242 243 change_obstacle_type(label, get_obstacle_state_id(id, state)); 244end 245 246function cmp_obstacle_state(label, state) 247 local id = get_obstacle_type(label); 248 249 return (id == get_obstacle_state_id(id, state)); 250end 251 252-- Quest functions 253function add_quest(quest, text) -- FDtux:add_quest 254 if (not running_benchmark()) then 255 if done_quest(quest) or 256 has_quest(quest) then 257 if (not running_benchmark()) then -- don't spam the validator 258 print(FDutils.text.highlight("\n\tSEVERE ERROR", "red")) 259 print(FDutils.text.highlight("\tTried to assign already assigned quest!", "red")) 260 print(FDutils.text.highlight("\tWe will continue execution, quest is:", "red")) 261 print(FDutils.text.highlight(quest, "red")) 262 end 263 end 264 end 265 assign_quest(quest, text) 266 play_sound("effects/Mission_Status_Change_Sound_0.ogg") 267 if (run_from_dialog()) then 268 cli_says(" "..S_"New Quest assigned: " .. D_(quest),"NO_WAIT") 269 npc_says("") 270 else 271 display_big_message(" "..S_"New Quest assigned: " .. D_(quest)) 272 end 273end 274 275function update_quest(quest, text) -- FDtux:update_quest 276 if (has_quest(quest)) then 277 add_diary_entry(quest, text) 278 play_sound("effects/Mission_Status_Change_Sound_0.ogg") 279 if (run_from_dialog()) then 280 cli_says(" ".._"Quest log updated: " .. D_(quest), "NO_WAIT") 281 npc_says("") 282 else 283 display_big_message(" "..S_"Quest log updated: " .. D_(quest)) 284 end 285 else -- we don't have the quest, wtf? 286 if (not running_benchmark()) then -- don't spam the validator 287 print(FDutils.text.highlight("\n\tSEVERE ERROR", "red")) 288 print(FDutils.text.highlight("\tTried to update quest that was never assigned!", "red")) 289 print(FDutils.text.highlight("\tWe will continue execution, quest is:", "red")) 290 print(FDutils.text.highlight(quest, "red")) 291 end 292 end 293end 294 295function end_quest(quest, text) -- FDtux:end_quest 296 if (not running_benchmark()) then -- don't spam the validator 297 if (done_quest(quest)) then 298 print(FDutils.text.highlight("\n\tERROR", "red")) 299 print(FDutils.text.highlight("\tTried to end already done quest!", "red")) 300 print(FDutils.text.highlight("\tWe will continue execution, quest is:", "red")) 301 print(FDutils.text.highlight(quest, "red")) 302 elseif (not has_quest(quest)) then 303 print(FDutils.text.highlight("\n\tSEVERE ERROR", "red")) 304 print(FDutils.text.highlight("\tTried to end never assigned quest!", "red")) 305 print(FDutils.text.highlight("\tWe will continue execution, quest is:", "red")) 306 print(FDutils.text.highlight(quest, "red")) 307 end 308 end 309 310 complete_quest(quest, text) 311 play_sound("effects/Mission_Status_Change_Sound_0.ogg") 312 if (run_from_dialog()) then 313 cli_says(" "..S_"Quest completed: " .. D_(quest),"NO_WAIT") 314 npc_says("") 315 else 316 display_big_message(" "..S_"Quest completed: " .. D_(quest)) 317 end 318end 319 320-- Set faction and name 321function npc_faction(faction, name) 322 set_npc_faction(faction) 323 if (name == nil) then 324 else 325 set_bot_name(name) 326 end 327end 328 329function chat_says_format(text, ...) 330 local arg = {...} 331 local no_wait = "WAIT" 332 if (arg[#arg] == "NO_WAIT") then 333 no_wait = "NO_WAIT" 334 table.remove(arg) 335 end 336 text = string.format(text, table.unpack(arg)) 337 return text, no_wait 338end 339 340function tux_says(text, ...) -- FDtux:says 341 local text, no_wait = chat_says_format('\1- ' .. text .. '\n', ...) 342 chat_says(text, no_wait) 343end 344 345function npc_says(text, ...) -- FDnpc:says 346 local text, no_wait = chat_says_format('\2' .. text .. '\n', ...) 347 chat_says(apply_bbcode(text,"\3","\2"), no_wait) 348end 349 350function cli_says(text, ...) 351 local text, no_wait = chat_says_format('\3' .. text, ...) 352 chat_says(text, no_wait) 353end 354 355function display_console_message(text) 356 event_display_console_message(apply_bbcode(text,"\4","\5")) 357end 358 359-- Magic font-numbers table: 360-- number font face default 361-- '\1' medium orange tux_says() 362-- '\2' medium yellow npc_says() 363-- '\3' medium blue cli_cays() 364-- '\4' small blue 365-- '\5' small yellow display_console_message() 366function apply_bbcode(text,magic_num_b,magic_num_nrm) 367 local text = string.gsub(text, '%[b%]', magic_num_b) 368 text = string.gsub(text, '%[/b%]', magic_num_nrm) 369 return text 370end 371 372function npc_says_random(...) -- FDnpc:says_random 373 arg = {...} 374 if (arg[#arg] == "NO_WAIT") then 375 npc_says(arg[math.random(#arg-1)],"NO_WAIT") 376 else 377 npc_says(arg[math.random(#arg)]) 378 end 379end 380 381function tux_says_random(...) -- FDtux:says_random 382 arg = {...} 383 if (arg[#arg] == "NO_WAIT") then 384 tux_says(arg[math.random(#arg-1)],"NO_WAIT") 385 else 386 tux_says(arg[math.random(#arg)]) 387 end 388end 389 390function get_random(...) 391 arg = {...} 392 return arg[math.random(#arg)] 393end 394 395function del_gold(gold_amount) -- FDtux:del_gold 396 if (gold_amount <= get_gold()) then 397 add_gold(-gold_amount) 398 return true 399 else 400 return false 401 end 402end 403 404function count_item(item_name) -- FDtux:count_item 405 local number = count_item_backpack(item_name) 406 if has_item_equipped(item_name) then 407 return number + 1 408 else 409 return number 410 end 411end 412 413function has_item_backpack(item_name) -- FDtux:has_item_backpack 414 return (count_item_backpack(item_name) > 0) 415end 416 417function del_item(item_name) -- FDtux:del_item 418 if (count_item_backpack(item_name) > 0) then 419 del_item_backpack(item_name) 420 return true 421 else 422 return false 423 end 424end 425 426function del_points(num_points) -- FDtux:del_points 427 if (get_training_points() >= num_points) then 428 del_training_points(num_points) 429 return true 430 else 431 return false 432 end 433end 434 435function can_tux_train(gold_amount, num_points) -- FDtux:can_train 436 if (get_gold() < gold_amount) then 437 return false 438 end 439 440 if (get_training_points() < num_points) then 441 return false 442 end 443 444 return true 445end 446 447function train_skill(gold_amount, num_points, skill) -- FDtux:train_skill 448 if (get_gold() < gold_amount) then 449 return false 450 end 451 452 if (get_training_points() < num_points) then 453 return false 454 end 455 456 add_gold(-gold_amount) 457 del_training_points(num_points) 458 improve_skill(skill) 459 return true 460end 461 462function train_program(gold_amount, num_points, program) -- FDtux:train_program 463 if (get_gold() < gold_amount) then 464 return false 465 end 466 467 if (get_training_points() < num_points) then 468 return false 469 end 470 471 add_gold(-gold_amount) 472 del_training_points(num_points) 473 improve_program(program) 474 return true 475end 476 477function tux_hp_ratio() -- FDtux:get_hp_ratio 478 return get_tux_hp()/get_tux_max_hp() 479end 480 481function npc_damage_ratio() -- FDnpc:get_damage_ratio 482 return npc_damage_amount()/npc_max_health() 483end 484 485function del_health(num_points) -- FDtux:del_health 486 if (num_points < get_tux_hp()) then 487 hurt_tux(num_points) 488 return true 489 else 490 return false 491 end 492end 493 494function drain_bot() -- FDnpc:drain_health 495--[[ npc_damage_amount - npc_max_health will return the HPs of the droid 496 for example: max_HP = 20, DMG_amount = 10 ; 10-20 = -10 497 hurt_tux(-10) will heal tux by 10 HP 498 to have the difficulty lvl influence the HP tux gets we divide the 499 heal-HP by the difficulty_lvl+1 (to prevent division by zero) 500 -10/2 (difficulty_lvl = 3/hard) = -5. Tux will be healed by 5 HP ]]-- 501 hurt_tux((npc_damage_amount() - npc_max_health())/(difficulty_level()+1)) 502 drop_dead() 503end 504 505function difficulty() 506 local levels = {"easy", "normal", "hard"} 507 return levels[difficulty_level()+1] 508end 509 510function get_random_bot_59() 511 local bot_59 = get_random(123, 139, 247, 249, 296, 296, 302, 302, 329, 329, 420, 512 420, 476, 476, 493, 493, 516, 516, 516, 571, 571, 571, 598, 513 598, 598, 614, 614, 614, 615, 615, 615, 629, 629, 629, 711, 514 711, 711, 742, 742, 742, 751, 751, 751, 821, 821, 821, 834, 515 834, 834, 883, 883, 883, 999, 999, 999, 543, 516 543, 543, 603) -- "GUN") 517 return bot_59 518end 519 520function has_item(...) -- FDtux:has_item 521 for i,item in ipairs({...}) do 522 if (not (count_item(item) > 0)) then 523 return false 524 end 525 end 526 return true 527end 528 529--[[ 530>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<< 531 24 / Debug Level below this line: 532~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 533]]-- 534 535function closelvl24doors() 536 change_obstacle_state("24door1", "closed") 537 change_obstacle_state("24door2", "closed") 538 change_obstacle_state("24door3", "closed") 539 change_obstacle_state("24door4", "closed") 540end 541 542function openlvl24doors() 543 change_obstacle_state("24door1", "opened") 544 change_obstacle_state("24door2", "opened") 545 change_obstacle_state("24door3", "opened") 546 change_obstacle_state("24door4", "opened") 547end 548 549function level24obstacles() 550 local randobstacletype 551 function level24newid() 552 randobstacletype = math.random(0,465) -- 466 obstacles 553 end 554 function level24idcheck() 555 if (randobstacletype == 25) then 556 -- cat ./map/obstacle_specs.lua | grep "image_filenames" | nl -v 0| grep "DUMMY" (note: skip the last one) 557 display_big_message(randobstacletype.." getting new id") 558 level24newid() 559 level24idcheck() 560 end 561 end 562 level24newid() 563 level24idcheck() 564 display_big_message(randobstacletype) 565 change_obstacle_type("24randobst", randobstacletype) 566end 567 568 569