fb_naethvjirr = obj { nam = "fb_naethvjirr"; disp2 = "Наэтвьирра"; position = 4; throw = 0; -- оставшиеся ходы до возможности применения (раз в 4 хода) charge = 0; -- оставшиеся ходы до возможности применения (раз в 3 хода) shield = true; -- активность щита shieldRecharge = false; -- О, как я люблю эти маленькие костыли. Это нужно, чтобы щит не восстанавливался сразу после выстрела canshoot = function(s) return not s.shield; end; canhit = function(s) return not s.shield; end; nohitmsg = "Это бессмыссленно, пока он закрыт щитом"; noshootmsg = "Это бессмыссленно, пока он закрыт щитом"; hitpoints = 3; passturn = function(s) if (s.hitpoints > 0) then local gens = 0; for i = 0, #final_battle.generators do if (final_battle.generators[i] == 4) then gens = gens + 1; s.charge = s.charge - 1; elseif (final_battle.generators[i] == 3) then gens = gens + 1; s.throw = s.throw - 1; elseif (final_battle.generators[i] == 2) then gens = gens + 1; if (not s.shield) then if (s.shieldRecharge) then s.shield = true; s.shieldRecharge = false; p("Щит вокруг Наэтвьирра восстановлен и он снова защищен от ваших атак. "); else s.shieldRecharge = true; end; end; end; end; if (gens == 0) then p("Глаза Наэтвьирра гаснут, и конструкт бессильно падает на пол. "); s.hitpoints = 0; return true; end; if (s.charge <= 0) then -- Пускаем разряд в игрока s.charge = 3; p("Наэтвьирр отправляет в вас электрический разряд. Вы не можете пошевелиться. "); if (rnd(4) < 2) then -- Отбросить игрока в сторону p("Разряд отбрасывает вас в сторону. "); fb_throwAway(pl); end; if (rnd(4) < 2) then -- 25% p("Вы чувствуете, что атака не прошла для вас бесследно. "); pl.hitpoints = pl.hitpoints - 1; if (pl.hitpoints <= 0) then walk(game_over_naethvjirr); return; end; end; final_battle.passturn(final_battle); p("Вы оправились от атаки Наэтвьирра и снова можете действовать. "); elseif (s.throw <= 0) then -- Отбрасываем игрока s.throw = 4; fb_throwAway(pl); p("Наэтвьирр отправляет в вас мощную волну воздуха, которая отбрасывает вас в сторону. "); if (rnd(4) > 1) then -- 75% pl.hitpoints = pl.hitpoints - 1; p("Вы чувствуете, что атака не прошла для вас бесследно. "); if (pl.hitpoints <= 0) then walk(game_over_naethvjirr); return; end; end; end; end; end; onhit = function(s) local result = ""; s.hitpoints = s.hitpoints - 1; if (s.hitpoints == 2) then result = "Сильный удар повреждает Наэтвьирра, но вы не замечаете, сказалось ли это на его работоспособности. "; elseif (s.hitpoints == 1) then result = "Наэтвьирр пошатнулся от вашего удара, давая понять, что попадание не прошло бесследно. "; elseif (s.hitpoints == 0) then result = "После вашего удара глаза Наэтвьирра гаснут и конструкт с грохотом падает рядом со своим троном. "; end; p(result); final_battle.passturn(final_battle); end; onshoot = function(s) local hit = false; if (pl.position[1] == 1 and pl.position[2] == 1) then hit = (rnd(4) > 1); else hit = (rnd(2) > 1); end; local result = ""; if (hit) then s.hitpoints = s.hitpoints - 1; if (s.hitpoints == 2) then result = "Ваш выстрел повреждает Наэтвьирра, но вы не замечаете, сказалось ли это на его работоспособности. "; elseif (s.hitpoints == 1) then result = "Глаза Наэтвьирра на мгновение моргают, давая понять, что попадание не прошло бесследно. "; elseif (s.hitpoints == 0) then result = "Глаза Наэтвьирра гаснут и конструкт с грохотом падает рядом со своим троном. "; end; else result = "Пуля пролетает мимо конструкта, не причинив ему никакого вреда. "; end; pn(result); final_battle.passturn(final_battle); end; dsc = function(s) if (s.hitpoints > 0) then local shield = ""; if (s.shield) then shield = "Вокруг него едва заметно силовое поле, защищающее его от физических повреждений. "; end; return "В центре зала перед массивной конструкцией, напоминающей трон, стоит {навьяр}. Конструкт выглядит совершенно как живой, сияющие красноватым светом глаза внимательно следят за вашими действиями. ".. shield .."^"; else --return "В центре зала рядом с массивной конструкцией, напоминающей трон, лежит сильно поврежденный {навьяр-конструкт}. ^"; return ""; end; end; }; fb_black = obj { nam = "fb_black"; position = 4; bullets = 6; -- потребуется перезарядка, если потратит все 6 патронов. Скорее всего до этого никогда не дойдет, но предусмотреть стоит hitpoints = 1; disp2 = "Блэка"; canshoot = function(s) if (pl.position[1] == 1 and pl.position[2] == 1) then return true; else return false; end; end; noshootmsg = "Вы не попадете в него. "; nohitmsg = "Для этого до него еще надо добраться. "; dsc = function(s) if (s.hitpoints > 0) then return "{Адриан Блэк} укрылся от вас за троном. ^"; end; end; onshoot = function(s) if (rnd(2) > 1) then--50% s.hitpoints = 0; p("Вы раните Блэка в плечо, он роняет пистолет и скрывается за троном. Более он не опасен. "); else p("Ваша пуля пролетает мимо, не причинив Блэку никакого вреда. "); end; final_battle.passturn(final_battle); end; passturn = function(s) if (s.hitpoints > 0) then if (s.bullets > 0) then if (pl.position[1] == 1 and pl.position[2] == 1) then -- Стреляем в игрока p("Блэк стреляет в вас. "); if (rnd(4) > 1) then--75% pl.hitpoints = pl.hitpoints - 1; if (pl.hitpoints > 0) then p("Пуля лишь слегка задевает вас, практически не нанеся урона. "); else walk(game_over_shot_fb); end; end; end; else -- Перезаряжаем s.bullets = 6; p("Адриан Блэк перезаряжает револьвер. "); end; end; end; }; fb_pylons = obj { nam = "fb_pylons"; position = "с"; state = 2;--Количество активных пилонов charging = 0; canhit = true; noshootmsg = "Вы не попадете в них"; onhit = function(s) if (s.state > 0) then if (pl.position[1] == 1 and pl.position[2] == 1) then s.state = s.state - 1; if (s.state == 0) then -- Если оба пилона уничтожены, нет смысла передавать им энергию. for i = 0, #final_battle.generators do if (final_battle.generators[i] == 5) then final_battle.generators[i] = 1; end; end; end; p("Ударом по металлическому стержню, вы выводите из строя один из пилонов"); final_battle.passturn(final_battle); else return "Пилоны слишком далеко от вас"; end; else return "Оба пилона уже выведены из строя"; end; end; passturn = function(s) for i = 1, #final_battle.generators do if (final_battle.generators[i] == 5) then s.charging = s.charging + 1; end; end; if (s.charging >= 10) then pl.hitpoints = 0; walk(game_over_pylon); end; end; dsc = function(s) if (s.state == 2) then return "В центральной части комнаты расположены два {пилона} высотой около метра. На вершине их установлены сверкающие металлические стержни.^"; elseif (s.state == 1) then return "В центральной части комнаты расположены два {пилона} высотой около метра. На вершине одного из пилонов установлен сверкающий металлический стержень. Стержень на втором пилоне сильно погнут и выведен из строя.^"; elseif (s.state == 0) then return "В центральной части комнаты расположены два пилона высотой около метра. Металлические стержни, установленные в их вершине сильно повреждены.^"; end; end; }; fb_throwAway = function(target) local positions = {}; if (target.position[1] - 1 >= 0) then if (target.position[2] - 1 >= 0) then positions[#positions + 1] = {target.position[1] - 1, target.position[2] - 1}; end; positions[#positions + 1] = {target.position[1] - 1, target.position[2]}; if (target.position[2] + 1 <= 2) then positions[#positions + 1] = {target.position[1] - 1, target.position[2] + 1}; end; end; if (target.position[2] - 1 >= 0) then positions[#positions + 1] = {target.position[1], target.position[2] - 1}; end; if (target.position[2] + 1 <= 2) then positions[#positions + 1] = {target.position[1], target.position[2] + 1}; end; if (target.position[1] + 1 <= 2) then if (target.position[2] - 1 >= 0) then positions[#positions + 1] = {target.position[1] + 1, target.position[2] - 1}; end; positions[#positions + 1] = {target.position[1] + 1, target.position[2]}; if (target.position[2] + 1 <= 2) then positions[#positions + 1] = {target.position[1] + 1, target.position[2] + 1}; end; end; target.position = positions[rnd(#positions)]; end; fb_getGeneratorIcon = function(value) if (value == 0) then return "images/fb_inactive.png"; elseif (value == 1) then return "images/fb_awake.png"; elseif (value == 2) then return "images/fb_shield.png"; elseif (value == 3) then return "images/fb_throw.png"; elseif (value == 4) then return "images/fb_charge.png"; elseif (value == 5) then return "images/fb_pylon.png"; end; end; final_battle = room { nam = "final_battle"; pic = function(s) local image = 'images/fb_bcg.png'; image = image .. ";" .. fb_getGeneratorIcon(s.generators[1]) .. "@48,0"; image = image .. ";" .. fb_getGeneratorIcon(s.generators[2]) .. "@96,0"; image = image .. ";" .. fb_getGeneratorIcon(s.generators[3]) .. "@96,48"; image = image .. ";" .. fb_getGeneratorIcon(s.generators[4]) .. "@96,96"; image = image .. ";" .. fb_getGeneratorIcon(s.generators[5]) .. "@48,96"; image = image .. ";" .. fb_getGeneratorIcon(s.generators[6]) .. "@0,96"; image = image .. ";" .. fb_getGeneratorIcon(s.generators[7]) .. "@0,48"; image = image .. ";" .. fb_getGeneratorIcon(s.generators[8]) .. "@0,0"; if (fb_naethvjirr.hitpoints > 0) then image = image .. ";images/fb_naethvjirr.png@64,80"; end; if (fb_black.hitpoints > 0) then image = image .. ";images/fb_black.png@80,80"; end; image = image .. ";images/fb_player.png@"..tostring(pl.position[1] * 48 + 16)..","..tostring((2 - pl.position[2]) * 48 + 16); if (fb_pylons.state > 1) then image = image .. ";images/fb_pylon.png@48,64"; else image = image .. ";images/fb_inactive.png@48,64"; end; if (fb_pylons.state > 0) then image = image .. ";images/fb_pylon.png@80,64"; else image = image .. ";images/fb_inactive.png@80,64"; end; return image; end; disp = "Лсэрианотр, центральный зал"; awakening = 300; dsc = function(s) local temp = ""; if (pl.position[1] == 1 and pl.position[2] == 2) then temp = "северной"; elseif (pl.position[1] == 2 and pl.position[2] == 2) then temp = "северо-восточной"; elseif (pl.position[1] == 2 and pl.position[2] == 1) then temp = "восточной"; elseif (pl.position[1] == 2 and pl.position[2] == 0) then temp = "юго-восточной"; elseif (pl.position[1] == 1 and pl.position[2] == 0) then temp = "южной"; elseif (pl.position[1] == 0 and pl.position[2] == 0) then temp = "юго-западной"; elseif (pl.position[1] == 0 and pl.position[2] == 1) then temp = "западной"; elseif (pl.position[1] == 0 and pl.position[2] == 2) then temp = "северо-западной"; elseif (pl.position[1] == 1 and pl.position[2] == 1) then temp = "центральной"; end; local debug_str = tostring(s.awakening) .. " "; debug_str = debug_str .. tostring(fb_pylons.charging) .. " "; return "Вы находитесь в " .. temp .. " части главного зала древнего города Навьяр. На схеме приведено расположение важных объектов в комнате, включая символы, изображенные на генераторах" .. debug_str; --Вдоль стен стоят огромные металлические шкафы, из которых тысячи проводом тянутся к громадной конструкции в центре зала. Мягкий свет льется сверху, практически ослепляя вас после полумрака остальной части мертвого города. " --]]; end; left = function(s) lifeoff(s); end; entered = function(s) -- Здесь будем собирать все необходимое для начала финальной битвы: сопартийцы отыграют свою роль, после чего начнется битва не на жизнь, а на смерть. s.entered = nil; -- Должно отработать не более одного раза pl.position = {1,2}; local throw = rnd(8); while (s.generators[throw] ~= 1) do throw = rnd(8); end; s.generators[throw] = 3; local shield = rnd(8); while (s.generators[shield] ~= 1) do shield = rnd(8); end; s.generators[shield] = 2; local charge = rnd(8); while (s.generators[charge] ~= 1) do charge = rnd(8); end; s.generators[charge] = 4; local pylon = rnd(8); while (s.generators[pylon] ~= 1) do pylon = rnd(8); end; s.generators[pylon] = 5; --[[for i = 1, #pl.party do if (pl.party[i] == "phaetlarr") elseif (pl.party[i] == "learr") elseif (pl.party[i] == "radcliffe") elseif (pl.party[i] == "wright") end; end;]] lifeon(s); end; life = function(s) fb_north:enable(); fb_northeast:enable(); fb_east:enable(); fb_southeast:enable(); fb_south:enable(); fb_southwest:enable(); fb_west:enable(); fb_northwest:enable(); if (pl.position[2] == 2) then fb_north:disable(); fb_northeast:disable(); fb_northwest:disable(); elseif (pl.position[2] == 0) then fb_south:disable(); fb_southeast:disable(); fb_southwest:disable(); end; if (pl.position[1] == 2) then fb_east:disable(); fb_northeast:disable(); fb_southeast:disable(); elseif (pl.position[1] == 0) then fb_west:disable(); fb_northwest:disable(); fb_southwest:disable(); end; fb_generator:enable(); if (pl.position[1] == 1 and pl.position[2] == 2) then fb_generator.index = 1; elseif (pl.position[1] == 2 and pl.position[2] == 2) then fb_generator.index = 2; elseif (pl.position[1] == 2 and pl.position[2] == 1) then fb_generator.index = 3; elseif (pl.position[1] == 2 and pl.position[2] == 0) then fb_generator.index = 4; elseif (pl.position[1] == 1 and pl.position[2] == 0) then fb_generator.index = 5; elseif (pl.position[1] == 0 and pl.position[2] == 0) then fb_generator.index = 6; elseif (pl.position[1] == 0 and pl.position[2] == 1) then fb_generator.index = 7; elseif (pl.position[1] == 0 and pl.position[2] == 2) then fb_generator.index = 8; elseif (pl.position[1] == 1 and pl.position[2] == 1) then fb_generator:disable(); end; local activeGens = false; for i = 1, #s.generators do if (s.generators[i] ~= 0) then activeGens = true; end; end; if (not activeGens) then walk(game_over_victory); end; end; passturn = function(s) -- реальный расчет боевых действий будет в этой функции for i = 1,#s.generators do if (s.generators[i] == 1) then s.awakening = s.awakening - 10; end; end; for i = 1,#s.obj do if (s.obj[i].passturn) then s.obj[i].passturn(s.obj[i]); end; end; if (s.awakening <= 0) then walk(game_over_awakening); end; end; generators = { 1, 1, 1, 1, 1, 1, 1, 1 -- В этот массив заносятся состояния генераторов: a - active, i - inactive, t - throw, s - shield, c - charge, p - pylon -- Состояния генераторов записываются цифрами по приоритету от минимального до максимального(чем больше цифра, тем больше приоритет) -- 0 - inactive, 1 - active, 2 - shield, 3 - throw, 4 - charge, 5 - pylon }; obj = { 'fb_pylons', 'fb_naethvjirr', 'fb_black', 'fb_generator', 'fb_north', 'fb_northeast', 'fb_east', 'fb_southeast', 'fb_south', 'fb_southwest', 'fb_west', 'fb_northwest' }; }; fb_generator = obj { nam = "fb_generator", dsc = function(s) if (final_battle.generators[s.index] == 0) then return "Рядом с вами расположен огромный металлический {шкаф}, искореженный несколькими ударами тяжелого предмета. Судя по всему этот генератор выведен из строя. ^"; else return "Рядом с вами расположен огромный металлический {шкаф}, расположенный рядом с вами издает негромкий гул. На его передней стенке виден светящийся символ. Конструкция соединена толстыми проводами с троном Наэтвьирра, в центре зала. ^"; end; end; index = 0; act = "Вы ничего не сможете сделать с генератором без дополнительных приспособлений"; noshootmsg = "Это бесполезно"; canhit = true; onhit = function(s) --[[ Модули питания могут быть назначены на одну из нескольких подсистем. Для питания каждой подсистемы требуется минимум один источник ее питания. Всего подсистемы следующие: пилоны, щит, разряд, разброс и пробуждение. Приоритеты распределения таковы: Всегда должна быть активна минимум одна атакующая подсистема, в порядке эффективности: пилоны, разряд, разброс. Если для атакующих подсистем достаточно энергии, то активен и щит. Наименьшим приоритетом обладает пробуждение. Также учитывается возможность и целесообразность применения защитных и атакующих подсистем: Если аватар уничтожен, нет смысла поддерживать щит, разброс и разряд. ]] local gen = final_battle.generators[s.index]; final_battle.generators[s.index] = 0; local moreInfo = ""; if (gen == 5) then --Как самая эффективная система атаки, пилоны всегда заряжаются, независимо от обстоятельств fb_pylons.charging = fb_pylons.charging - 4; if (fb_pylons.charging < 0) then fb_pylons.charging = 0; end; local priorityToReplace = 4; local activeCount = 0; for i = 1,#final_battle.generators do if (final_battle.generators[i] ~= 0 and final_battle.generators[i] <= priorityToReplace) then activeCount = activeCount + 1; if (final_battle.generators[i] < priorityToReplace) then priorityToReplace = final_battle.generators[i]; end; end; end; if (activeCount > 0) then local replacementIndex = rnd(8); while (final_battle.generators[replacementIndex] ~= priorityToReplace) do replacementIndex = rnd(8); end; final_battle.generators[replacementIndex] = gen; end; elseif (gen == 4) then fb_naethvjirr.charge = fb_naethvjirr.charge + 1; local priorityToReplace = 3; local activeCount = 0; for i = 1,#final_battle.generators do if (final_battle.generators[i] ~= 0 and final_battle.generators[i] <= priorityToReplace) then activeCount = activeCount + 1; if (final_battle.generators[i] < priorityToReplace) then priorityToReplace = final_battle.generators[i]; end; end; end; if (activeCount > 0) then local replacementIndex = rnd(8); while (final_battle.generators[replacementIndex] ~= priorityToReplace) do replacementIndex = rnd(8); end; final_battle.generators[replacementIndex] = gen; end; elseif (gen == 3) then fb_naethvjirr.throw = fb_naethvjirr.throw + 1; local priorityToReplace = 2; local activeCount = 0; for i = 1,#final_battle.generators do if (final_battle.generators[i] ~= 0 and final_battle.generators[i] <= priorityToReplace) then activeCount = activeCount + 1; if (final_battle.generators[i] < priorityToReplace) then priorityToReplace = final_battle.generators[i]; end; end; end; if (activeCount > 0) then local replacementIndex = rnd(8); while (final_battle.generators[replacementIndex] ~= priorityToReplace) do replacementIndex = rnd(8); end; final_battle.generators[replacementIndex] = gen; end; elseif (gen == 2) then fb_naethvjirr.shield = false; moreInfo = "Щит вокруг Наэтвьирра растворяется, оставляя конструкта открытым для ваших атак. "; local priorityToReplace = 1; local activeCount = 0; for i = 1,#final_battle.generators do if (final_battle.generators[i] ~= 0 and final_battle.generators[i] <= priorityToReplace) then activeCount = activeCount + 1; if (final_battle.generators[i] < priorityToReplace) then priorityToReplace = final_battle.generators[i]; end; end; end; if (activeCount > 0) then local replacementIndex = rnd(8); while (final_battle.generators[replacementIndex] ~= priorityToReplace) do replacementIndex = rnd(8); end; final_battle.generators[replacementIndex] = gen; end; elseif (gen == 0) then return "Генератор итак выведен из строя, незачем его дальше колотить. "; end; p("После нескольких сильных ударов генератор затихает. ".. moreInfo); final_battle.passturn(final_battle); end; }; fb_north = obj { nam = "north", dsc = "{На север}", act = function(s) pl.position[2] = pl.position[2] + 1; p("Вы идете на север"); final_battle.passturn(final_battle); end; }; fb_northeast = obj { nam = "northeast", dsc = "{На северо-восток}", act = function(s) pl.position[1] = pl.position[1] + 1; pl.position[2] = pl.position[2] + 1; p("Вы идете на северо-восток."); final_battle.passturn(final_battle); end; }; fb_east = obj { nam = "east", dsc = "{На восток}", act = function(s) pl.position[1] = pl.position[1] + 1; p("Вы идете на восток."); final_battle.passturn(final_battle); end; }; fb_southeast = obj { nam = "southeast", dsc = "{На юго-восток}", act = function(s) pl.position[1] = pl.position[1] + 1; pl.position[2] = pl.position[2] - 1; p("Вы идете на юго-восток."); final_battle.passturn(final_battle); end; }; fb_south = obj { nam = "south", dsc = "{На юг}", act = function(s) pl.position[2] = pl.position[2] - 1; p("Вы идете на юг."); final_battle.passturn(final_battle); end; }; fb_southwest = obj { nam = "southwest", dsc = "{На юго-запад}", act = function(s) pl.position[1] = pl.position[1] - 1; pl.position[2] = pl.position[2] - 1; p("Вы идете на юго-запад."); final_battle.passturn(final_battle); end; }; fb_west = obj { nam = "west", dsc = "{На запад}", act = function(s) pl.position[1] = pl.position[1] - 1; p("Вы идете на запад."); final_battle.passturn(final_battle); end; }; fb_northwest = obj { nam = "northwest", dsc = "{На северо-запад}", act = function(s) pl.position[1] = pl.position[1] - 1; pl.position[2] = pl.position[2] + 1; p("Вы идете на северо-запад."); final_battle.passturn(final_battle); end; };