-- Endless Dungeon -- By Tim Sandford, 2018 -- Comments to timsandford42@hotmail.com function love.run() -- Main function major, minor, revision, codename = love.getVersion() if major >= 11 then -- Colour fix for 11.0 onwards local oldSetColor = love.graphics.setColor love.graphics.setColor = function (r, g, b, a) if type(r)=="table" then r = r[1] / 255 g = r[2] / 255 b = r[3] / 255 a = (r[4] or 255) / 255 else r = r / 255 g = g / 255 b = b / 255 a = (a or 255) / 255 end oldSetColor(r,g,b,a) end end math.randomseed(os.time()) -- True randomness love.load(love.arg.parseGameArguments(arg), arg) -- load variables etc. while true do -- Main loop if love.event then -- Process events love.event.pump() for name, a,b,c,d,e,f in love.event.poll() do if name == "quit" then if not love.quit or not love.quit() then return a end end love.handlers[name](a,b,c,d,e,f) end end love.update() -- Update love.graphics.origin() -- Not sure, probably reset origin? love.graphics.clear(love.graphics.getBackgroundColor()) -- Clears the screen love.draw() -- Collect draw commands love.graphics.present() -- Present the graphics on the screen! love.timer.sleep(0.001) -- This is to lower the load on the CPU, but I could edit it :) end end function love.load(arg) io.stdout:setvbuf("no") -- Print messages immediately, allows tracing bugs if arg[#arg] == "-debug" then require("mobdebug").start() end --Zerobrane debugging love.mouse.setVisible(false) sCOMMENTARY = {"", "", "", "", "", "", "", "", "", "", "", "", ""} -- 13 lines of blank text gCOMMENTARY = 13 gGAMEMODE = "Title" -- Draw menu first gGAMEMODE_old = "Title" -- Allows press escape twice to go back gINV_MENU = 0 -- Which inventory menu are they moving within? gSPELLS_MENU = 0 -- Which spells menu are they moving within? gINV_CURSOR = 1 -- Current inventory selection gEQUIP_CURSOR = 1 -- Current equipped selection gCHAR_CURSOR = 1 -- Current character selection gSHOP_CURSOR = 1 -- Current shop cursor selection gSPELLS_CURSOR = 1 -- Current spells cursor gINV_SELECTED = 0 -- What have they selected from inventory? gEQUIP_SELECTED = 0 -- What have they selected from equipped? gSHOP_SELECTED = 0 -- What have they selected from the shop? gSPELLS_SELECTED = 0 -- What have they selected from spells? gITEM_INFO = "" -- Description of item gSCREENWIDTH = love.graphics.getWidth() -- Get screensize gSCREENHEIGHT = love.graphics.getHeight() -- Get screensize gRATIOX = gSCREENWIDTH / 800 -- Scale graphics to screen gRATIOY = gSCREENHEIGHT / 600 -- Scale graphics to screen gTIMER = love.timer.getTime() -- Use timer in love.update for speed of game gFADE = 255 -- Fade in effect gFADESPEED = 10 -- Speed of fade in effect gFPS = 60 -- Frames per second gFLASH = 255 -- flashing text transparency gFLASH_z = 10 -- speed of change for flashing text gFLASH_min = 80 -- minimum transparency of anything flashing gFLASH_max = 255 -- maximum transparency of anything flashing gSOUNDON = true -- Sounds on gMUSICON = true -- Music on gGUION = true -- Display GUI overlay gSTARTING = 0 -- Slight delay to loading map, smoother startscreen :) gTARGET_MONSTER = nil -- Target monster (displays info about them) gTARGET_TIMER = 0 -- Countdown before the information is cleared fTINY = love.graphics.newFont("fonts/font.ttf", 9) -- tiny font fSMALL = love.graphics.newFont("fonts/font.ttf", 12) -- small font fDEFAULT = love.graphics.newFont("fonts/font.ttf", 16) -- default font fHEADING = love.graphics.newFont("fonts/font.ttf", 24) -- heading font fTITLE = love.graphics.newFont("fonts/font.ttf", 40) -- title font mTITLE = love.audio.newSource("music/titlemusic.mp3", "stream") -- title music mTITLE:setLooping(true) mLEVEL = love.audio.newSource("music/gamemusic.mp3", "stream") -- game music mLEVEL:setLooping(true) mEND = love.audio.newSource("music/endmusic.mp3", "stream") -- ending music playtitlemusic() tPLAYER = {} tTEMPLATES = {} tITEMCLASS = {} tITEMS = {} tTREASURE = {} tINVENTORY = {} tEQUIPPED = {} tEQUIPSLOTS = {"Helmet", "Amulet", "Armour", "Weapon", "Shield", "Gloves", "Ring", "Boots"} tQUICKSLOT = {"Weapon", "Health Potion", "Mana Potion", 0, 0, 0, 0, 0, 0, 0} tTILES = {} tDISCOVERED = {} tROOMS = {} tCREATURES = {} tMONSTERCLASS = {} tMONSTERS = {} tTEXT = {} tPROJECTILES = {} tSHOP = {} tSPELLS = {} tSCHOOLS = {} readitems() readcreatures() readclasses() readspells() gPLAYERIMAGES = 1 while love.filesystem.getInfo("player/Player"..gPLAYERIMAGES..".png", "file") ~= nil do gPLAYERIMAGES = gPLAYERIMAGES + 1 end gPLAYERIMAGES = gPLAYERIMAGES - 1 gPLAYERIMAGE = 1 iDOWNSTAIRS = love.graphics.newImage("gui/Downstairs.png") -- Icon to go downstairs iPLUS = love.graphics.newImage("gui/Plus.png") -- Icon to show unused points iMINUS = love.graphics.newImage("gui/Minus.png") -- Icon to take away ability points iGOLD = love.graphics.newImage("items/Gold.png") -- Icon for gold coins iACTIVE = love.graphics.newImage("tiles/Trap Revealed.png") -- Image for revealed trap iDEACTIVE = love.graphics.newImage("tiles/Trap Dead.png") -- Image for dead trap gXP_AMOUNT = 50 -- Base amount of XP per kill gHEALTHGROWTH = 0.8 -- Health gained per constitution point per level gMANAGROWTH = 0.8 -- Health gained per constitution point per level gLEVEL = 1 -- Start on level 1 gMINSIZE = 20 -- Minimum size for the map gGRIDSIZE = 50 -- Defined by map level gGRIDGROWTH = 0.5 -- Rate of gridsize growth gMAXSIZE = 60 -- Maximum size for the map gCHESTS = 0.6 -- Density of chests per room gTRAPS = 0.35 -- Density of traps per room gDROPITEM = 0.4 -- Chance to drop an item gDROPPOTION = 0.1 -- Chance to drop a health/mana potion gDROPTORCH = 0.02 -- Chance to drop a torch gDROPBOOK = 0.02 -- Chance to drop a book/tome gWEALTH = 0.2 -- Amount of gold that drops gLOOT = 20 -- Value of loot that drops gFEATURE = 0.07 -- Chance a blank tile is a feature gBLUE = 0.2 -- Chance a level has a mana fountain gRED = 0.2 -- Chance a level has a health fountain gALTARS = 0.05 -- Chance a room has an altar gSWORDS = 0.05 -- Chance a room has a sword statue gCOLUMNS = 0.05 -- Chance a room is full of columns gMLEVEL = 0.9 -- Monster levels gained per level gTAX = 1.35 -- How much of an item's value does it sell for? gFLOAT_TIMER = 100 -- How long floaty text stays around for tMAIN_MENU = {"New game", "Controls", "Sounds on", "Music on", "Credits", "Quit"} -- List of menu options gMAIN_SELECT = 1 -- Current menu selection if love.filesystem.getInfo("savegame.txt", "file") ~= nil then table.insert(tMAIN_MENU, 1, "Continue from checkpoint") end end function blankplayer() local i gLEVEL = 1 tPLAYER = {} tPLAYER.MaxHealth = 10 tPLAYER.Wounds = 0 tPLAYER.MaxMana = 10 tPLAYER.UsedMana = 0 tPLAYER.Image = love.graphics.newImage("player/Player"..gPLAYERIMAGE..".png") tPLAYER.SightRange = 1.5 tPLAYER.Gold = 1 tPLAYER.STR = 6 tPLAYER.DEX = 6 tPLAYER.CON = 6 tPLAYER.INT = 6 tPLAYER.UnusedPoints = 8 tPLAYER.SpellPoints = 0 tPLAYER.Spells = {} tPLAYER.Effects = {} tPLAYER.XP = 0 tPLAYER.Level = 1 tPLAYER.Recoil = 0 tPLAYER.RecoilMax = 0 tPLAYER.FreezeCount = 0 tPLAYER.HealthCount = 0 tPLAYER.ManaCount = 0 tPLAYER.RegenCount = 0 tPLAYER.SearchCount = 0 tPLAYER.Resurrection = 0 tPLAYER.Resting = false if next(tSCHOOLS) ~= nil then for i = 1, #tSCHOOLS, 1 do table.insert(tPLAYER.Spells, 0) end end if next(tSPELLS) ~= nil then for i = 1, #tSPELLS, 1 do tPLAYER.Effects[i] = {} tPLAYER.Effects[i].Effect = "" tPLAYER.Effects[i].Active = false tPLAYER.Effects[i].Count = 0 end end tINVENTORY = {} tEQUIPPED = {} tQUICKSLOT = {"Weapon", "Health Potion", "Mana Potion", 0, 0, 0, 0, 0, 0, 0} sCOMMENTARY = {"", "", "", "", "", "", "", "", "", "", "", "", ""} -- 13 lines of blank text gCOMMENTARY = 13 addcommentary("120120120Player reset") end function startgame() createmap() createchests() createdoors() createfeatures() createmonsters() if gLEVEL%3==0 then createshop() end createtraps() generateitems() savegame() end function savegame() local i, file local s = "" if love.filesystem.getInfo("savegame.txt", "file") then love.filesystem.remove("savegame.txt") end file = love.filesystem.newFile("savegame.txt") file:open("w") file:write("**BEGIN GAME SETTINGS**\r\n") file:write("Dungeon_Level="..gLEVEL.."\r\n") file:write("**END GAME SETTINGS**\r\n") file:write("**BEGIN PLAYER STATS**\r\n") file:write("PlayerImage="..gPLAYERIMAGE.."\r\n") file:write("MaxHealth="..tPLAYER.MaxHealth.."\r\n") file:write("Wounds="..tPLAYER.Wounds.."\r\n") file:write("MaxMana="..tPLAYER.MaxMana.."\r\n") file:write("UsedMana="..tPLAYER.UsedMana.."\r\n") file:write("SightRange="..tPLAYER.SightRange.."\r\n") file:write("Gold="..tPLAYER.Gold.."\r\n") file:write("Strength="..tPLAYER.STR.."\r\n") file:write("Dexterity="..tPLAYER.DEX.."\r\n") file:write("Constitution="..tPLAYER.CON.."\r\n") file:write("Intelligence="..tPLAYER.INT.."\r\n") file:write("UnusedPoints="..tPLAYER.UnusedPoints.."\r\n") file:write("SpellPoints="..tPLAYER.SpellPoints.."\r\n") if next(tPLAYER.Spells) ~= nil then for i = 1, #tPLAYER.Spells, 1 do s = s..tostring(tPLAYER.Spells[i]) end end file:write("Schools="..s.."\r\n") file:write("XP="..tPLAYER.XP.."\r\n") file:write("Player_Level="..tPLAYER.Level.."\r\n") file:write("Resurrection="..tPLAYER.Resurrection.."\r\n") for i = 4, 10, 1 do file:write("Quick"..tostring(i%10).."="..tQUICKSLOT[i].."\r\n") end file:write("**END PLAYER STATS**\r\n") file:write("**BEGIN EQUIPPED SLOTS**\r\n") for i = 1, 8, 1 do if tEQUIPPED[i] ~= nil then file:write("Base="..tEQUIPPED[i].Base.."\r\n") if tEQUIPPED[i].AC ~= 0 then file:write("AC="..tEQUIPPED[i].AC.."\r\n") end if tEQUIPPED[i].BonusSTR ~= 0 then file:write("BonusSTR="..tEQUIPPED[i].BonusSTR.."\r\n") end if tEQUIPPED[i].BonusDEX ~= 0 then file:write("BonusDEX="..tEQUIPPED[i].BonusDEX.."\r\n") end if tEQUIPPED[i].BonusCON ~= 0 then file:write("BonusCON="..tEQUIPPED[i].BonusCON.."\r\n") end if tEQUIPPED[i].BonusINT ~= 0 then file:write("BonusINT="..tEQUIPPED[i].BonusINT.."\r\n") end if tEQUIPPED[i].Magic ~= 0 then file:write("Magic="..tEQUIPPED[i].Magic.."\r\n") end if tEQUIPPED[i].Fire ~= 0 then file:write("Fire="..tEQUIPPED[i].Fire.."\r\n") end if tEQUIPPED[i].Ice ~= 0 then file:write("Ice="..tEQUIPPED[i].Ice.."\r\n") end if tEQUIPPED[i].Vampire ~= 0 then file:write("Vampire="..tEQUIPPED[i].Vampire.."\r\n") end if tEQUIPPED[i].Poison ~= 0 then file:write("Poison="..tEQUIPPED[i].Poison.."\r\n") end if tEQUIPPED[i].Regenerate ~= 0 then file:write("Regenerate="..tEQUIPPED[i].Regenerate.."\r\n") end if tEQUIPPED[i].Sight ~= 0 then file:write("Sight="..tEQUIPPED[i].Sight.."\r\n") end file:write("**END ITEM**\r\n") end end file:write("**END EQUIPPED SLOTS**\r\n") file:write("**BEGIN INVENTORY**\r\n") if next(tINVENTORY) ~= nil then for i = 1, #tINVENTORY, 1 do if tINVENTORY[i] ~= nil then file:write("Base="..tINVENTORY[i].Base.."\r\n") if tINVENTORY[i].AC ~= 0 then file:write("AC="..tINVENTORY[i].AC.."\r\n") end if tINVENTORY[i].BonusSTR ~= 0 then file:write("BonusSTR="..tINVENTORY[i].BonusSTR.."\r\n") end if tINVENTORY[i].BonusDEX ~= 0 then file:write("BonusDEX="..tINVENTORY[i].BonusDEX.."\r\n") end if tINVENTORY[i].BonusCON ~= 0 then file:write("BonusCON="..tINVENTORY[i].BonusCON.."\r\n") end if tINVENTORY[i].BonusINT ~= 0 then file:write("BonusINT="..tINVENTORY[i].BonusINT.."\r\n") end if tINVENTORY[i].Magic ~= 0 then file:write("Magic="..tINVENTORY[i].Magic.."\r\n") end if tINVENTORY[i].Fire ~= 0 then file:write("Fire="..tINVENTORY[i].Fire.."\r\n") end if tINVENTORY[i].Ice ~= 0 then file:write("Ice="..tINVENTORY[i].Ice.."\r\n") end if tINVENTORY[i].Vampire ~= 0 then file:write("Vampire="..tINVENTORY[i].Vampire.."\r\n") end if tINVENTORY[i].Poison ~= 0 then file:write("Poison="..tINVENTORY[i].Poison.."\r\n") end if tINVENTORY[i].Regenerate ~= 0 then file:write("Regenerate="..tINVENTORY[i].Regenerate.."\r\n") end if tINVENTORY[i].Sight ~= 0 then file:write("Sight="..tINVENTORY[i].Sight.."\r\n") end file:write("**END ITEM**\r\n") end end end file:write("**END INVENTORY**\r\n") file:close() addfloatytext("Saved", tPLAYER.X, tPLAYER.Y) addcommentary("200200200The game has been saved") end function loadgame() local i, slot, base local item = {} local inventory, equipped = false, false if love.filesystem.getInfo("savegame.txt", "file") then for line in love.filesystem.lines("savegame.txt") do if string.find(line, "Dungeon_Level=") then gLEVEL = tonumber(string.sub(line, 15)) end if string.find(line, "PlayerImage=") then gPLAYERIMAGE = tonumber(string.sub(line, 13)) tPLAYER.Image = love.graphics.newImage("player/Player"..gPLAYERIMAGE..".png") end if string.find(line, "MaxHealth=") then tPLAYER.MaxHealth = tonumber(string.sub(line,11)) end if string.find(line, "Wounds=") then tPLAYER.Wounds = tonumber(string.sub(line,8)) end if string.find(line, "MaxMana=") then tPLAYER.MaxMana = tonumber(string.sub(line,9)) end if string.find(line, "UsedMana=") then tPLAYER.UsedMana = tonumber(string.sub(line,10)) end if string.find(line, "SightRange=") then tPLAYER.SightRange = tonumber(string.sub(line,12)) end if string.find(line, "Gold=") then tPLAYER.Gold = tonumber(string.sub(line,6)) end if string.find(line, "Strength=") then tPLAYER.STR = tonumber(string.sub(line,10)) end if string.find(line, "Dexterity=") then tPLAYER.DEX = tonumber(string.sub(line,11)) end if string.find(line, "Constitution=") then tPLAYER.CON = tonumber(string.sub(line,14)) end if string.find(line, "Intelligence=") then tPLAYER.INT = tonumber(string.sub(line,14)) end if string.find(line, "UnusedPoints=") then tPLAYER.UnusedPoints = tonumber(string.sub(line,14)) end if string.find(line, "SpellPoints=") then tPLAYER.SpellPoints = tonumber(string.sub(line,13)) end if string.find(line, "Schools=") then for i = 9, string.len(line), 1 do tPLAYER.Spells[i-8] = tonumber(string.sub(line,i,i)) end end if string.find(line, "XP=") then tPLAYER.XP = tonumber(string.sub(line,4)) end if string.find(line, "Player_Level=") then tPLAYER.Level = tonumber(string.sub(line,14)) end if string.find(line, "Resurrection=") then tPLAYER.Resurrection = tonumber(string.sub(line,14)) end for i = 4, 10, 1 do if string.find(line, "Quick"..tostring(i%10).."=") then tQUICKSLOT[i] = tonumber(string.sub(line,8)) end end if string.find(line, "**BEGIN EQUIPPED SLOTS**") then equipped = true end if string.find(line, "**END EQUIPPED SLOTS**") then equipped = false end if string.find(line, "**BEGIN INVENTORY**") then inventory = true end if string.find(line, "**END INVENTORY**") then inventory = false end if string.find(line, "Base=") then base = string.sub(line,6) if string.find(base, "Potion") then item = createspecialitem(base,0,0,0) elseif string.find(base, "Torch") then item = createspecialitem(base,0,0,0) elseif string.find(base, "Tome") then item = createspecialitem(base,0,0,0) elseif string.find(base, "Resurrection Stone") then item = createspecialitem(base,0,0,0) else item = getbaseitem(base) end end if string.find(line, "AC=") then item.AC = tonumber(string.sub(line,4)) end if string.find(line, "BonusSTR=") then item.BonusSTR = tonumber(string.sub(line,10)) end if string.find(line, "BonusDEX=") then item.BonusDEX = tonumber(string.sub(line,10)) end if string.find(line, "BonusCON=") then item.BonusCON = tonumber(string.sub(line,10)) end if string.find(line, "BonusINT=") then item.BonusINT = tonumber(string.sub(line,10)) end if string.find(line, "Magic=") then item.Magic = tonumber(string.sub(line,7)) end if string.find(line, "Fire=") then item.Fire = tonumber(string.sub(line,6)) end if string.find(line, "Ice=") then item.Ice = tonumber(string.sub(line,5)) end if string.find(line, "Vampire=") then item.Vampire = tonumber(string.sub(line,9)) end if string.find(line, "Poison=") then item.Poison = tonumber(string.sub(line,8)) end if string.find(line, "Regenerate=") then item.Regenerate = tonumber(string.sub(line,12)) end if string.find(line, "Sight=") then item.Sight = tonumber(string.sub(line,7)) end if string.find(line, "**END ITEM**") then if inventory == true and equipped == false then table.insert(tINVENTORY, deepcopy(item)) elseif equipped == true and inventory == false then slot = 0 for i = 1, 8, 1 do if item.Type == tEQUIPSLOTS[i] then slot = i end end if slot ~= 0 then tEQUIPPED[slot] = deepcopy(item) end else end end end end end function createmap() local i, j, k, r local d, x, y local minsize = {5, 3, 2} local maxsize = {9, 6, 4} local trylimit = 10000 local trycount, found local rm_x, rm_y, rm_width, rm_height local best_d, start_x, start_y, end_x, end_y tTILES = {} tDISCOVERED = {} tROOMS = {} tITEMS = {} tMONSTERS = {} gGRIDSIZE = math.min(gMINSIZE + math.floor(gLEVEL * gGRIDGROWTH), gMAXSIZE) repeat -- Just to double check we don't get something unsolveable for i = 1, gGRIDSIZE, 1 do -- Blank the grid as walls tTILES[i] = {} tDISCOVERED[i] = {} for j = 1, gGRIDSIZE, 1 do tTILES[i][j] = {} createtile("Wall", i, j) tDISCOVERED[i][j] = false end end for k = 1, #minsize, 1 do -- Loop and place different sized rooms, big->small repeat trycount = 0 repeat found = true trycount = trycount + 1 rm_width = math.random(minsize[k], maxsize[k]) rm_height = math.random(minsize[k], maxsize[k]) if rm_width<=gGRIDSIZE-2 and rm_height<=gGRIDSIZE-2 then rm_x = math.random(2, gGRIDSIZE-rm_width) rm_y = math.random(2, gGRIDSIZE-rm_height) for i = rm_x-1, rm_x+rm_width, 1 do for j = rm_y-1, rm_y+rm_height, 1 do if tTILES[i][j].Type ~= "Wall" then found = false end end end else found = false end until trycount > trylimit or found == true if found == true then if next(tROOMS) ~= nil then r = #tROOMS + 1 else r = 1 end tROOMS[r] = {} tROOMS[r].X = rm_x tROOMS[r].Y = rm_y tROOMS[r].Width = rm_width tROOMS[r].Height = rm_height tROOMS[r].Links = {} for i = rm_x, rm_x+rm_width-1, 1 do for j = rm_y, rm_y+rm_height-1, 1 do createtile("Blank", i, j) end end end until trycount > trylimit end found = true if next(tROOMS) ~= nil then trycount = 0 repeat -- Loop until the maze is solveable trycount = trycount + 1 r = math.random(#tROOMS) -- Choose a random room d = math.random(4) -- Choose a random direction x, y = getedgespot(r, d) -- Choose a random place on the edge of the room i, j = x, y -- Remember that start place for later repeat -- Keep going in this direction until I have reason to stop found = false if d == 1 then y = y + 1 if getroom(x-1,y) > 0 or getroom(x+1,y) > 0 then found = true end -- Adjacent to a room, no good elseif d == 2 then x = x + 1 if getroom(x,y-1) > 0 or getroom(x,y+1) > 0 then found = true end -- Adjacent to a room, no good elseif d == 3 then y = y - 1 if getroom(x-1,y) > 0 or getroom(x+1,y) > 0 then found = true end -- Adjacent to a room, no good else x = x - 1 if getroom(x,y-1) > 0 or getroom(x,y+1) > 0 then found = true end -- Adjacent to a room, no good end if getroom(x, y) > 0 then found = true end -- In a room, check it until found == true or x == 1 or x == gGRIDSIZE or y == 1 or y == gGRIDSIZE k = getroom(x, y) if k > 0 then -- I'm in a room, is it a new link between these two? found = false if next(tROOMS[r].Links) ~= nil then for x = 1, #tROOMS[r].Links, 1 do if tROOMS[r].Links[x] == k then found = true end -- Ah, we've linked these two before sorry, no good. end end if found == false then -- The room is a new link! Huzzah. Now link the two. x, y = i, j repeat if d == 1 then y = y + 1 elseif d == 2 then x = x + 1 elseif d == 3 then y = y - 1 else x = x - 1 end createtile("Blank", x, y) until getroom(x, y) == k table.insert(tROOMS[r].Links, k) table.insert(tROOMS[k].Links, r) end end found = getsolveable() until found == true or trycount > trylimit end until found == true if next(tROOMS) ~= nil then trycount = 0 best_d = 0 repeat r = math.random(#tROOMS) until (tROOMS[r].Width >= 3 and tROOMS[r].Height >= 3) or #tROOMS==1 if #tROOMS>1 then end_x = math.random(tROOMS[r].X+1, tROOMS[r].X+tROOMS[r].Width-2) end_y = math.random(tROOMS[r].Y+1, tROOMS[r].Y+tROOMS[r].Height-2) else end_x = tROOMS[r].X end_y = tROOMS[r].Y end repeat -- Choose a good start place and finish place trycount = trycount + 1 repeat r = math.random(#tROOMS) until (tROOMS[r].Width >= 3 and tROOMS[r].Height >= 3) or #tROOMS==1 if #tROOMS>1 then x = math.random(tROOMS[r].X+1, tROOMS[r].X+tROOMS[r].Width-2) y = math.random(tROOMS[r].Y+1, tROOMS[r].Y+tROOMS[r].Height-2) else x = tROOMS[r].X+tROOMS[r].Width-1 y = tROOMS[r].Y+tROOMS[r].Height-1 end d = math.floor(math.sqrt(((x-end_x)^2) + ((y-end_y)^2))+0.5) if d > best_d then start_x = x start_y = y best_d = d end until trycount > trylimit and best_d > 0 createtile("Start", start_x, start_y) tPLAYER.X = start_x tPLAYER.Y = start_y tPLAYER.VX = 0 tPLAYER.VY = 0 createtile("Finish", end_x, end_y) end addcommentary("120120120Rooms created") end function createtile(tile, i, j) local feature = {"Bone", "Dirt", "Mould", "Planks", "Skulls"} local r = math.random(100) tTILES[i][j].Type = tile tTILES[i][j].Locked = false tTILES[i][j].Image = love.graphics.newImage("tiles/"..tile..".png") tTILES[i][j].Solid = true tTILES[i][j].Flagged = false tTILES[i][j].Triggered = false if tile == "Blank" then tTILES[i][j].Solid = false if r<=(gFEATURE*100) then r = math.random(#feature) tTILES[i][j].Image = love.graphics.newImage("tiles/"..feature[r]..".png") end elseif tile == "Open Door" then tTILES[i][j].Solid = false elseif tile == "Finish" then tTILES[i][j].Solid = false elseif tile == "Column Collapsed" then tTILES[i][j].Solid = false elseif tile == "Trap" then tTILES[i][j].Solid = false else end end function getedgespot(r,d) local x, y if d == 1 then x = math.random(tROOMS[r].X, tROOMS[r].X+tROOMS[r].Width-1) y = tROOMS[r].Y+tROOMS[r].Height-1 elseif d == 2 then x = tROOMS[r].X+tROOMS[r].Width-1 y = math.random(tROOMS[r].Y, tROOMS[r].Y+tROOMS[r].Height-1) elseif d == 3 then x = math.random(tROOMS[r].X, tROOMS[r].X+tROOMS[r].Width-1) y = tROOMS[r].Y else x = tROOMS[r].X y = math.random(tROOMS[r].Y, tROOMS[r].Y+tROOMS[r].Height-1) end return x, y end function getroom(x,y) local room = 0 local i if next(tROOMS) ~= nil then for i = 1, #tROOMS, 1 do if x>=tROOMS[i].X and x<=tROOMS[i].X+tROOMS[i].Width-1 and y>=tROOMS[i].Y and y<=tROOMS[i].Y+tROOMS[i].Height-1 then room=i end end end return room end function getmonster(x,y) local m = 0 local i, j if next(tMONSTERS) ~= nil then for i = 1, #tMONSTERS, 1 do if tMONSTERS[i].X == x and tMONSTERS[i].Y == y then m = i end end end return m end function getsolveable() local i, j, r local route = {} local options local s = true if next(tROOMS) ~= nil then for i = 1, #tROOMS, 1 do -- mark all rooms unvisited tROOMS[i].visited = false end r = math.random(#tROOMS) -- choose a random room to start with repeat -- loop until there are no unvisited routes if tROOMS[r].visited == false then -- if it's first time here then mark this room as visited and add it to the route tROOMS[r].visited = true table.insert(route, r) end options = {} -- compile a list of unvisited options if next(tROOMS[r].Links) ~= nil then for i = 1, #tROOMS[r].Links, 1 do j = tROOMS[r].Links[i] if tROOMS[j].visited == false then table.insert(options, j) end end end if next(options) ~= nil then -- if there's an unvisited option then choose one i = math.random(#options) r = options[i] else -- otherwise step back in the chain table.remove(route) if next(route) ~= nil then r = route[#route] end end until next(route) == nil for i = 1, #tROOMS, 1 do -- is any room still unvisited? if tROOMS[i].visited == false then s = false end end end return s end function createchests() local i, j, r, x, y local chests, found tCHESTS = {} if next(tTILES) ~= nil and next(tROOMS) ~= nil then for chests = 1, math.ceil(#tROOMS*gCHESTS), 1 do repeat found = true r = math.random(#tROOMS) x, y = getedgespot(r, math.random(4)) if tTILES[x-1][y].Type~="Blank" and tTILES[x+1][y].Type~="Blank" and tTILES[x][y-1].Type~="Blank" and tTILES[x][y+1].Type~="Blank" then found = false end -- Must be approachable from one direction! if tTILES[x-1][y].Type~="Wall" and tTILES[x+1][y].Type~="Wall" and tTILES[x][y-1].Type~="Wall" and tTILES[x][y+1].Type~="Wall" then found = false end -- Not blocking an exit for i = -1, 1, 1 do for j = -1, 1, 1 do if tTILES[x+i][y+j].Type == "Start" or tTILES[x+i][y+j].Type == "Finish" or tTILES[x+i][y+j].Type == "Closed Chest" then found = false end -- not touching start/finish/another chest end end if x == tROOMS[r].X then if y == tROOMS[r].Y and (tTILES[x-1][y].Type~="Wall" or tTILES[x][y-1].Type~="Wall") then found = false end -- two walls in corner if y == tROOMS[r].Y+tROOMS[r].Height-1 and (tTILES[x-1][y].Type~="Wall" or tTILES[x][y+1].Type~="Wall") then found = false end -- two walls in corner elseif x == tROOMS[r].X+tROOMS[r].Width-1 then if y == tROOMS[r].Y and (tTILES[x+1][y].Type~="Wall" or tTILES[x][y-1].Type~="Wall") then found = false end -- two walls in corner if y == tROOMS[r].Y+tROOMS[r].Height-1 and (tTILES[x+1][y].Type~="Wall" or tTILES[x][y+1].Type~="Wall") then found = false end -- two walls in corner else end until found == true createtile("Closed Chest", x, y) end end addcommentary("120120120Chests added") end function createdoors() local i, x, y if next(tTILES) ~= nil and next(tROOMS) ~= nil then for i = 1, #tROOMS, 1 do for x = tROOMS[i].X, tROOMS[i].X+tROOMS[i].Width-1, 1 do y = tROOMS[i].Y-1 if tTILES[x][y].Type=="Blank" and y > 1 then if tTILES[x][y-1].Type=="Blank" then createtile("Closed Door", x, y) end end y = tROOMS[i].Y+tROOMS[i].Height if tTILES[x][y].Type=="Blank" and y < gGRIDSIZE then if tTILES[x][y+1].Type=="Blank" then createtile("Closed Door", x, y) end end end for y = tROOMS[i].Y, tROOMS[i].Y+tROOMS[i].Height-1, 1 do x = tROOMS[i].X-1 if tTILES[x][y].Type=="Blank" and x > 1 then if tTILES[x-1][y].Type=="Blank" then createtile("Closed Door", x, y) end end x = tROOMS[i].X+tROOMS[i].Width if tTILES[x][y].Type=="Blank" and x < gGRIDSIZE then if tTILES[x+1][y].Type=="Blank" then createtile("Closed Door", x, y) end end end end end end function createfeatures() local i, j, x, y, r, d local walls local trylimit = 10000 local trycount, found if next(tROOMS) ~= nil then if math.random(100)<=(gBLUE*100) then -- Mana fountain trycount = 0 repeat r = math.random(#tROOMS) trycount = trycount + 1 found = true x, y = getedgespot(r, math.random(4)) walls = 0 for i = -1, 1, 1 do for j = -1, 1, 1 do if tTILES[x+i][y+j].Type == "Wall" then walls = walls + 1 end if tTILES[x+i][y+j].Type ~= "Wall" and tTILES[x+i][y+j].Type ~= "Blank" then found = false end end end if walls ~= 3 then found = false end until found == true or trycount > trylimit if found == true then createtile("Fountain Blue", x, y) end end if math.random(100)<=(gRED*100) then -- Health fountain trycount = 0 repeat r = math.random(#tROOMS) trycount = trycount + 1 found = true x, y = getedgespot(r, math.random(4)) walls = 0 for i = -1, 1, 1 do for j = -1, 1, 1 do if tTILES[x+i][y+j].Type == "Wall" then walls = walls + 1 end if tTILES[x+i][y+j].Type ~= "Wall" and tTILES[x+i][y+j].Type ~= "Blank" then found = false end end end if walls ~= 3 then found = false end until found == true or trycount > trylimit if found == true then createtile("Fountain Red", x, y) end end for r = 1, #tROOMS, 1 do -- Altar tables if math.random(100)<=(gALTARS*100) then trycount = 0 repeat trycount = trycount + 1 found = true x, y = getedgespot(r, math.random(4)) walls = 0 for i = -1, 1, 1 do for j = -1, 1, 1 do if tTILES[x+i][y+j].Type == "Wall" then walls = walls + 1 end if tTILES[x+i][y+j].Type ~= "Wall" and tTILES[x+i][y+j].Type ~= "Blank" then found = false end end end if walls ~= 3 then found = false end until found == true or trycount > trylimit if found == true then createtile("Altar", x, y) end end end for r = 1, #tROOMS, 1 do -- Sword statues if math.random(100)<=(gSWORDS*100) then trycount = 0 repeat trycount = trycount + 1 found = true x, y = getedgespot(r, math.random(4)) walls = 0 for i = -1, 1, 1 do for j = -1, 1, 1 do if tTILES[x+i][y+j].Type == "Wall" then walls = walls + 1 end if tTILES[x+i][y+j].Type ~= "Wall" and tTILES[x+i][y+j].Type ~= "Blank" then found = false end end end if walls ~= 3 then found = false end until found == true or trycount > trylimit if found == true then createtile("Sword Statue", x, y) end end end for r = 1, #tROOMS, 1 do -- Columns if math.random(100)<=(gCOLUMNS*100) and tROOMS[r].Width >= 3 and tROOMS[r].Height >= 3 then for x = tROOMS[r].X+1, tROOMS[r].X+tROOMS[r].Width-2, 2 do for y = tROOMS[r].Y+1, tROOMS[r].Y+tROOMS[r].Height-2, 2 do found = true for i = -1, 1, 1 do for j = -1, 1, 1 do if tTILES[x+i][y+j].Type ~= "Blank" then found = false end end end if found == true then if math.random(2)==1 then createtile("Column Full", x, y) else createtile("Column Broken", x, y) end elseif tTILES[x][y].Type == "Blank" then createtile("Column Collapsed", x, y) else end end end end end end end function createmonsters() local i, l, n, r, s, t local list local start = 0 local x, y local try if next(tROOMS) ~= nil and next(tCREATURES) ~= nil then for r = 1, #tROOMS, 1 do for x = tROOMS[r].X, tROOMS[r].X+tROOMS[r].Width-1, 1 do for y = tROOMS[r].Y, tROOMS[r].Y+tROOMS[r].Height-1, 1 do if tTILES[x][y].Type=="Start" then start = r end end end end for r = 1, #tROOMS, 1 do if r ~= start then list = {} -- Blank the list of creatures s = math.floor((math.sqrt(tROOMS[r].Width * tROOMS[r].Height))+0.5) -- Size of room n = 0 if s >= 1 then -- Larger the room, more likely populated for i = 1, s, 1 do n = n + math.random(2) - 1 end end if n > 0 then repeat s = math.random(#tCREATURES) until math.ceil(gLEVEL*gMLEVEL) >= tCREATURES[s].From and math.floor(gLEVEL*gMLEVEL) <= tCREATURES[s].To -- Pick a family of creatures to spawn for i = 1, #tCREATURES, 1 do -- Make a list of other possible creatures (in the family) if tCREATURES[i].Family==tCREATURES[s].Family and math.ceil(gLEVEL*gMLEVEL)>=tCREATURES[i].From and math.floor(gLEVEL*gMLEVEL)<=tCREATURES[i].To then for t = 1, tCREATURES[i].Group, 1 do table.insert(list, i) end end end n = math.min(n, #list) for i = 1, n, 1 do t = tonumber(list[math.random(#list)]) l = math.ceil(gLEVEL*gMLEVEL) - math.random(5) l = math.max(l, 1) try = 0 repeat try = try + 1 x = math.random(tROOMS[r].X, tROOMS[r].X+tROOMS[r].Width-1) y = math.random(tROOMS[r].Y, tROOMS[r].Y+tROOMS[r].Height-1) until (tTILES[x][y].Solid == false and getmonster(x,y) == 0) or try > 1000 if try <= 1000 then spawnmonster(t, l, x, y) end end end end end end addcommentary("120120120Monsters added") end function spawnmonster(mon, level, x, y) local i, j local monster = {} if next(tCREATURES) ~= nil then monster = deepcopy(tCREATURES[mon]) monster.Image = love.graphics.newImage("monsters/"..tCREATURES[mon].Name..".png") monster.X = x monster.Y = y monster.TX = x monster.TY = y monster.Min = monster.Min + math.floor(level*monster.MinGR) monster.Max = monster.Max + math.floor(level*monster.MaxGR) monster.Life = monster.Life + math.floor(level*monster.LifeGR) monster.Armour = monster.Armour + math.floor(level*monster.ArmourGR) monster.AttackBonus = monster.AttackBonus + math.floor(level*monster.AttackGR) monster.Wounds = 0 monster.Level = level monster.MOVCount = 0 monster.ATKCount = 0 monster.Reacted = false monster.Slowed = false monster.Cursed = false monster.Feared = false if next(tMONSTERCLASS) ~= nil then j = monster.Level-tPLAYER.Level for i = 1, #tMONSTERCLASS, 1 do if j >= tMONSTERCLASS[i].Threshold then monster.Class = tMONSTERCLASS[i].Class end end end table.insert(tMONSTERS, deepcopy(monster)) end end function createshop() local try = 0 local i, r, x, y, space local item local res_stone = false if next(tINVENTORY) ~= nil then for i = 1, #tINVENTORY, 1 do if tINVENTORY[i].Name == "Resurrection Stone" then res_stone = true end end end repeat space = true try = try + 1 r = math.random(4) if r==1 then x=1 y=math.random(2,gGRIDSIZE-1) if tTILES[x+1][y].Solid==true then space=false end elseif r==2 then x=gGRIDSIZE y=math.random(2,gGRIDSIZE-1) if tTILES[x-1][y].Solid==true then space=false end elseif r==3 then x=math.random(2,gGRIDSIZE-1) y=1 if tTILES[x][y+1].Solid==true then space=false end else x=math.random(2,gGRIDSIZE-1) y=gGRIDSIZE if tTILES[x][y-1].Solid==true then space=false end end until try>=1000 or space==true if space==true then createtile("Shop",x,y) end tSHOP = {} for i = 1, 20, 1 do item = createrandomitem(0, 0) table.insert(tSHOP,deepcopy(item)) end for i = 1, math.ceil(gLEVEL/2), 1 do r = math.random(#tSHOP) addbonus(tSHOP[r]) tSHOP[r].Value = valueitem(tSHOP[r]) tSHOP[r].Name = nameitem(tSHOP[r]) end for i = 1, 6, 1 do r = math.random(2) if r==1 then item=createspecialitem("Health Potion",0,0,0) else item=createspecialitem("Mana Potion",0,0,0) end table.insert(tSHOP,deepcopy(item)) end if next(tSHOP) ~= nil then for i = #tSHOP, 1, -1 do if tSHOP[i].Value > ((gLEVEL/3)^2)*gTAX*100 then table.remove(tSHOP, i) end end end if res_stone == false then item=createspecialitem("Resurrection Stone",0,0,0) table.insert(tSHOP,deepcopy(item)) end end function createtraps() local r, x, y local traps, found, try if next(tTILES) ~= nil and next(tROOMS) ~= nil then for traps = 1, math.ceil(#tROOMS*gTRAPS), 1 do try = 0 repeat found = true try = try + 1 r = math.random(#tROOMS) x = math.random(tROOMS[r].X, tROOMS[r].X+tROOMS[r].Width-1) y = math.random(tROOMS[r].Y, tROOMS[r].Y+tROOMS[r].Height-1) if tTILES[x][y].Type ~= "Blank" then found = false end until found == true or try > 1000 createtile("Trap", x, y) end end addcommentary("120120120Traps added") end function lineofsight(a,b,c,d,source) local xf, yf = {}, {} local x, y, z = {}, {}, {} local dx, dy = {}, {} local blocked = {} local i, j, k local all_blocked, reached_goal k = 0 for i = -1, 1, 1 do for j = -1, 1, 1 do k = k + 1 x[k] = a + (i*0.45) y[k] = b + (j*0.45) x[k] = math.max(x[k],1) y[k] = math.max(y[k],1) x[k] = math.min(x[k],gGRIDSIZE) y[k] = math.min(y[k],gGRIDSIZE) z[k] = math.sqrt(((c-x[k])^2)+((d-y[k])^2)) xf[k] = x[k] yf[k] = y[k] if z[k] ~= 0 then dx[k] = (c-x[k])/z[k] else dx[k] = 0 end if z[k] ~= 0 then dy[k] = (d-y[k])/z[k] else dy[k] = 0 end blocked[k] = false end end if next(tTILES) ~= nil then reached_goal = false repeat all_blocked = true for k = 1, 9, 1 do xf[k] = xf[k] + dx[k] yf[k] = yf[k] + dy[k] x[k] = math.floor(xf[k]+0.5) y[k] = math.floor(yf[k]+0.5) if x[k] == c and y[k] == d and blocked[k] == false then reached_goal = true end if withingrid(x[k],y[k]) then if tTILES[x[k]][y[k]].Type=="Wall" or tTILES[x[k]][y[k]].Type=="Closed Door" then blocked[k] = true end end if blocked[k] == false then all_blocked = false end end until all_blocked == true or reached_goal == true end if reached_goal == true then if source == "Player" then tDISCOVERED[a][b] = true if tPLAYER.SearchCount <= 0 then -- Look for a trap if tTILES[a][b].Type == "Trap" and tTILES[a][b].Triggered == false and tTILES[a][b].Flagged == false then i = math.random(20) j = math.floor((getint()-10)/2) if i+j >= math.floor(gLEVEL/4)+10 then tTILES[a][b].Image = iACTIVE tTILES[a][b].Flagged = true addcommentary("120120120Trap detected") end tPLAYER.SearchCount = gFPS end end end return true else return false end end function love.update() local i updategeneral() if gGAMEMODE == "Playing" then updateplaying() updateprojectiles() updatemonsters() end end function updategeneral() if gFADE > 0 then -- fade in graphics gFADE = gFADE - gFADESPEED if gFADE < 0 then gFADE = 0 end end if gGAMEMODE ~= "Paused" then gFLASH = gFLASH + gFLASH_z end -- flash counter if gFLASH > 255 then -- this affects everything that flashes (same speed) gFLASH = gFLASH_max gFLASH_z = 0 - gFLASH_z elseif gFLASH < gFLASH_min then gFLASH = gFLASH_min gFLASH_z = 0 - gFLASH_z else end if gSTARTING > 0 then gSTARTING = gSTARTING - 1 if gSTARTING == 0 then startgame() end end repeat until love.timer.getTime() - gTIMER > (1/gFPS) -- frame rate gTIMER = love.timer.getTime() -- new timer end function updateplaying() local i, r, d local x, y = tPLAYER.X, tPLAYER.Y local res_stone = false gCAMERA_X = tPLAYER.X gCAMERA_Y = tPLAYER.Y if next(tTEXT) ~= nil then -- Floaty text i = 0 repeat i = i + 1 tTEXT[i].Timer = tTEXT[i].Timer - 1 until tTEXT[i].Timer >= gFLOAT_TIMER - 20 or i == #tTEXT for i = #tTEXT, 1, -1 do if tTEXT[i].Timer <= 0 then table.remove(tTEXT, i) end end end if tPLAYER.Recoil > 0 then tPLAYER.Recoil = tPLAYER.Recoil - 1 end -- Decrease player attack timer if gTARGET_TIMER > 0 then -- Decrease target monster timer gTARGET_TIMER = gTARGET_TIMER - 1 if gTARGET_TIMER == 0 then gTARGET_MONSTER = nil end end if tPLAYER.XP >= (tPLAYER.Level*(tPLAYER.Level+1))*500 then levelup() end -- Level up if tPLAYER.HealthCount > 0 then tPLAYER.HealthCount = tPLAYER.HealthCount - 1 end -- Health recovery countdown if tPLAYER.HealthCount == 0 and tPLAYER.Wounds > 0 then -- Health recovery happens tPLAYER.HealthCount = gethealthcount() tPLAYER.Wounds = tPLAYER.Wounds - 1 addcommentary("000255000You recover 1 health.") end if tPLAYER.ManaCount > 0 then tPLAYER.ManaCount = tPLAYER.ManaCount - 1 end -- Mana recovery countdown if tPLAYER.ManaCount == 0 and tPLAYER.UsedMana > 0 then -- Mana recovery happens tPLAYER.ManaCount = getmanacount() tPLAYER.UsedMana = tPLAYER.UsedMana - 1 addcommentary("000075125You recover 1 mana.") end if tPLAYER.RegenCount > 0 then -- Regenerate countdown happens tPLAYER.RegenCount = tPLAYER.RegenCount - 1 if tPLAYER.RegenCount == 0 then if tPLAYER.Wounds > 0 then tPLAYER.Wounds = PLAYER.Wounds - 1 addcommentary("000255000Regenerated 1 health") end j = getregen() if j > 0 then tPLAYER.RegenCount = math.ceil((10 * gFPS) / j) end end end if next(tPLAYER.Effects) ~= nil then -- Effect counters for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Count > 0 then tPLAYER.Effects[i].Count = tPLAYER.Effects[i].Count - 1 if tPLAYER.Effects[i].Count == 0 then tPLAYER.Effects[i].Active = false if tPLAYER.Effects[i].Name == "Slow" then if next(tMONSTERS) ~= nil then for r = 1, #tMONSTERS, 1 do if tMONSTERS[r].Slowed == true then tMONSTERS[r].Slowed = false tMONSTERS[r].MOVSpeed = tMONSTERS[r].MOVSpeed / 2 tMONSTERS[r].ATKSpeed = tMONSTERS[r].ATKSpeed / 2 end end end elseif tPLAYER.Effects[i].Name == "Curse" then if next(tMONSTERS) ~= nil then for r = 1, #tMONSTERS, 1 do tMONSTERS[r].Cursed = false end end else end end end end end if tPLAYER.FreezeCount > 0 then tPLAYER.FreezeCount = tPLAYER.FreezeCount - 1 end if tPLAYER.SearchCount > 0 then tPLAYER.SearchCount = tPLAYER.SearchCount - 1 end -- Search for traps countdown if gethealth() <= 0 then -- Player death addcommentary("255000000You have died") gCOMMENTARY = #sCOMMENTARY if next(tINVENTORY) ~= nil then for i = #tINVENTORY, 1, -1 do if tINVENTORY[i].Name == "Resurrection Stone" then res_stone = true table.remove(tINVENTORY, i) addcommentary("120120120Resurrection Stone lost") end end end if res_stone == true then tPLAYER.Wounds = 0 addcommentary("120120120You lost "..tostring(tPLAYER.XP - (((tPLAYER.Level-1)*(tPLAYER.Level))*500)).." XP") tPLAYER.XP = ((tPLAYER.Level-1)*(tPLAYER.Level))*500 savegame() addcommentary("000255000You were resurrected back to life!") for x = 1, gGRIDSIZE, 1 do for y = 1, gGRIDSIZE, 1 do if tTILES[x][y].Type == "Start" then tPLAYER.X = x tPLAYER.Y = y end end end addfloatytext("Resurrected", tPLAYER.X, tPLAYER.Y) else gGAMEMODE = "End Game" playendmusic() if love.filesystem.getInfo("savegame.txt", "file") then love.filesystem.remove("savegame.txt") end end end end function explodefireball(x,y,level) local a, b for a = x-1, x+1, 1 do for b = y-1, y+1, 1 do if withingrid(a,b) and not (a~=x and b~=y) then createprojectile("Fireball",getdiceroll(level,10),a,b,0,0,"Neutral",1) end end end end function spawnmeteor(r) local x, y x = math.random(tROOMS[r].X, tROOMS[r].X+tROOMS[r].Width-1) y = math.random(tROOMS[r].Y, tROOMS[r].Y+tROOMS[r].Height-1) createprojectile("Meteor", math.random(20,50), x, y, 0, 0, "Player", 1) end function hitprojectile(p, i) local x,y = p.X, p.Y local r = getroom(x,y) local m = getmonster(x,y) local src = p.Source local remove, reflect, frozen = false, false, false local j, file if next(tPLAYER.Effects) ~= nil then for j = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[j].Name == "Frozen Arrow" and tPLAYER.Effects[j].Active == true then frozen = true end if tPLAYER.Effects[j].Name == "Reflect Missiles" and tPLAYER.Effects[j].Active == true then reflect = true end end end if p.Type=="Fireball" and (tTILES[x][y].Solid==true or m>0) and (src=="Player" or src=="Monster") then if src=="Player" then explodefireball(x,y,math.min(tPLAYER.Level,6)) elseif src=="Monster" then explodefireball(x,y,math.ceil(m.DMG/5)) else end end if tTILES[x][y].Solid==true and p.Type ~= "Meteor" then remove = true elseif m > 0 and (src=="Player" or src=="Neutral") and p.Type~="Bomb" and p.Hit == false then if p.Type=="Meteor" then spawnmeteor(r) end if src=="Player" then gTARGET_MONSTER=deepcopy(tMONSTERS[m]) gTARGET_TIMER = 400 end damagemonster(m, p.DMG, p.DMGTYPE) if frozen == true then damagemonster(m, getdiceroll(2,5), "Ice") end if p.Type == "Lightning" then p.Hit = true else remove = true end elseif x==tPLAYER.X and y==tPLAYER.Y and (src=="Monster" or src=="Neutral") and p.Type~="Bomb" then if reflect == true and p.Hit == false and (p.VX~=0 or p.VY~=0) then tPROJECTILES[i].VX = -tPROJECTILES[i].VX tPROJECTILES[i].VY = -tPROJECTILES[i].VY tPROJECTILES[i].Dist = 5 tPROJECTILES[i].Count = tPROJECTILES[i].Speed tPROJECTILES[i].Source = "Player" tPROJECTILES[i].Hit = true if tPROJECTILES[i].VX==0 and tPROJECTILES[i].VY==1 then file="projectiles/"..tPROJECTILES[i].Type.."3.png" elseif tPROJECTILES[i].VX==1 and tPROJECTILES[i].VY==0 then file="projectiles/"..tPROJECTILES[i].Type.."2.png" elseif tPROJECTILES[i].VX==0 and tPROJECTILES[i].VY==-1 then file="projectiles/"..tPROJECTILES[i].Type.."1.png" elseif tPROJECTILES[i].VX==-1 and tPROJECTILES[i].VY==0 then file="projectiles/"..tPROJECTILES[i].Type.."4.png" else end if love.filesystem.getInfo(file, "file") then tPROJECTILES[i].Image=love.graphics.newImage(file) else tPROJECTILES[i].Image=iPLUS end else damageplayer(p.DMG, p.DMGTYPE) remove = true end else end if remove == true then table.remove(tPROJECTILES, i) end return remove end function updateprojectiles() local i, j, m, src local x, y, a, b if next(tPROJECTILES) ~= nil then for i = #tPROJECTILES, 1, -1 do if hitprojectile(tPROJECTILES[i], i) ~= true then tPROJECTILES[i].Count = tPROJECTILES[i].Count - 1 if tPROJECTILES[i].Count <= 0 then tPROJECTILES[i].X = tPROJECTILES[i].X + tPROJECTILES[i].VX tPROJECTILES[i].Y = tPROJECTILES[i].Y + tPROJECTILES[i].VY tPROJECTILES[i].Count = tPROJECTILES[i].Speed tPROJECTILES[i].Dist = tPROJECTILES[i].Dist - 1 tPROJECTILES[i].Hit = false end if tPROJECTILES[i].Dist <= 0 then if tPROJECTILES[i].Type=="Fireball" and (tPROJECTILES[i].Source=="Player" or tPROJECTILES[i].Source=="Monster") then if tPROJECTILES[i].Source=="Player" then explodefireball(tPROJECTILES[i].X,tPROJECTILES[i].Y,math.min(tPLAYER.Level,6)) elseif tPROJECTILES[i].Source=="Monster" then explodefireball(tPROJECTILES[i].X,tPROJECTILES[i].Y,math.ceil(tPROJECTILES[i].DMG/5)) else end elseif tPROJECTILES[i].Type == "Meteor" then if next(tPLAYER.Effects) ~= nil then for j = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[j].Name == "Meteor Shower" and tPLAYER.Effects[j].Active == true then r = getroom(tPROJECTILES[i].X,tPROJECTILES[i].Y) spawnmeteor(r) end end end elseif tPROJECTILES[i].Type == "Bomb" then explodefireball(tPROJECTILES[i].X, tPROJECTILES[i].Y, math.min(tPLAYER.Level, 10)) else end table.remove(tPROJECTILES, i) elseif tPROJECTILES[i].VX ~= 0 or tPROJECTILES[i].VY ~= 0 then hitprojectile(tPROJECTILES[i], i) else end end end end end function updatemonsters() local d, i, j, r local x, y, tx, ty local px, py = tPLAYER.X, tPLAYER.Y local moved, dmg, roll, hit, att local inv = false if next(tPLAYER.Effects) ~= nil then -- Is the player invisible? for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Hide in Shadows" and tPLAYER.Effects[i].Active == true then inv = true end end end if next(tMONSTERS) ~= nil then for i = #tMONSTERS, 1, -1 do if tMONSTERS[i].MOVCount > 0 then tMONSTERS[i].MOVCount = tMONSTERS[i].MOVCount - 1 end -- Countdown MOV timer if tMONSTERS[i].ATKCount > 0 then tMONSTERS[i].ATKCount = tMONSTERS[i].ATKCount - 1 end -- Countdown ATK timer x, y = tMONSTERS[i].X, tMONSTERS[i].Y d = distancebetween(x, y, px, py) dmg = math.random(tMONSTERS[i].Min, tMONSTERS[i].Max) if tMONSTERS[i].Cursed == true then dmg = dmg - 3 end dmg = math.max(dmg, 0) moved = false if tMONSTERS[i].ATKCount == 0 and inv == false then -- Attack if I can! if tMONSTERS[i].Ranged == true and tMONSTERS[i].Ammo ~= "None" then -- Ranged attack if (x==px or y==py) and d<=tMONSTERS[i].Earshot and lineofsight(px,py,x,y,"Monster")==true then -- I'm inline.. attack? if tMONSTERS[i].Reacted==false then -- unless I've not reacted yet tMONSTERS[i].Reacted=true tMONSTERS[i].ATKCount = math.random(15,tMONSTERS[i].ATKSpeed) tMONSTERS[i].MOVCount = math.random(15,tMONSTERS[i].MOVSpeed) else -- yes, fire! addcommentary("150000000"..tMONSTERS[i].Class.." "..tMONSTERS[i].Name.." attacks you") if xpx and y==py then createprojectile(tMONSTERS[i].Ammo,dmg,x,y,-1,0,"Monster",tMONSTERS[i].Earshot) elseif x==px and ypy then createprojectile(tMONSTERS[i].Ammo,dmg,x,y,0,-1,"Monster",tMONSTERS[i].Earshot) else end if tMONSTERS[i].Special ~= "None" then -- do I have a special attack? j = math.random(100) if j <= tMONSTERS[i].SpecialCH then specialattack(tMONSTERS[i].Special, i) end end tMONSTERS[i].ATKCount = tMONSTERS[i].ATKSpeed end moved = true end else -- Melee attack if (x+1==px and y==py) or (x-1==px and y==py) or (x==px and y+1==py) or (x==px and y-1==py) then -- Am I next door? addcommentary("150000000"..tMONSTERS[i].Class.." "..tMONSTERS[i].Name.." attacks you") roll = math.random(20) att = tMONSTERS[i].AttackBonus if tMONSTERS[i].Cursed == true then att = att - 3 end if roll == 20 then hit = 2 addcommentary("150000000"..roll.." + "..att.." = *CRITICAL HIT*") elseif roll == 1 then hit = 0 addcommentary("150000000"..roll.." + "..att.." = *CRITICAL MISS*") elseif roll + att > getarmour() then hit = 1 addcommentary("150000000"..roll.." + "..att.." = *HIT*") else hit = 0 addcommentary("150000000"..roll.." + "..att.." = *MISS*") end if hit >= 1 then -- Was it a successful attack? damageplayer(dmg*hit, tMONSTERS[i].DMGType) if tMONSTERS[i].Special ~= "None" then -- Call special attack only on hit? j = math.random(100) if j <= tMONSTERS[i].SpecialCH then specialattack(tMONSTERS[i].Special, i, dmg*hit) end end else if next(tPLAYER.Effects) ~= nil and tEQUIPPED[5] ~= nil then for j = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[j].Name=="Shock" and tPLAYER.Effects[j].Active==true and (string.find(tEQUIPPED[5].Name,"Shield") or string.find(tEQUIPPED[5].Name,"Buckler")) then damagemonster(i, getdiceroll(5,3), "Magic") end end end end tMONSTERS[i].ATKCount = tMONSTERS[i].ATKSpeed moved = true end end end if tMONSTERS[i].MOVCount == 0 and moved == false and inv == false then -- If I didn't attack, I can move if tMONSTERS[i].Ranged == false and tMONSTERS[i].Feared == false then -- This is melee behaviour if d<=tMONSTERS[i].Earshot then -- Player in earshot, my new target tMONSTERS[i].TX = px tMONSTERS[i].TY = py if (x+1==px and y==py) or (x-1==px and y==py) or (x==px and y+1==py) or (x==px and y-1==py) then -- If I'm nextdoor to player, stay put tMONSTERS[i].TX = x tMONSTERS[i].TY = y end if tMONSTERS[i].Reacted == false then -- First time I've seen the player? tMONSTERS[i].ATKCount = tMONSTERS[i].ATKSpeed tMONSTERS[i].MOVCount = tMONSTERS[i].MOVSpeed tMONSTERS[i].Reacted = true moved = true end end tx = tMONSTERS[i].TX -- Shorthand tx ty = tMONSTERS[i].TY -- Shorthand ty if x~=tx or y~=ty and moved==false then -- Not at my target, go towards it? r = math.random(2) -- 1=x-direction, 2=y-direction if r==1 then -- x-direction moves if xtx and getfree(x-1,y)==true then monstermove(i,x-1,y) -- good move left elseif xtx and y==ty and getfree(x-1,y)==false then -- blocked left but but inline vertically r = math.random(2) -- could go upwards or downwards? if r==1 and getfree(x,y+1)==true then monstermove(i,x,y+1) -- move upwards around elseif r==2 and getfree(x,y-1)==true then monstermove(i,x,y-1) -- move downwards around else end elseif xty and getfree(x+1,y)==false and getfree(x,y-1)==false then -- blocked both right and down if getfree(x-1,y)==true then monstermove(i,x-1,y) end elseif x>tx and ytx and y>ty and getfree(x-1,y)==false and getfree(x,y-1)==false then -- blocked both left and down if getfree(x+1,y)==true then monstermove(i,x+1,y) end else end else -- y-direction moves if yty and getfree(x,y-1)==true then monstermove(i,x,y-1) -- good move down elseif x==tx and yty and getfree(x,y-1)==false then -- blocked downwards but inline horizontally r = math.random(2) -- could go right or left if r==1 and getfree(x+1,y)==true then monstermove(i,x+1,y) -- move right elseif r==2 and getfree(x-1,y)==true then monstermove(i,x-1,y) -- move left else end elseif xty and getfree(x+1,y)==false and getfree(x,y-1)==false then -- blocked both right and down if getfree(x,y+1)==true then monstermove(i,x,y+1) end elseif x>tx and ytx and y>ty and getfree(x-1,y)==false and getfree(x,y-1)==false then -- blocked both left and down if getfree(x,y+1)==true then monstermove(i,x,y+1) end else end end elseif moved==false then -- Random move if already at target but not in earshot if d>tMONSTERS[i].Earshot then tMONSTERS[i].Reacted = false r = math.random(4) if r==1 and getfree(x+1,y) then monstermove(i,x+1,y) elseif r==2 and getfree(x-1,y) then monstermove(i,x-1,y) elseif r==3 and getfree(x,y+1) then monstermove(i,x,y+1) elseif r==4 and getfree(x,y-1) then monstermove(i,x,y-1) else end end else end else -- This is ranged behaviour if d < 2.5 then -- Try to run away if I'm close r = math.random(2) if r==1 and xpx and getfree(x+1,y) then monstermove(i,x+1,y) elseif r==2 and ypy and getfree(x,y+1) then monstermove(i,x,y+1) else end elseif d > 3 and d <= tMONSTERS[i].Earshot then -- Try to get inline if I'm within earshot if math.abs(x-px) > math.abs(y-py) then -- y is closer inline? if ypy and getfree(x,y-1) then monstermove(i,x,y-1) else end elseif math.abs(x-px) < math.abs(y-py) then -- x is closer inline? if xpx and getfree(x-1,y) then monstermove(i,x-1,y) else end else -- it's equal so choose at random r = math.random(2) if r==1 and xpx and getfree(x+1,y) then monstermove(i,x+1,y) elseif r==2 and ypy and getfree(x,y+1) then monstermove(i,x,y+1) else end end else -- Make a random move if further away tMONSTERS[i].Reacted = false r = math.random(4) if r==1 and getfree(x+1,y) then monstermove(i,x+1,y) elseif r==2 and getfree(x-1,y) then monstermove(i,x-1,y) elseif r==3 and getfree(x,y+1) then monstermove(i,x,y+1) elseif r==4 and getfree(x,y-1) then monstermove(i,x,y-1) elseif r==1 and tTILES[x+1][y].Type=="Closed Door" and tTILES[x+1][y].Locked==false then opendoor(i,x+1,y) elseif r==2 and tTILES[x-1][y].Type=="Closed Door" and tTILES[x-1][y].Locked==false then opendoor(i,x-1,y) elseif r==3 and tTILES[x][y+1].Type=="Closed Door" and tTILES[x][y+1].Locked==false then opendoor(i,x,y+1) elseif r==4 and tTILES[x][y-1].Type=="Closed Door" and tTILES[x][y-1].Locked==false then opendoor(i,x,y-1) else end end end end if tMONSTERS[i].Wounds >= tMONSTERS[i].Life then -- Remove dead monsters addfloatytext("Dead", tMONSTERS[i].X, tMONSTERS[i].Y) addcommentary("150000000"..tMONSTERS[i].Class.." "..tMONSTERS[i].Name.." is dead") awardxp(tMONSTERS[i].Level) table.remove(tMONSTERS, i) end end end end function monstermove(m,x,y) if tTILES[x][y].Type=="Closed Door" then createtile("Open Door", x, y) tMONSTERS[m].Reacted = false end tMONSTERS[m].X = x tMONSTERS[m].Y = y tMONSTERS[m].MOVCount = tMONSTERS[m].MOVSpeed end function getfree(x,y) if withingrid(x,y)==false then return false elseif getmonster(x,y)~=0 then return false elseif ((tPLAYER.X==x)and(tPLAYER.Y==y)) then return false elseif tTILES[x][y].Solid==true and (tTILES[x][y].Type~="Closed Door" or tTILES[x][y].Locked==true) then return false else return true end end function love.draw() love.graphics.scale(gRATIOX, gRATIOY) if gGAMEMODE == "Title" then drawmenu("Endless Dungeon", tMAIN_MENU, 200, 60, 400, 480, 10, gMAIN_SELECT) elseif gGAMEMODE == "Choose Appearance" then drawchooseappearance() elseif gGAMEMODE == "Startscreen" then drawmenu("Level "..gLEVEL, {"Press Any Key"}, 200, 100, 400, 400, 10, 1) elseif gGAMEMODE == "Playing" or gGAMEMODE == "Paused" or gGAMEMODE == "End Game" then if gGAMEMODE ~= "Playing" or tPLAYER.Resting ~= true then drawmap() drawgui() end drawheader() elseif gGAMEMODE == "Inventory" then drawinventory() elseif gGAMEMODE == "Character" then drawcharacter() elseif gGAMEMODE == "Shop" then drawshop() elseif gGAMEMODE == "Spells" then drawspells() elseif gGAMEMODE == "Credits" then drawcredits() elseif gGAMEMODE == "Controls" then drawcontrols() else end if gGAMEMODE == "Paused" then love.graphics.setColor(0, 0, 0, 100) love.graphics.rectangle("fill", 0, 0, 800, 600) love.graphics.setColor(255, 215, 0, 255) love.graphics.setFont(fTITLE) love.graphics.printf("Paused", 200, 250, 400, "center") elseif tPLAYER.Resting == true then love.graphics.setColor(255, 215, 0, 255) love.graphics.setFont(fTITLE) love.graphics.printf("You are Resting", 200, 250, 400, "center") elseif gGAMEMODE == "End Game" then drawend() else end if gFADE > 0 then love.graphics.setColor(0, 0, 0, gFADE) love.graphics.rectangle("fill", 0, 0, 800, 600) else end end function drawchooseappearance() love.graphics.setColor(255, 255, 255, 255) love.graphics.draw(tPLAYER.Image, 352, 202, 0, 2, 2) drawmenu("Choose Appearance", {"", "", "Next", "Confirm", "Exit"}, 200, 100, 400, 400, 10, gAPP_SELECT) end function drawmenu(title, list, x, y, width, height, border, selection) local i, n local a = fTITLE:getHeight() local b = fHEADING:getHeight() love.graphics.setFont(fTITLE) love.graphics.setColor(200, 200, 200, 255) love.graphics.printf(title, x+border, y+border, width-(2*border), "center") love.graphics.setFont(fHEADING) if next(list) ~= nil then n = #list + 1 for i = 1, #list, 1 do if i == selection then love.graphics.setColor(255, 255, 255, gFLASH) else love.graphics.setColor(200, 200, 200, 255) end love.graphics.printf(tostring(list[i]), x+border, y+(3*border)+a+((i/n)*(height-(4*border)-a))-(b/2), width-(2*border), "center") end end end function drawmap() local inv = false local i, j if next(tPLAYER.Effects) ~= nil then -- Check for invisibility for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Hide in Shadows" and tPLAYER.Effects[i].Active == true then inv = true end end end if next(tTILES) ~= nil then -- TILES for i = gCAMERA_X-7, gCAMERA_X+7, 1 do for j = gCAMERA_Y-5, gCAMERA_Y+5, 1 do if withingrid(i,j) and withingrid(tPLAYER.X,tPLAYER.Y) then if distancebetween(tPLAYER.X,tPLAYER.Y,i,j) <= getsight() and lineofsight(i,j,tPLAYER.X,tPLAYER.Y,"Player") == true then drawobject(tTILES[i][j], i, j, true) elseif tDISCOVERED[i][j] == true then drawobject(tTILES[i][j], i, j, false) else end end end y = 0 end end if next(tITEMS) ~= nil then -- ITEMS for i = 1, #tITEMS, 1 do if withingrid(tITEMS[i].X,tITEMS[i].Y) and withingrid(tPLAYER.X,tPLAYER.Y) then if distancebetween(tPLAYER.X,tPLAYER.Y,tITEMS[i].X,tITEMS[i].Y) <= getsight() and lineofsight(tITEMS[i].X,tITEMS[i].Y,tPLAYER.X,tPLAYER.Y,"Player") == true then drawobject(tITEMS[i], tITEMS[i].X, tITEMS[i].Y, true) end end end end if next(tMONSTERS) ~= nil then -- MONSTERS for i = 1, #tMONSTERS, 1 do if withingrid(tMONSTERS[i].X,tMONSTERS[i].Y) and withingrid(tPLAYER.X,tPLAYER.Y) then if distancebetween(tPLAYER.X,tPLAYER.Y,tMONSTERS[i].X,tMONSTERS[i].Y) <= getsight() and lineofsight(tMONSTERS[i].X,tMONSTERS[i].Y,tPLAYER.X,tPLAYER.Y,"Player") == true then drawobject(tMONSTERS[i], tMONSTERS[i].X, tMONSTERS[i].Y, true) drawhealthbar(tMONSTERS[i], tMONSTERS[i].X, tMONSTERS[i].Y) if tMONSTERS[i].ATKCount > 0 then love.graphics.setColor(200, 200, 200, 255) love.graphics.rectangle("line",((tMONSTERS[i].X-gCAMERA_X)*48)+376,((tMONSTERS[i].Y-gCAMERA_Y)*48)+320,48,4) love.graphics.setColor(255, 215, 0, 255) love.graphics.rectangle("fill",((tMONSTERS[i].X-gCAMERA_X)*48)+376,((tMONSTERS[i].Y-gCAMERA_Y)*48)+321,(math.min(tMONSTERS[i].ATKCount,tMONSTERS[i].ATKSpeed)/tMONSTERS[i].ATKSpeed)*48,2) end end end end end if withingrid(tPLAYER.X, tPLAYER.Y) then -- PLAYER if inv == false then drawobject(tPLAYER, tPLAYER.X, tPLAYER.Y, true) else drawobject(tPLAYER, tPLAYER.X, tPLAYER.Y, false) end if tPLAYER.Recoil > 0 then love.graphics.setColor(200, 200, 200, 255) love.graphics.rectangle("line",((tPLAYER.X-gCAMERA_X)*48)+376,((tPLAYER.Y-gCAMERA_Y)*48)+320,48,4) love.graphics.setColor(255, 215, 0, 255) love.graphics.rectangle("fill",((tPLAYER.X-gCAMERA_X)*48)+376,((tPLAYER.Y-gCAMERA_Y)*48)+321,(math.min(tPLAYER.Recoil,tPLAYER.RecoilMax)/tPLAYER.RecoilMax)*48,2) end end if next(tPROJECTILES) ~= nil then -- PROJECTILES for i = 1, #tPROJECTILES, 1 do if withingrid(tPROJECTILES[i].X,tPROJECTILES[i].Y) and withingrid(tPLAYER.X,tPLAYER.Y) then if distancebetween(tPLAYER.X,tPLAYER.Y,tPROJECTILES[i].X,tPROJECTILES[i].Y) <= getsight() and lineofsight(tPROJECTILES[i].X,tPROJECTILES[i].Y,tPLAYER.X,tPLAYER.Y,"Player") == true then drawobject(tPROJECTILES[i], tPROJECTILES[i].X, tPROJECTILES[i].Y, true) end end end end end function drawhealthbar(monster, x, y) local w = monster.Wounds local h = monster.Life local p = (h-w)/h love.graphics.setColor(0, 0, 0, 255) love.graphics.rectangle("fill", ((x-gCAMERA_X)*48)+381, ((y-gCAMERA_Y)*48)+275, 38, 6) if p > 0.85 then love.graphics.setColor(0, 255, 0, 255) elseif p>0.65 and p<=0.85 then love.graphics.setColor(255, 255, 0, 255) elseif p>0.45 and p<=0.65 then love.graphics.setColor(255, 165, 0, 255) elseif p>0.25 and p<=0.45 then love.graphics.setColor(255, 0, 0, 255) else love.graphics.setColor(125, 0, 0, 255) end love.graphics.rectangle("fill", ((x-gCAMERA_X)*48)+382, ((y-gCAMERA_Y)*48)+276, p*36, 4) end function drawobject(object, x, y, seen) if seen == true then love.graphics.setColor(255, 255, 255, 255) else love.graphics.setColor(90, 90, 90, 255) end love.graphics.draw(object.Image, ((x-gCAMERA_X)*48)+376, ((y-gCAMERA_Y)*48)+276) end function drawgui() if next(tTILES) ~= nil then -- Finish icon (moving) if tTILES[tPLAYER.X][tPLAYER.Y].Type == "Finish" then love.graphics.setColor(255, 255, 255, 255) love.graphics.draw(iDOWNSTAIRS, ((tPLAYER.X-gCAMERA_X)*48)+376, ((tPLAYER.Y-gCAMERA_Y)*48)+238-(((gFLASH-gFLASH_min)/(gFLASH_max-gFLASH_min))*4)) end end if tPLAYER.UnusedPoints > 0 then -- Level up abilities icon love.graphics.setColor(255, 255, 255, gFLASH) love.graphics.draw(iPLUS, 2, 40) love.graphics.setFont(fSMALL) love.graphics.setColor(255, 255, 255, 255) love.graphics.printf("Press C to add Ability Points", 2, 90, 80, "left") end if gGUION == true then drawquickslots() end if gTARGET_MONSTER ~= nil then drawtargetmonster() end drawgrounditems() drawfloatytext() if gGUION == true then drawcommentary() end end function drawheader() local h = gethealth() local t = getmaxhealth() local m = getmana() love.graphics.setFont(fHEADING) love.graphics.setColor(255, 215, 0, 255) love.graphics.printf("Level "..gLEVEL, 340, 3, 120, "center") love.graphics.setColor(255, 0, 0, 255) love.graphics.printf("Health", 20, 3, 100, "center") love.graphics.rectangle("line", 120, 10, 200, 16) if h > 0 then love.graphics.rectangle("fill", 122, 12, (h/t)*196, 12) end love.graphics.setColor(0, 150, 255, 255) love.graphics.printf("Mana", 680, 3, 100, "center") love.graphics.rectangle("line", 480, 10, 200, 16) if m > 0 then love.graphics.rectangle("fill", 678-((m/tPLAYER.MaxMana)*196), 12, (m/tPLAYER.MaxMana)*196, 12) end end function drawquickslots() local i, j local s,t,r,g,b love.graphics.setFont(fDEFAULT) if tEQUIPPED[4] ~= nil then love.graphics.setColor(255,215,0,255) love.graphics.rectangle("line", 2, 550, 76, 50) love.graphics.printf("1", 0, 550, 76, "right") love.graphics.setColor(255,255,255,255) love.graphics.draw(tEQUIPPED[4].Image, 16, 551) end i = getinvitem("Health Potion") if i > 0 then love.graphics.setColor(255,215,0,255) love.graphics.rectangle("line", 82, 550, 76, 50) love.graphics.printf("2", 80, 550, 76, "right") love.graphics.setColor(255,255,255,255) love.graphics.draw(tINVENTORY[i].Image, 96, 551) end i = getinvitem("Mana Potion") if i > 0 then love.graphics.setColor(255,215,0,255) love.graphics.rectangle("line", 162, 550, 76, 50) love.graphics.printf("3", 160, 550, 76, "right") love.graphics.setColor(255,255,255,255) love.graphics.draw(tINVENTORY[i].Image, 176, 551) end for i = 4, 10, 1 do j = tQUICKSLOT[i] if j > 0 then love.graphics.setColor(255,215,0,255) love.graphics.rectangle("line", (i*80)-78, 550, 76, 50) love.graphics.printf(tostring(i%10), (i-1)*80, 550, 76, "right") s = 0 for t = 1, #tSCHOOLS, 1 do if tSCHOOLS[t].Name == tSPELLS[j].School then s = t end end if s ~= 0 then r,g,b = tSCHOOLS[s].R, tSCHOOLS[s].G, tSCHOOLS[s].B if getmana() >= tSPELLS[j].Cost and tPLAYER.Effects[j].Count == 0 then love.graphics.setColor(r,g,b,255) elseif tPLAYER.Effects[j].Count > 0 and tPLAYER.Effects[j].Count <= 6*gFPS then love.graphics.setColor(r,g,b,gFLASH) else love.graphics.setColor(r/3,g/3,b/3,255) end love.graphics.draw(tSPELLS[j].Image, (i*80)-64, 551) end end end end function drawfloatytext() local x, y, z local i if next(tTEXT) ~= nil then love.graphics.setFont(fSMALL) for i = 1, #tTEXT, 1 do x = ((tTEXT[i].X-gCAMERA_X)*48)+400 y = ((tTEXT[i].Y-gCAMERA_Y)*48)+210+math.floor(tTEXT[i].Timer/2) z = math.floor(255*(tTEXT[i].Timer/gFLOAT_TIMER)) if x >= 0 and x <= 800 and y >= 0 and y <= 600 then love.graphics.setColor(0, 0, 0, z) love.graphics.printf(tTEXT[i].Text, x-79, y+1, 160, "center") if string.sub(tTEXT[i].Text,1,1) == "+" then love.graphics.setColor(0, 255, 0, z) elseif string.sub(tTEXT[i].Text,1,1) == "-" then love.graphics.setColor(255, 0, 0, z) else love.graphics.setColor(255, 255, 255, z) end love.graphics.printf(tTEXT[i].Text, x-80, y, 160, "center") end end end end function drawcommentary() local i, j local s = "" local r,g,b love.graphics.setFont(fSMALL) love.graphics.setColor(0, 0, 0, 100) love.graphics.rectangle("fill", 2, 345, 300, 200) love.graphics.setColor(200, 200, 200, 255) love.graphics.rectangle("line", 2, 345, 300, 200) j = 348 for i = gCOMMENTARY-12, gCOMMENTARY, 1 do r = tonumber(string.sub(sCOMMENTARY[i],1,3)) g = tonumber(string.sub(sCOMMENTARY[i],4,6)) b = tonumber(string.sub(sCOMMENTARY[i],7,9)) if r ~= nil and g ~= nil and b ~= nil then love.graphics.setColor(r,g,b,255) love.graphics.print(string.sub(sCOMMENTARY[i],10), 7, j) end j = j + 14 end end function drawcharacter() local i love.graphics.setColor(255, 255, 255, 255) love.graphics.setFont(fHEADING) love.graphics.draw(tPLAYER.Image, 152, 32, 0, 2, 2) if tPLAYER.UnusedPoints > 0 then for i = 1, 4, 1 do love.graphics.draw(iPLUS, 340, (i*90)+66) end end if tPLAYER.STR > tPLAYER.Old_STR then love.graphics.draw(iMINUS, 10, 156) end if tPLAYER.DEX > tPLAYER.Old_DEX then love.graphics.draw(iMINUS, 10, 246) end if tPLAYER.CON > tPLAYER.Old_CON then love.graphics.draw(iMINUS, 10, 336) end if tPLAYER.INT > tPLAYER.Old_INT then love.graphics.draw(iMINUS, 10, 426) end love.graphics.printf(getstr(), 225, 150, 65, "right") love.graphics.printf(getdex(), 225, 240, 65, "right") love.graphics.printf(getcon(), 225, 330, 65, "right") love.graphics.printf(getint(), 225, 420, 65, "right") love.graphics.setColor(150, 0, 0, 255) if getstr() ~= tPLAYER.STR then love.graphics.printf("("..tPLAYER.STR..")", 225, 150, 100, "right") end if getdex() ~= tPLAYER.DEX then love.graphics.printf("("..tPLAYER.DEX..")", 225, 240, 100, "right") end if getcon() ~= tPLAYER.CON then love.graphics.printf("("..tPLAYER.CON..")", 225, 330, 100, "right") end if getint() ~= tPLAYER.INT then love.graphics.printf("("..tPLAYER.INT..")", 225, 420, 100, "right") end for i = 1, 4, 1 do love.graphics.setColor(255, 215, 0, 255) if gCHAR_CURSOR == i then love.graphics.setColor(255, 255, 255, gFLASH) end love.graphics.rectangle("line", 70, (i*90)+60, 260, 75) end love.graphics.setColor(255, 215, 0, 255) love.graphics.rectangle("line", 410, 10, 380, 580) love.graphics.printf("Strength", 75, 150, 150, "left") love.graphics.printf("Dexterity", 75, 240, 150, "left") love.graphics.printf("Constitution", 75, 330, 150, "left") love.graphics.printf("Intelligence", 75, 420, 150, "left") if tPLAYER.UnusedPoints > 0 then love.graphics.printf("Ability Points: "..tPLAYER.UnusedPoints, 150, 510, 225, "right") end if gCHAR_CURSOR == 5 then love.graphics.setColor(255, 255, 255, gFLASH) end love.graphics.printf("Done", 50, 510, 100, "center") love.graphics.setColor(0, 150, 255, 255) love.graphics.printf("Spell Points: "..tPLAYER.SpellPoints, 150, 545, 225, "right") love.graphics.setColor(150, 0, 0, 255) love.graphics.printf("Character Info", 500, 15, 200, "center") love.graphics.printf("Resistances", 595, 235, 180, "center") love.graphics.setFont(fDEFAULT) love.graphics.printf("Health:", 400, 120, 120, "right") love.graphics.printf("Max Health:", 580, 120, 120, "right") love.graphics.setColor(255, 215, 0, 255) love.graphics.printf("Level:", 400, 45, 120, "right") love.graphics.printf("XP:", 580, 45, 120, "right") love.graphics.printf("Next Level:", 580, 70, 120, "right") love.graphics.printf("DMG:", 400, 195, 120, "right") love.graphics.printf("AC:", 580, 195, 120, "right") love.graphics.printf("Magic:", 580, 270, 120, "right") love.graphics.printf("Fire:", 580, 295, 120, "right") love.graphics.printf("Ice:", 580, 320, 120, "right") love.graphics.printf("Poison:", 580, 345, 120, "right") love.graphics.printf("(Physical)", 400, 220, 120, "right") love.graphics.printf("(Magic)", 400, 245, 120, "right") love.graphics.printf("(Fire)", 400, 270, 120, "right") love.graphics.printf("(Ice)", 400, 295, 120, "right") love.graphics.printf("(Poison)", 400, 320, 120, "right") love.graphics.printf("(Vampiric)", 400, 345, 120, "right") love.graphics.printf("Attack Speed:", 400, 395, 120, "right") love.graphics.printf("Sight Range:", 580, 395, 120, "right") love.graphics.printf("Health Renew:", 400, 420, 120, "right") love.graphics.printf("Melee Attack:", 400, 460, 120, "right") love.graphics.printf("Mana Renew:", 580, 420, 120, "right") love.graphics.printf("Life per level:", 580, 460, 120, "right") love.graphics.printf("Mana per level:", 580, 485, 120, "right") love.graphics.setColor(0, 150, 255, 255) love.graphics.printf("Mana:", 400, 145, 120, "right") love.graphics.printf("Max Mana:", 580, 145, 120, "right") love.graphics.setColor(255, 255, 255, 255) love.graphics.printf(tPLAYER.Level, 520, 45, 60, "center") love.graphics.printf(tPLAYER.XP, 700, 45, 60, "center") love.graphics.printf((tPLAYER.Level*(tPLAYER.Level+1))*500, 700, 70, 60, "center") love.graphics.printf(gethealth(), 520, 120, 60, "center") love.graphics.printf(getmaxhealth(), 700, 120, 60, "center") love.graphics.printf(getmana(), 520, 145, 60, "center") love.graphics.printf(tPLAYER.MaxMana, 700, 145, 60, "center") love.graphics.printf(tostring(getmindmg()+getbonusdmg()).."-"..tostring(getmaxdmg()+getbonusdmg()), 520, 195, 60, "center") love.graphics.printf((getarmour()*2).."%", 700, 195, 60, "center") love.graphics.printf(getmindmg().."-"..getmaxdmg(), 520, 220, 60, "center") love.graphics.printf(getmagicdmg(), 520, 245, 60, "center") love.graphics.printf(getfiredmg(), 520, 270, 60, "center") love.graphics.printf(geticedmg(), 520, 295, 60, "center") love.graphics.printf(getpoisdmg(), 520, 320, 60, "center") love.graphics.printf(getvampdmg(), 520, 345, 60, "center") love.graphics.printf(getmagicres(), 700, 270, 60, "center") love.graphics.printf(getfireres(), 700, 295, 60, "center") love.graphics.printf(geticeres(), 700, 320, 60, "center") love.graphics.printf(getpoisres(), 700, 345, 60, "center") love.graphics.printf(tostring(math.floor((getweaponspeed()*100)/gFPS)/100).." s", 520, 395, 60, "center") love.graphics.printf(getsight().." m", 700, 395, 60, "center") love.graphics.printf(tostring(math.floor((gethealthcount()*10)/gFPS)/10).." s", 520, 420, 60, "center") love.graphics.printf(tostring(math.floor((getmanacount()*10)/gFPS)/10).." s", 700, 420, 60, "center") if getattackbonus()>=0 then love.graphics.printf("+"..getattackbonus(), 520, 460, 60, "center") else love.graphics.printf(getattackbonus(), 520, 460, 60, "center") end love.graphics.printf(tostring(math.floor(tPLAYER.CON*gHEALTHGROWTH)) ,700, 460, 60, "center") love.graphics.printf(tostring(math.floor(tPLAYER.INT*gMANAGROWTH)) ,700, 485, 60, "center") love.graphics.setFont(fSMALL) love.graphics.setColor(255, 255, 255, 255) love.graphics.printf("Strength increases physical damage, chance to hit with melee weapons and the total weight you can carry.", 75, 175, 245, "left") love.graphics.printf("Dexterity increases your armour class, chance to avoid traps and your weapon speed.", 75, 265, 245, "left") love.graphics.printf("Constitution increases your resistance to non-physical damage, the amount of health gained per level and health renewal speed.", 75, 355, 245, "left") love.graphics.printf("Intelligence increases your magical damage, mana gain per level, mana renewal, ability to detect traps and unlocks new spells.", 75, 445, 245, "left") end function getitemcolour(item) local i local r, g, b = 255, 255, 255 if next(tITEMCLASS) ~= nil then for i = 1, #tITEMCLASS, 1 do if item.Class == tITEMCLASS[i].Class then r = tITEMCLASS[i].R g = tITEMCLASS[i].G b = tITEMCLASS[i].B end end end return r, g, b end function drawitem(item, x, y, width, height) local s = (3* height) / 240 local r, g, b = getitemcolour(item) love.graphics.setFont(fSMALL) love.graphics.setColor(0, 0, 0, 160) love.graphics.rectangle("fill", x, y, width, height) love.graphics.setColor(r/2, g/2, b/2, 255) love.graphics.rectangle("fill", x+2, y+(height/2)-(24*s), 48*s, 48*s) love.graphics.setColor(r, g, b, 255) love.graphics.rectangle("line", x+2, y+(height/2)-(24*s), 48*s, 48*s) love.graphics.printf(item.Class, x+4+(48*s), y+2, width-6-(48*s), "center") love.graphics.setColor(255, 255, 255, 255) love.graphics.printf(item.Name, x+4+(48*s), y+14, width-6-(48*s), "center") love.graphics.draw(item.Image, x+2, y+(height/2)-(24*s), 0, s, s) end function drawgrounditems() local i, j local r, g, b local list = {} if next(tITEMS) ~= nil then for i = 1, #tITEMS, 1 do if tITEMS[i].X == tPLAYER.X and tITEMS[i].Y == tPLAYER.Y then table.insert(list, tITEMS[i]) end end if next(list) ~= nil then for i = 1, #list, 1 do if i <=4 then drawitem(list[i], 325, (i*62)+304, 150, 60) elseif i>4 and i<=8 then drawitem(list[i], 173, (i*62)+284, 150, 60) elseif i>8 and i<=12 then drawitem(list[i], 477, (i*62)+284, 150, 60) else end end end end end function drawtargetmonster() local fade = math.min(255, gTARGET_TIMER*2) if gTARGET_MONSTER ~= nil then love.graphics.setColor(0, 0, 0, 100) love.graphics.rectangle("fill", 570, 30, 225, 100) love.graphics.setColor(200, 200, 200, fade) love.graphics.rectangle("line", 570, 30, 225, 100) love.graphics.setColor(255, 255, 255, fade) love.graphics.draw(gTARGET_MONSTER.Image, 572, 64) love.graphics.setFont(fSMALL) love.graphics.printf(monsterinfo(gTARGET_MONSTER), 620, 32, 170, "left") end end function drawinventory() local img = love.graphics.newImage("tiles/Blank.png") local i, s, x, y local r, g, b local eq_x = {51, 51, 51, 1, 101, 1, 101, 51} local eq_y = {101, 151, 201, 151, 151, 201, 201, 251} love.graphics.setColor(255, 255, 180, 255) -- Yellow outlines love.graphics.rectangle("line", 0, 30, 150, 60) love.graphics.rectangle("line", 175, 30, 75, 60) love.graphics.rectangle("line", 275, 10, 270, 70) love.graphics.rectangle("line", 570, 30, 75, 60) love.graphics.rectangle("line", 670, 30, 130, 60) love.graphics.rectangle("line", 0, 100, 150, 200) love.graphics.rectangle("line", 0, 310, 150, 290) love.graphics.rectangle("line", 160, 100, 500, 500) love.graphics.rectangle("line", 670, 100, 130, 300) love.graphics.rectangle("line", 670, 410, 130, 190) love.graphics.setFont(fTITLE) -- Title love.graphics.printf("Inventory", 275, 20, 270, "center") love.graphics.setFont(fHEADING) -- Headings love.graphics.printf("Equipped", 0, 45, 150, "center") love.graphics.printf("Info", 670, 45, 130, "center") love.graphics.setFont(fDEFAULT) -- Information love.graphics.printf("Gold", 675, 420, 120, "center") love.graphics.printf("Carried", 675, 480, 120, "center") love.graphics.printf("Weight", 675, 540, 120, "center") love.graphics.printf("AC", 175, 40, 75, "center") love.graphics.printf(tostring(getarmour()*2).."%", 175, 60, 75, "center") love.graphics.printf("DMG", 570, 40, 75, "center") love.graphics.printf(tostring(getmindmg()+getbonusdmg()).."-"..tostring(getmaxdmg()+getbonusdmg()), 570, 60, 75, "center") for i = 1, 8, 1 do -- Equipped slot boxes love.graphics.setColor(255, 255, 255, 255) love.graphics.draw(img, eq_x[i], eq_y[i]) if gEQUIP_CURSOR == i and gINV_MENU == 2 then love.graphics.setColor(255, 255, 255, gFLASH) else love.graphics.setColor(125, 125, 125, 255) end love.graphics.rectangle("line", eq_x[i], eq_y[i], 48, 48) end love.graphics.setColor(255, 255, 255, 255) -- Rest of text white love.graphics.printf(tPLAYER.Gold, 675, 440, 120, "center") s = tostring(getcarriednumber()).." / 100" love.graphics.printf(s, 675, 500, 120, "center") s = tostring(getcarriedweight()).." / "..tostring(getmaxweight()).." lbs." love.graphics.printf(s, 675, 560, 120, "center") love.graphics.setFont(fSMALL) love.graphics.printf(gITEM_INFO, 675, 110, 120, "left") -- Selected item info if next(tINVENTORY) ~= nil then -- Inventory items x = 161 y = 101 for i = 1, #tINVENTORY, 1 do r, g, b = getitemcolour(tINVENTORY[i]) love.graphics.setColor(r/2, g/2, b/2, 255) love.graphics.rectangle("fill", x, y, 48, 48) if i == gINV_SELECTED then love.graphics.setColor(r, g, b, 255) love.graphics.rectangle("fill", x, y, 48, 48) elseif i == gINV_CURSOR and gINV_MENU == 1 then love.graphics.setColor(r, g, b, gFLASH) love.graphics.rectangle("fill", x, y, 48, 48) else end love.graphics.setColor(r, g, b, 255) love.graphics.rectangle("line", x, y, 48, 48) love.graphics.setColor(255, 255, 255, 255) love.graphics.draw(tINVENTORY[i].Image, x, y) x = x + 50 if x>611 then x = 161 y = y + 50 end end end for i = 1, 8, 1 do -- Equipped items if tEQUIPPED[i] ~= nil then r, g, b = getitemcolour(tEQUIPPED[i]) love.graphics.setColor(r/2, g/2, b/2, 255) love.graphics.rectangle("fill", eq_x[i], eq_y[i], 48, 48) if i == gEQUIP_SELECTED then love.graphics.setColor(r, g, b, 255) love.graphics.rectangle("fill", eq_x[i], eq_y[i], 48, 48) elseif i == gEQUIP_CURSOR and gINV_MENU == 2 then love.graphics.setColor(r, g, b, gFLASH) love.graphics.rectangle("fill", eq_x[i], eq_y[i], 48, 48) else end love.graphics.setColor(r, g, b, 255) love.graphics.rectangle("line", eq_x[i], eq_y[i], 48, 48) love.graphics.setColor(255, 255, 255, 255) love.graphics.draw(tEQUIPPED[i].Image, eq_x[i], eq_y[i]) end end if gINV_MENU == 3 then drawmenu("", tINV_MENU, 0, 310, 150, 290, 5, gINV_SELECT) -- Corner menu else drawmenu("", tINV_MENU, 0, 310, 150, 290, 5, 0) end end function drawshop() local i, j local r, g, b local min, max local tax = gTAX if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Barter" and tPLAYER.Effects[i].Active == true then tax = tax * 0.9 end end end love.graphics.setFont(fHEADING) -- Headings love.graphics.setColor(255,215,0,255) love.graphics.printf("Inventory",10,165,200,"left") love.graphics.printf("Gold: "..tPLAYER.Gold,270,165,120,"left") love.graphics.setColor(150,0,0,255) love.graphics.printf("Shop",410,165,380,"right") love.graphics.setColor(255,255,255,255) love.graphics.draw(iGOLD,215,160) if next(tINVENTORY) ~= nil then -- Inventory list min=gINV_CURSOR-3 min=math.max(min,1) max=min+6 max=math.min(max,#tINVENTORY) j=0 for i = min, max, 1 do j=j+1 if i==gINV_SELECTED and gINV_MENU==1 then -- Solid background selected love.graphics.setColor(200,200,200,150) love.graphics.rectangle("fill",2,(j*56)+146,396,52) elseif i==gINV_CURSOR and gINV_MENU==1 then -- Flashing background cursor love.graphics.setColor(120,120,120,gFLASH) love.graphics.rectangle("fill",2,(j*56)+146,396,52) else end -- No background normal love.graphics.setColor(255,255,255,255) love.graphics.rectangle("line",2,(j*56)+146,396,52) r,g,b=getitemcolour(tINVENTORY[i]) -- Coloured background based on item class love.graphics.setColor(r/2,g/2,b/2,255) love.graphics.rectangle("fill",4,(j*56)+148,48,48) love.graphics.setColor(r,g,b,255) love.graphics.rectangle("line",4,(j*56)+148,48,48) love.graphics.setColor(255,255,255,255) -- Draw the image love.graphics.draw(tINVENTORY[i].Image, 4, (j*56)+148) love.graphics.setFont(fDEFAULT) -- Item name love.graphics.printf(tINVENTORY[i].Name, 56, (j*56)+148, 338, "left") love.graphics.setColor(255,215,0,255) -- Item sell price love.graphics.printf("Selling price: "..tINVENTORY[i].Value.." gold", 56, (j*56)+172, 338, "left") if i==gINV_SELECTED and i==gINV_CURSOR and gINV_MENU==1 then love.graphics.setColor(0,0,0,150) love.graphics.rectangle("fill",2,(j*56)+146,396,52) love.graphics.setFont(fHEADING) love.graphics.setColor(255,215,0,255) love.graphics.printf("Sell this for "..tINVENTORY[i].Value.." gold?", 56, (j*56)+156, 338, "center") end end end if next(tSHOP) ~= nil then -- Shop list min=gSHOP_CURSOR-3 min=math.max(min,1) max=min+6 max=math.min(max,#tSHOP) j=0 for i = min, max, 1 do j=j+1 if i==gSHOP_SELECTED and gINV_MENU==2 then -- Solid background selected love.graphics.setColor(200,200,200,150) love.graphics.rectangle("fill",402,(j*56)+146,396,52) elseif i==gSHOP_CURSOR and gINV_MENU==2 then -- Flashing background cursor love.graphics.setColor(120,120,120,gFLASH) love.graphics.rectangle("fill",402,(j*56)+146,396,52) else end -- No background normal love.graphics.setColor(255,255,255,255) love.graphics.rectangle("line",402,(j*56)+146,396,52) r,g,b=getitemcolour(tSHOP[i]) -- Coloured background based on item class love.graphics.setColor(r/2,g/2,b/2,255) love.graphics.rectangle("fill",404,(j*56)+148,48,48) love.graphics.setColor(r,g,b,255) love.graphics.rectangle("line",404,(j*56)+148,48,48) love.graphics.setColor(255,255,255,255) -- Draw the image love.graphics.draw(tSHOP[i].Image, 404, (j*56)+148) love.graphics.setFont(fDEFAULT) -- Item name love.graphics.printf(tSHOP[i].Name, 456, (j*56)+148, 338, "left") if tPLAYER.Gold>=math.ceil(tSHOP[i].Value*tax) then love.graphics.setColor(255,215,0,255) -- Item sell price else love.graphics.setColor(150,0,0,255) end love.graphics.printf("Selling price: "..math.ceil(tSHOP[i].Value*tax).." gold", 456, (j*56)+172, 338, "left") if i==gSHOP_SELECTED and i==gSHOP_CURSOR and gINV_MENU==2 then love.graphics.setColor(0,0,0,150) love.graphics.rectangle("fill",402,(j*56)+146,396,52) love.graphics.setFont(fHEADING) if tPLAYER.Gold < math.ceil(tSHOP[i].Value*tax) then love.graphics.setColor(150,0,0,255) love.graphics.printf("Cannot afford this item", 456, (j*56)+156, 338, "center") else love.graphics.setColor(255,215,0,255) love.graphics.printf("Buy this for "..math.ceil(tSHOP[i].Value*tax).." gold?", 456, (j*56)+156, 338, "center") end end end end love.graphics.setFont(fSMALL) if gINV_SELECTED ~= 0 then -- Selected inventory item r,g,b=getitemcolour(tINVENTORY[gINV_SELECTED]) love.graphics.setColor(r/2,g/2,b/2,255) love.graphics.rectangle("fill",8,44,72,72) love.graphics.setColor(r,g,b,255) love.graphics.rectangle("line",8,44,72,72) love.graphics.setColor(255,255,255,255) love.graphics.draw(tINVENTORY[gINV_SELECTED].Image, 8, 44, 0, 1.5, 1.5) love.graphics.setColor(255,215,0,255) love.graphics.printf(iteminfo(tINVENTORY[gINV_SELECTED]),90,5,305,"left") end if gSHOP_SELECTED ~= 0 then -- Selected shop item r,g,b=getitemcolour(tSHOP[gSHOP_SELECTED]) love.graphics.setColor(r/2,g/2,b/2,255) love.graphics.rectangle("fill",408,44,72,72) love.graphics.setColor(r,g,b,255) love.graphics.rectangle("line",408,44,72,72) love.graphics.setColor(255,255,255,255) love.graphics.draw(tSHOP[gSHOP_SELECTED].Image, 408, 44, 0, 1.5, 1.5) love.graphics.setColor(255,215,0,255) love.graphics.printf(iteminfo(tSHOP[gSHOP_SELECTED]),490,5,305,"left") end end function drawspells() local i, j, k, l, m, n local r, g, b if next(tSCHOOLS) ~= nil and next(tSPELLS) ~= nil then if gSPELLS_MENU == 0 then j = 600 / #tSCHOOLS love.graphics.setFont(fDEFAULT) for i = 1, #tSCHOOLS, 1 do r, g, b = tSCHOOLS[i].R, tSCHOOLS[i].G, tSCHOOLS[i].B if i == gSPELLS_CURSOR then love.graphics.setColor(r/2,g/2,b/2,gFLASH) else love.graphics.setColor(r/2,g/2,b/2,255) end love.graphics.rectangle("line",(j*(i-0.5))+50,250,100,100) love.graphics.setColor(r,g,b,255) love.graphics.draw(tSCHOOLS[i].Image, (j*(i-0.5))+52, 252) love.graphics.printf(tSCHOOLS[i].Name, (j*(i-1))+100, 355, j, "center") love.graphics.setColor(150, 150, 150, 255) love.graphics.printf("Level: "..tPLAYER.Spells[i], (j*(i-1))+100, 370, j, "center") end love.graphics.setFont(fHEADING) love.graphics.setColor(0, 150, 255, 255) love.graphics.printf("Spell Points: "..tPLAYER.SpellPoints, 200, 420, 400, "center") else love.graphics.setFont(fTITLE) r,g,b = tSCHOOLS[gSPELLS_MENU].R, tSCHOOLS[gSPELLS_MENU].G, tSCHOOLS[gSPELLS_MENU].B love.graphics.setColor(r, g, b, 255) love.graphics.printf("School of "..tSCHOOLS[gSPELLS_MENU].Name, 10, 10, 390, "left") love.graphics.setFont(fHEADING) love.graphics.setColor(255,215,0,255) love.graphics.printf("Points to spend: "..tPLAYER.SpellPoints, 400, 15, 390, "right") j = getmaxspelllevel(tSCHOOLS[gSPELLS_MENU].Name) for i = 1, j, 1 do l = getspellsbylevel(tSCHOOLS[gSPELLS_MENU].Name,i) if l > 0 then love.graphics.setFont(fHEADING) love.graphics.setColor(r, g, b, 255) love.graphics.printf("Level "..i, 10, (i*80), 180, "center") if tPLAYER.Spells[gSPELLS_MENU] >= i then love.graphics.setColor(255,215,0,255) love.graphics.printf("Unlocked", 10, (i*80)+25, 180, "center") else love.graphics.setColor(120,120,120,255) love.graphics.printf("Locked", 10, (i*80)+25, 180, "center") if tPLAYER.Spells[gSPELLS_MENU] == i - 1 then love.graphics.setColor(255,215,0,255) love.graphics.setFont(fSMALL) if i>1 then love.graphics.printf(i.." points to unlock", 10, (i*80)+55, 180, "center") else love.graphics.printf(i.." point to unlock", 10, (i*80)+55, 180, "center") end end end m = 0 for k = 1, #tSPELLS, 1 do if tSPELLS[k].School == tSCHOOLS[gSPELLS_MENU].Name and tSPELLS[k].Level == i then m = m + 1 love.graphics.setFont(fTINY) if tPLAYER.Spells[gSPELLS_MENU] >= i and getmana() >= tSPELLS[k].Cost and tPLAYER.Effects[k].Count == 0 then love.graphics.setColor(r, g, b, 255) else love.graphics.setColor(r, g, b, 100) end love.graphics.draw(tSPELLS[k].Image, ((m/(l+1))*400)+176, i*80) love.graphics.printf(tSPELLS[k].Name, ((m/(l+1))*400)+140, (i*80)+50, 120, "center") love.graphics.printf("Mana cost: "..tSPELLS[k].Cost, ((m/(l+1))*400)+160, (i*80)+62, 80, "center") love.graphics.setFont(fTITLE) for n = 4, 9, 1 do if tQUICKSLOT[n] == k then love.graphics.setColor(0,0,0,255) love.graphics.printf(n, ((m/(l+1))*400)+177, (i*80)+1, 48, "center") love.graphics.setColor(255,215,0,255) love.graphics.printf(n, ((m/(l+1))*400)+176, (i*80), 48, "center") end end if tQUICKSLOT[10] == k then love.graphics.setColor(0,0,0,255) love.graphics.printf("0", ((m/(l+1))*400)+177, (i*80)+1, 48, "center") love.graphics.setColor(255,215,0,255) love.graphics.printf("0", ((m/(l+1))*400)+176, (i*80), 48, "center") end if m == gSPELLS_SELECTED and i == gSPELLS_CURSOR then love.graphics.setColor(r, g, b, gFLASH) love.graphics.rectangle("line", ((m/(l+1))*400)+175, (i*80)-1, 50, 50) love.graphics.setFont(fSMALL) love.graphics.setColor(255,255,255,255) love.graphics.rectangle("line", 605, (i*80), 190, 70) love.graphics.printf(tSPELLS[k].Description, 610, (i*80)+5, 180, "left") end end end end end if tPLAYER.Spells[gSPELLS_MENU] >= gSPELLS_CURSOR then love.graphics.setFont(fHEADING) love.graphics.setColor(255,215,0,255) love.graphics.printf("Press enter to cast / 4 to 0 assigns to quickslot", 0, 560, 800, "center") end end end end function drawcredits() love.graphics.setFont(fHEADING) love.graphics.setColor(255,215,0,255) love.graphics.printf("Credits", 200, 100, 400, "center") love.graphics.printf("Press Space", 100, 450, 600, "center") love.graphics.setFont(fDEFAULT) love.graphics.setColor(255,255,255,255) love.graphics.printf("Graphic tiles used in this program is the public domain roguelike tileset 'rltiles'\nSome of the tiles have been modified by myself.\nYou can find the original tileset at: http://rltiles.sf.net", 80, 200, 640, "center") love.graphics.printf("The spell icons are provided by lorc, delapouite & contributors\nYou can find the full work at https://game-icons.net/", 80, 350, 640, "center") end function drawcontrols() love.graphics.setFont(fHEADING) love.graphics.setColor(255,255,255,255) love.graphics.printf("Main menu/Back", 0, 120, 380, "right") love.graphics.printf("Movement", 0, 150, 380, "right") love.graphics.printf("Use weapon", 0, 180, 380, "right") love.graphics.printf("Pick up/Interact", 0, 210, 380, "right") love.graphics.printf("Rest", 0, 240, 380, "right") love.graphics.printf("Inventory screen", 0, 270, 380, "right") love.graphics.printf("Character screen", 0, 300, 380, "right") love.graphics.printf("Spellbook screen", 0, 330, 380, "right") love.graphics.printf("Commentary (up)", 0, 360, 380, "right") love.graphics.printf("Commentary (down)", 0, 390, 380, "right") love.graphics.printf("Toggle GUI", 0, 420, 380, "right") love.graphics.setColor(255,215,0,255) love.graphics.printf("Controls", 200, 75, 400, "center") love.graphics.printf("Esc key", 420, 120, 380, "left") love.graphics.printf("Arrows (alt: WASD)", 420, 150, 380, "left") love.graphics.printf("1 (alt: R-SHIFT)", 420, 180, 380, "left") love.graphics.printf("Enter key", 420, 210, 380, "left") love.graphics.printf("R key", 420, 240, 380, "left") love.graphics.printf("I key", 420, 270, 380, "left") love.graphics.printf("C key", 420, 300, 380, "left") love.graphics.printf("B key", 420, 330, 380, "left") love.graphics.printf("] key", 420, 360, 380, "left") love.graphics.printf("' key", 420, 390, 380, "left") love.graphics.printf("G key", 420, 420, 380, "left") love.graphics.setColor(255,215,0,gFLASH) love.graphics.printf("Press Space", 200, 475, 400, "center") end function drawend() love.graphics.setFont(fTITLE) love.graphics.setColor(0, 0, 0, 255) love.graphics.printf("You Died", 201, 151, 400, "center") love.graphics.printf("You Died", 202, 152, 400, "center") love.graphics.setColor(255, 215, 0, 255) love.graphics.printf("You Died", 200, 150, 400, "center") love.graphics.setFont(fHEADING) love.graphics.setColor(0, 0, 0, 255) love.graphics.printf("You Reached Level "..gLEVEL, 201, 291, 400, "center") love.graphics.printf("You Reached Level "..gLEVEL, 202, 292, 400, "center") love.graphics.setColor(200, 200, 200, 255) love.graphics.printf("You Reached Level "..gLEVEL, 200, 290, 400, "center") love.graphics.setColor(0, 0, 0, gFLASH) love.graphics.printf("Press Space", 201, 421, 400, "center") love.graphics.printf("Press Space", 202, 422, 400, "center") love.graphics.setColor(200, 200, 200, gFLASH) love.graphics.printf("Press Space", 200, 420, 400, "center") end function withingrid(x,y) if x>=1 and x<=gGRIDSIZE and y>=1 and y<=gGRIDSIZE then return true else return false end end function distancebetween(a,b,c,d) return math.sqrt(((c-a)^2)+((d-b)^2)) end function love.keypressed(key) local s if gGAMEMODE == "Title" then keystitle(key) elseif gGAMEMODE == "Choose Appearance" then keyschooseappearance(key) elseif gGAMEMODE == "Startscreen" then keysstartscreen(key) elseif gGAMEMODE == "Playing" then keysgame(key) elseif gGAMEMODE == "Paused" then keyspaused(key) elseif gGAMEMODE == "Inventory" then keysinventory(key) elseif gGAMEMODE == "Character" then keyscharacter(key) elseif gGAMEMODE == "Shop" then keysshop(key) elseif gGAMEMODE == "Spells" then keysspells(key) elseif gGAMEMODE == "Credits" or gGAMEMODE == "Controls" then keyscredits(key) elseif gGAMEMODE == "End Game" then keysend(key) else end end function keystitle(key) if key == "escape" and gGAMEMODE ~= gGAMEMODE_old then gGAMEMODE = gGAMEMODE_old playgamemusic() gFADE = 255 elseif (key == "down" or key == "s") then gMAIN_SELECT = gMAIN_SELECT + 1 if gMAIN_SELECT > #tMAIN_MENU then gMAIN_SELECT = 1 end elseif (key == "up" or key == "w") then gMAIN_SELECT = gMAIN_SELECT - 1 if gMAIN_SELECT < 1 then gMAIN_SELECT = #tMAIN_MENU end elseif (key == "return" or key == "space") then if tMAIN_MENU[gMAIN_SELECT]=="New game" then blankplayer() gGAMEMODE = "Choose Appearance" gAPP_SELECT = 3 gFADE = 255 elseif tMAIN_MENU[gMAIN_SELECT]=="Continue from checkpoint" then blankplayer() loadgame() gGAMEMODE = "Startscreen" gSTARTING = 2 gFADE = 255 playgamemusic() elseif tMAIN_MENU[gMAIN_SELECT]=="Sounds on" then gSOUNDON = false addcommentary("120120120Sound OFF") tMAIN_MENU[gMAIN_SELECT] = "Sounds off" elseif tMAIN_MENU[gMAIN_SELECT]=="Sounds off" then gSOUNDON = true addcommentary("120120120Sound ON") tMAIN_MENU[gMAIN_SELECT] = "Sounds on" elseif tMAIN_MENU[gMAIN_SELECT]=="Music on" then gMUSICON = false addcommentary("120120120Music OFF") tMAIN_MENU[gMAIN_SELECT] = "Music off" playtitlemusic() elseif tMAIN_MENU[gMAIN_SELECT]=="Music off" then gMUSICON = true addcommentary("120120120Music ON") tMAIN_MENU[gMAIN_SELECT] = "Music on" playtitlemusic() elseif tMAIN_MENU[gMAIN_SELECT]=="Credits" then gGAMEMODE = "Credits" gFADE = 255 elseif tMAIN_MENU[gMAIN_SELECT]=="Controls" then gGAMEMODE = "Controls" gFADE = 255 elseif tMAIN_MENU[gMAIN_SELECT]=="Quit" then love.timer.sleep(1) love.event.quit() else end else end end function keyschooseappearance(key) if key == "escape" then gGAMEMODE_old = gGAMEMODE gGAMEMODE = "Title" gFADE = 255 elseif key == "up" or key == "w" then gAPP_SELECT = gAPP_SELECT - 1 if gAPP_SELECT < 3 then gAPP_SELECT = 5 end elseif key == "down" or key == "s" then gAPP_SELECT = gAPP_SELECT + 1 if gAPP_SELECT > 5 then gAPP_SELECT = 3 end elseif key == "right" or key == "d" then gPLAYERIMAGE = gPLAYERIMAGE + 1 if gPLAYERIMAGE > gPLAYERIMAGES then gPLAYERIMAGE = 1 end tPLAYER.Image = love.graphics.newImage("player/Player"..gPLAYERIMAGE..".png") elseif key == "left" or key == "a" then gPLAYERIMAGE = gPLAYERIMAGE - 1 if gPLAYERIMAGE < 1 then gPLAYERIMAGE = gPLAYERIMAGES end tPLAYER.Image = love.graphics.newImage("player/Player"..gPLAYERIMAGE..".png") elseif key == "return" then if gAPP_SELECT == 3 then gPLAYERIMAGE = gPLAYERIMAGE + 1 if gPLAYERIMAGE > gPLAYERIMAGES then gPLAYERIMAGE = 1 end tPLAYER.Image = love.graphics.newImage("player/Player"..gPLAYERIMAGE..".png") elseif gAPP_SELECT == 4 then tINVENTORY[1] = createspecialitem("Health Potion",0,0,0) tINVENTORY[2] = createspecialitem("Mana Potion",0,0,0) tEQUIPPED[4] = deepcopy(getbaseitem("Dagger")) tEQUIPPED[5] = createspecialitem("Torch",0,0,0) addcommentary("255215000Press I to access your Inventory") addcommentary("255215000Press C to access your Character Screen") gGAMEMODE = "Startscreen" gSTARTING = 2 gFADE = 255 playgamemusic() elseif gAPP_SELECT == 5 then gGAMEMODE = "Title" gFADE = 255 else end else end end function keysstartscreen(key) if key == "escape" then gGAMEMODE_old = gGAMEMODE gGAMEMODE = "Title" playtitlemusic() gFADE = 255 else gGAMEMODE = "Playing" gFADE = 255 addcommentary("200200200New level begun") end end function keysgame(key) local i, j, k if gethealth() <= 0 then -- do nothing, just to avoid one turn of fighting when dead! elseif key == "escape" then gGAMEMODE_old = gGAMEMODE gGAMEMODE = "Title" playtitlemusic() gFADE = 255 elseif tPLAYER.Resting == true then tPLAYER.Resting = false addcommentary("120120120You awake from your rest") elseif key == "r" and tPLAYER.Resting == false then j = 10 if next(tMONSTERS) ~= nil then for i = 1, #tMONSTERS, 1 do k = distancebetween(tMONSTERS[i].X,tMONSTERS[i].Y,tPLAYER.X,tPLAYER.Y) if k < j then j = k end end end if j >= 10 then tPLAYER.Resting = true addcommentary("120120120You settle into a deep sleep") else addcommentary("120120120You cannot rest with monsters so nearby") end elseif (key == "up" or key == "w") and tPLAYER.FreezeCount == 0 then trymove(0,-1) elseif (key == "down" or key == "s") and tPLAYER.FreezeCount == 0 then trymove(0,1) elseif (key == "right" or key == "d") and tPLAYER.FreezeCount == 0 then trymove(1,0) elseif (key == "left" or key == "a") and tPLAYER.FreezeCount == 0 then trymove(-1,0) elseif key == "]" then gCOMMENTARY = math.max(13, gCOMMENTARY-1) elseif key == "'" then gCOMMENTARY = math.min(#sCOMMENTARY, gCOMMENTARY+1) elseif key == "g" then if gGUION == true then gGUION = false else gGUION = true end elseif key == "i" then gGAMEMODE = "Inventory" tINV_MENU = {"Sort Items", "- - -", "- - -", "- - -", "Exit"} gINV_SELECT = 1 gINV_CURSOR = 0 gEQUIP_CURSOR = 0 gINV_SELECTED = 0 gEQUIP_SELECTED = 0 gINV_MENU = 3 gITEM_INFO = "" elseif key == "b" then gGAMEMODE = "Spells" gSPELLS_MENU = 0 gSPELLS_CURSOR = 1 gSPELLS_SELECTED = 0 elseif key == "c" then gGAMEMODE = "Character" tPLAYER.Old_STR = tPLAYER.STR tPLAYER.Old_DEX = tPLAYER.DEX tPLAYER.Old_CON = tPLAYER.CON tPLAYER.Old_INT = tPLAYER.INT elseif key == "return" then if tTILES[tPLAYER.X][tPLAYER.Y].Type == "Finish" then sCOMMENTARY = {"", "", "", "", "", "", "", "", "", "", "", "", ""} gCOMMENTARY = 13 tPLAYER.XP = tPLAYER.XP + (gLEVEL*100) addcommentary("255215000You gain "..(gLEVEL*100).." xp") gLEVEL = gLEVEL+1 gGAMEMODE = "Startscreen" gSTARTING = 2 gFADE = 255 else pickupitems() end elseif (key == "1" or key == "rshift") and tPLAYER.Recoil == 0 and (tPLAYER.VX ~= 0 or tPLAYER.VY ~= 0) then attack() elseif tonumber(key) ~= nil then i = tonumber(key) if i == 2 and getinvitem("Health Potion") > 0 then gINV_SELECTED = getinvitem("Health Potion") useitem() elseif i == 3 and getinvitem("Mana Potion") > 0 then gINV_SELECTED = getinvitem("Mana Potion") useitem() elseif i >= 4 and i <=9 then j = tQUICKSLOT[i] if j > 0 then castspell(j) end elseif i == 0 then j = tQUICKSLOT[10] if j > 0 then castspell(j) end else end elseif key == "space" then gGAMEMODE = "Paused" else end end function keyspaused(key) if key == "escape" then gGAMEMODE_old = gGAMEMODE gGAMEMODE = "Title" playtitlemusic() gFADE = 255 elseif (key == "up" or key == "w") then gCAMERA_Y = gCAMERA_Y - 1 elseif (key == "down" or key == "s") then gCAMERA_Y = gCAMERA_Y + 1 elseif (key == "right" or key == "d") then gCAMERA_X = gCAMERA_X + 1 elseif (key == "left" or key == "a") then gCAMERA_X = gCAMERA_X - 1 elseif key == "]" then gCOMMENTARY = math.max(13, gCOMMENTARY-1) elseif key == "'" then gCOMMENTARY = math.min(#sCOMMENTARY, gCOMMENTARY+1) elseif key == "space" then gGAMEMODE = "Playing" else end end function keysinventory(key) if key == "escape" or key == "i" then gGAMEMODE = "Playing" gFADE = 255 elseif gINV_MENU == 1 then if key == "right" or key == "d" then if next(tINVENTORY) ~= nil then if gINV_CURSOR % 10 == 0 or gINV_CURSOR>=#tINVENTORY then if gINV_CURSOR<=40 then gINV_MENU = 2 gEQUIP_CURSOR = 1 else gINV_MENU = 3 gINV_SELECT = 1 end else gINV_CURSOR = gINV_CURSOR + 1 end else gINV_MENU = 2 gEQUIP_CURSOR = 1 end elseif key == "left" or key == "a" then if next(tINVENTORY) ~= nil then if (gINV_CURSOR-1) % 10 == 0 then if gINV_CURSOR<=40 then gINV_MENU = 2 gEQUIP_CURSOR = 1 else gINV_MENU = 3 gSELECT = 1 end else gINV_CURSOR = gINV_CURSOR - 1 end else gINV_MENU = 3 gSELECT = 1 end elseif key == "up" or key == "w" then if next(tINVENTORY) ~= nil then if gINV_CURSOR >= 11 then gINV_CURSOR = gINV_CURSOR - 10 else gINV_CURSOR = gINV_CURSOR + (math.floor(#tINVENTORY/10)*10) if gINV_CURSOR > #tINVENTORY then gINV_CURSOR = gINV_CURSOR - 10 end end else gINV_MENU = 2 gEQUIP_CURSOR = 1 end elseif key == "down" or key == "s" then if next(tINVENTORY) ~= nil then if gINV_CURSOR <= #tINVENTORY - 10 then gINV_CURSOR = gINV_CURSOR + 10 else gINV_CURSOR = gINV_CURSOR - (math.floor(#tINVENTORY/10)*10) end else gINV_MENU = 3 gSELECT = 1 end elseif key == "return" then if next(tINVENTORY) ~= nil then if gINV_CURSOR >= 1 and gINV_CURSOR <= #tINVENTORY then if gINV_SELECTED == gINV_CURSOR then gINV_SELECTED = 0 else gINV_SELECTED = gINV_CURSOR gEQUIP_SELECTED = 0 tINV_MENU[2] = "Info" if tINVENTORY[gINV_CURSOR].Class == "Usable Item" then tINV_MENU[3] = "Use" else tINV_MENU[3] = "Equip" end tINV_MENU[4] = "Drop" gINV_MENU = 3 gSELECT = 1 end else gINV_CURSOR = 1 end else gINV_MENU = 3 gSELECT = 1 end else end elseif gINV_MENU == 2 then if key == "right" or key == "d" then if gEQUIP_CURSOR == 1 or gEQUIP_CURSOR == 5 or gEQUIP_CURSOR == 7 or gEQUIP_CURSOR == 8 then gINV_MENU = 1 gINV_CURSOR = 1 elseif gEQUIP_CURSOR == 4 then gEQUIP_CURSOR = 2 elseif gEQUIP_CURSOR == 6 then gEQUIP_CURSOR = 3 elseif gEQUIP_CURSOR == 2 then gEQUIP_CURSOR = 5 elseif gEQUIP_CURSOR == 3 then gEQUIP_CURSOR = 7 else end elseif key == "left" or key == "a" then if gEQUIP_CURSOR == 1 or gEQUIP_CURSOR == 4 or gEQUIP_CURSOR == 6 or gEQUIP_CURSOR == 8 then gINV_MENU = 1 gINV_CURSOR = 1 elseif gEQUIP_CURSOR == 5 then gEQUIP_CURSOR = 2 elseif gEQUIP_CURSOR == 7 then gEQUIP_CURSOR = 3 elseif gEQUIP_CURSOR == 2 then gEQUIP_CURSOR = 4 elseif gEQUIP_CURSOR == 3 then gEQUIP_CURSOR = 6 else end elseif key == "up" or key == "w" then if gEQUIP_CURSOR == 1 or gEQUIP_CURSOR == 4 or gEQUIP_CURSOR == 5 then gINV_MENU = 3 gINV_SELECT = 5 elseif gEQUIP_CURSOR == 2 then gEQUIP_CURSOR = 1 elseif gEQUIP_CURSOR == 6 then gEQUIP_CURSOR = 4 elseif gEQUIP_CURSOR == 3 then gEQUIP_CURSOR = 2 elseif gEQUIP_CURSOR == 7 then gEQUIP_CURSOR = 5 elseif gEQUIP_CURSOR == 8 then gEQUIP_CURSOR = 3 else end elseif key == "down" or key == "s" then if gEQUIP_CURSOR == 8 or gEQUIP_CURSOR == 6 or gEQUIP_CURSOR == 7 then gINV_MENU = 3 gINV_SELECT = 1 elseif gEQUIP_CURSOR == 2 then gEQUIP_CURSOR = 3 elseif gEQUIP_CURSOR == 4 then gEQUIP_CURSOR = 6 elseif gEQUIP_CURSOR == 3 then gEQUIP_CURSOR = 8 elseif gEQUIP_CURSOR == 5 then gEQUIP_CURSOR = 7 elseif gEQUIP_CURSOR == 1 then gEQUIP_CURSOR = 2 else end elseif key == "return" then if tEQUIPPED[gEQUIP_CURSOR] ~= nil then if gEQUIP_SELECTED == gEQUIP_CURSOR then gEQUIP_SELECTED = 0 else gEQUIP_SELECTED = gEQUIP_CURSOR gINV_SELECTED = 0 gINV_MENU = 3 tINV_MENU[2] = "Info" tINV_MENU[3] = "Unequip" end end else end elseif gINV_MENU == 3 then if key == "right" or key == "d" then gINV_MENU = 1 gINV_CURSOR = 1 elseif key == "left" or key == "a" then gINV_MENU = 2 gEQUIP_CURSOR = 1 elseif key == "up" or key == "w" then gINV_SELECT = gINV_SELECT - 1 while tINV_MENU[gINV_SELECT] == "- - -" do gINV_SELECT = gINV_SELECT - 1 end if gINV_SELECT < 1 then gINV_SELECT = 1 gINV_MENU = 2 gEQUIP_CURSOR = 8 end elseif key == "down" or key == "s" then gINV_SELECT = gINV_SELECT + 1 while tINV_MENU[gINV_SELECT] == "- - -" do gINV_SELECT = gINV_SELECT + 1 end if gINV_SELECT > 5 then gINV_SELECT = 1 gINV_MENU = 2 gEQUIP_CURSOR = 1 end elseif key == "return" then if tINV_MENU[gINV_SELECT] == "Exit" then gGAMEMODE = "Playing" elseif tINV_MENU[gINV_SELECT] == "Sort Items" then sortitems() elseif tINV_MENU[gINV_SELECT] == "Info" then if gINV_SELECTED ~= 0 then gITEM_INFO = iteminfo(tINVENTORY[gINV_SELECTED]) elseif gEQUIP_SELECTED ~= 0 then gITEM_INFO = iteminfo(tEQUIPPED[gEQUIP_SELECTED]) else end elseif tINV_MENU[gINV_SELECT] == "Equip" then equipitem() elseif tINV_MENU[gINV_SELECT] == "Unequip" then unequipitem() elseif tINV_MENU[gINV_SELECT] == "Drop" then dropitem() elseif tINV_MENU[gINV_SELECT] == "Use" then useitem() else end else end else end if next(tINVENTORY) == nil and gINV_MENU == 1 then gINV_MENU = 3 gINV_SELECT = 1 end end function checkinventory() local check = "OK" if getcarriednumber() > 100 then check = "Inventory Full" addcommentary("200200200You cannot carry any more items") elseif getcarriedweight() > getmaxweight() then check = "Weight Exceeded" addcommentary("200200200You cannot carry any more weight") else end return check end function keyscharacter(key) if key == "s" or key == "down" then gCHAR_CURSOR = gCHAR_CURSOR + 1 if gCHAR_CURSOR > 5 then gCHAR_CURSOR = 1 end elseif key == "w" or key == "up" then gCHAR_CURSOR = gCHAR_CURSOR - 1 if gCHAR_CURSOR < 1 then gCHAR_CURSOR = 5 end elseif (key == "d" or key == "right" or key=="return") and tPLAYER.UnusedPoints > 0 and gCHAR_CURSOR < 5 then if gCHAR_CURSOR == 1 then tPLAYER.STR = tPLAYER.STR + 1 elseif gCHAR_CURSOR == 2 then tPLAYER.DEX = tPLAYER.DEX + 1 elseif gCHAR_CURSOR == 3 then tPLAYER.CON = tPLAYER.CON + 1 elseif gCHAR_CURSOR == 4 then tPLAYER.INT = tPLAYER.INT + 1 if tPLAYER.INT > 10 then tPLAYER.SpellPoints = tPLAYER.SpellPoints + 1 end else end tPLAYER.UnusedPoints = tPLAYER.UnusedPoints - 1 elseif key == "a" or key == "left" then if gCHAR_CURSOR == 1 and tPLAYER.STR > tPLAYER.Old_STR then tPLAYER.STR = tPLAYER.STR - 1 tPLAYER.UnusedPoints = tPLAYER.UnusedPoints + 1 elseif gCHAR_CURSOR == 2 and tPLAYER.DEX > tPLAYER.Old_DEX then tPLAYER.DEX = tPLAYER.DEX - 1 tPLAYER.UnusedPoints = tPLAYER.UnusedPoints + 1 elseif gCHAR_CURSOR == 3 and tPLAYER.CON > tPLAYER.Old_CON then tPLAYER.CON = tPLAYER.CON - 1 tPLAYER.UnusedPoints = tPLAYER.UnusedPoints + 1 elseif gCHAR_CURSOR == 4 and tPLAYER.INT > tPLAYER.Old_INT then if tPLAYER.INT > 10 then tPLAYER.SpellPoints = tPLAYER.SpellPoints - 1 end tPLAYER.INT = tPLAYER.INT - 1 tPLAYER.UnusedPoints = tPLAYER.UnusedPoints + 1 else end elseif key == "c" or (key == "return" and gCHAR_CURSOR == 5) or key == "escape" then if tPLAYER.SpellPoints > 0 then addcommentary("000150255Press B to use your "..tPLAYER.SpellPoints.." spell points") end gGAMEMODE = "Playing" gFADE = 255 else end end function keysshop(key) local tax = gTAX local i if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Barter" and tPLAYER.Effects[i].Active == true then tax = tax * 0.9 end end end if key == "escape" or key == "i" then gGAMEMODE = "Playing" gFADE = 255 elseif key == "up" or key == "w" then if gINV_MENU==1 and next(tINVENTORY) ~= nil then gINV_CURSOR = gINV_CURSOR - 1 if gINV_CURSOR < 1 then gINV_CURSOR = #tINVENTORY end elseif gINV_MENU==2 and next(tSHOP) ~= nil then gSHOP_CURSOR = gSHOP_CURSOR - 1 if gSHOP_CURSOR < 1 then gSHOP_CURSOR = #tSHOP end else end elseif key == "down" or key == "s" then if gINV_MENU==1 and next(tINVENTORY) ~= nil then gINV_CURSOR = gINV_CURSOR + 1 if gINV_CURSOR > #tINVENTORY then gINV_CURSOR = 1 end elseif gINV_MENU==2 and next(tSHOP) ~= nil then gSHOP_CURSOR = gSHOP_CURSOR + 1 if gSHOP_CURSOR > #tSHOP then gSHOP_CURSOR = 1 end else end elseif key == "right" or key == "left" or key == "a" or key == "d" then gINV_MENU = 3-gINV_MENU elseif key == "return" then if gINV_MENU==1 and next(tINVENTORY) ~= nil then if gINV_SELECTED==gINV_CURSOR then tPLAYER.Gold = tPLAYER.Gold + tINVENTORY[gINV_SELECTED].Value if tINVENTORY[gINV_SELECTED].Name == "Resurrection Stone" then tPLAYER.Resurrection = tPLAYER.Resurrection - 1 end table.insert(tSHOP,deepcopy(tINVENTORY[gINV_SELECTED])) table.remove(tINVENTORY,gINV_SELECTED) if next(tINVENTORY) ~= nil then if gINV_CURSOR > #tINVENTORY then gINV_CURSOR = #tINVENTORY end elseif next(tSHOP) ~= nil then gINV_MENU=2 else end gINV_SELECTED=0 else gINV_SELECTED=gINV_CURSOR end elseif gINV_MENU==2 and next(tSHOP) ~= nil then if gSHOP_SELECTED==gSHOP_CURSOR and math.ceil(tSHOP[gSHOP_CURSOR].Value*tax) <= tPLAYER.Gold then tPLAYER.Gold = tPLAYER.Gold - math.ceil(tSHOP[gSHOP_SELECTED].Value*tax) if tSHOP[gSHOP_SELECTED].Name == "Resurrection Stone" then tPLAYER.Resurrection = tPLAYER.Resurrection + 1 end table.insert(tINVENTORY,deepcopy(tSHOP[gSHOP_SELECTED])) table.remove(tSHOP,gSHOP_SELECTED) if next(tSHOP) ~= nil then if gSHOP_CURSOR > #tSHOP then gSHOP_CURSOR = #tSHOP end elseif next(tINVENTORY) ~= nil then gINV_MENU=1 else end gSHOP_SELECTED=0 else gSHOP_SELECTED=gSHOP_CURSOR end else end else end end function keysspells(key) local i, j , k, l if next(tSPELLS) ~= nil and next(tSCHOOLS) ~= nil then if gSPELLS_MENU == 0 then if key == "escape" or key == "b" then gGAMEMODE = "Playing" elseif key == "right" or key == "d" then gSPELLS_CURSOR = gSPELLS_CURSOR + 1 if gSPELLS_CURSOR > #tSCHOOLS then gSPELLS_CURSOR = 1 end elseif key == "left" or key == "a" then gSPELLS_CURSOR = gSPELLS_CURSOR - 1 if gSPELLS_CURSOR < 1 then gSPELLS_CURSOR = #tSCHOOLS end elseif key == "return" or key == "space" then gSPELLS_MENU = gSPELLS_CURSOR gSPELLS_CURSOR = 1 gSPELLS_SELECTED = math.floor((getspellsbylevel(tSCHOOLS[gSPELLS_MENU].Name,1)+1)/2) else end elseif gSPELLS_MENU > 0 then if key == "escape" then gSPELLS_CURSOR = gSPELLS_MENU gSPELLS_MENU = 0 gSPELLS_SELECTED = 0 elseif key == "b" then gGAMEMODE = "Playing" elseif key == "down" or key == "s" then gSPELLS_CURSOR = gSPELLS_CURSOR + 1 if gSPELLS_CURSOR > getmaxspelllevel(tSCHOOLS[gSPELLS_MENU].Name) then gSPELLS_CURSOR = 1 end if gSPELLS_SELECTED > getspellsbylevel(tSCHOOLS[gSPELLS_MENU].Name,gSPELLS_CURSOR) then gSPELLS_SELECTED = math.floor((getspellsbylevel(tSCHOOLS[gSPELLS_MENU].Name,gSPELLS_CURSOR)+1)/2) end elseif key == "up" or key == "w" then gSPELLS_CURSOR = gSPELLS_CURSOR - 1 if gSPELLS_CURSOR < 1 then gSPELLS_CURSOR = getmaxspelllevel(tSCHOOLS[gSPELLS_MENU].Name) end if gSPELLS_SELECTED > getspellsbylevel(tSCHOOLS[gSPELLS_MENU].Name,gSPELLS_CURSOR) then gSPELLS_SELECTED = math.floor((getspellsbylevel(tSCHOOLS[gSPELLS_MENU].Name,gSPELLS_CURSOR)+1)/2) end elseif key == "right" or key == "d" then gSPELLS_SELECTED = gSPELLS_SELECTED + 1 if gSPELLS_SELECTED > getspellsbylevel(tSCHOOLS[gSPELLS_MENU].Name,gSPELLS_CURSOR) then gSPELLS_SELECTED = 1 end elseif key == "left" or key == "a" then gSPELLS_SELECTED = gSPELLS_SELECTED - 1 if gSPELLS_SELECTED < 1 then gSPELLS_SELECTED = getspellsbylevel(tSCHOOLS[gSPELLS_MENU].Name,gSPELLS_CURSOR) end elseif key == "return" or key == "space" then if tPLAYER.SpellPoints >= gSPELLS_CURSOR and tPLAYER.Spells[gSPELLS_MENU] == gSPELLS_CURSOR - 1 then tPLAYER.SpellPoints = tPLAYER.SpellPoints - gSPELLS_CURSOR tPLAYER.Spells[gSPELLS_MENU] = tPLAYER.Spells[gSPELLS_MENU] + 1 elseif tPLAYER.Spells[gSPELLS_MENU] >= gSPELLS_CURSOR then if gSPELLS_SELECTED > 0 and gSPELLS_SELECTED <= getspellsbylevel(tSCHOOLS[gSPELLS_MENU].Name,gSPELLS_CURSOR) then k = 0 for j = 1, #tSPELLS, 1 do if tSPELLS[j].School == tSCHOOLS[gSPELLS_MENU].Name and tSPELLS[j].Level == gSPELLS_CURSOR then k = k + 1 if k == gSPELLS_SELECTED then castspell(j) end end end end end elseif tonumber(key) ~= nil and getspellsbylevel(tSCHOOLS[gSPELLS_MENU].Name,gSPELLS_CURSOR) > 0 and tPLAYER.Spells[gSPELLS_MENU] >= gSPELLS_CURSOR then i = tonumber(key) if i == 0 then i = 10 end if i>=4 and i<=10 then k = 0 for j = 1, #tSPELLS, 1 do if tSPELLS[j].School == tSCHOOLS[gSPELLS_MENU].Name and tSPELLS[j].Level == gSPELLS_CURSOR then k = k + 1 if k == gSPELLS_SELECTED then tQUICKSLOT[i] = j for l = 4, 10, 1 do if tQUICKSLOT[l] == j and l ~= i then tQUICKSLOT[l] = 0 end end end end end end else end else end else gGAMEMODE = "Playing" end end function keyscredits(key) if key == "space" then gGAMEMODE = "Title" gFADE = 255 end end function keysend(key) if key == "space" then gGAMEMODE = "Credits" gGAMEMODE_old = "Title" tMAIN_MENU = {"New game", "Controls", "Sounds on", "Music on", "Credits", "Quit"} gFADE = 255 playtitlemusic() elseif key == "]" then gCOMMENTARY = math.max(13, gCOMMENTARY-1) elseif key == "'" then gCOMMENTARY = math.min(#sCOMMENTARY, gCOMMENTARY+1) else end end function iteminfo(item) local s = "" if item.Class ~= nil then s = item.Class end if item.Name ~= nil then s = s.."\r\n"..item.Name end if item.Type ~= nil and item.Ranged ~= nil then if item.Type == "Weapon" then if item.Ranged == true then s = s.."\r\nType: Ranged Weapon" else s = s.."\r\nType: Melee Weapon" end if item.MaxDMG ~= 0 then s = s.."\r\n"..item.MinDMG.."-"..item.MaxDMG.." physical damage" end if item.Magic ~= 0 then s = s.."\r\n+"..item.Magic.." magical damage" end if item.Fire ~= 0 then s = s.."\r\n+"..item.Fire.." fire damage" end if item.Ice ~= 0 then s = s.."\r\n+"..item.Ice.." ice damage" end if item.Vampire ~= 0 then s = s.."\r\n+"..item.Vampire.." vampiric damage" end if item.Poison ~= 0 then s = s.."\r\n+"..item.Poison.." poison damage" end else s = s.."\r\nType: "..item.Type if item.AC ~= 0 then s = s.."\r\nArmour +"..item.AC end if item.Magic ~= 0 then s = s.."\r\n+"..(item.Magic*2).." magic resistance" end if item.Fire ~= 0 then s = s.."\r\n+"..(item.Fire*2).." fire resistance" end if item.Ice ~= 0 then s = s.."\r\n+"..(item.Ice*2).." ice resistance" end if item.Poison ~= 0 then s = s.."\r\n+"..(item.Poison*2).." poison resistance" end end end if item.BonusSTR ~= 0 then s = s.."\r\n+"..item.BonusSTR.." strength" end if item.BonusDEX ~= 0 then s = s.."\r\n+"..item.BonusDEX.." dexterity" end if item.BonusCON ~= 0 then s = s.."\r\n+"..item.BonusCON.." constitution" end if item.BonusINT ~= 0 then s = s.."\r\n+"..item.BonusINT.." intelligence" end if item.Regenerate ~= 0 then s = s.."\r\nRegenerate +"..item.Regenerate.."/10sec" end if item.Sight ~= 0 then s = s.."\r\nSight Range +"..item.Sight end if item.Value ~= nil then s = s.."\r\nValue: "..item.Value end if item.Weight ~= nil then s = s.."\r\nWeight: "..item.Weight.." lbs" end return s end function monsterinfo(monster) local s = "" local im, re, vu = "None", "None", "None" if monster.Class ~= nil then s = monster.Class.." " end if monster.Name ~= nil then s = s..monster.Name end if monster.Level ~= nil then s = s.."\r\nLevel "..monster.Level end if monster.Magic ~= nil then if monster.Magic == 0 then if im == "None" then im = "Magic" else im = im..", Magic" end elseif monster.Magic>0 and monster.Magic<100 then if re == "None" then re = "Magic" else re = re..", Magic" end elseif monster.Magic>100 then if vu == "None" then vu = "Magic" else vu = vu..", Magic" end else end end if monster.Fire ~= nil then if monster.Fire == 0 then if im == "None" then im = "Fire" else im = im..", Fire" end elseif monster.Fire>0 and monster.Fire<100 then if re == "None" then re = "Fire" else re = re..", Fire" end elseif monster.Fire>100 then if vu == "None" then vu = "Fire" else vu = vu..", Fire" end else end end if monster.Ice ~= nil then if monster.Ice == 0 then if im == "None" then im = "Ice" else im = im..", Ice" end elseif monster.Ice>0 and monster.Ice<100 then if re == "None" then re = "Ice" else re = re..", Ice" end elseif monster.Ice>100 then if vu == "None" then vu = "Ice" else vu = vu..", Ice" end else end end if monster.Poison ~= nil then if monster.Poison == 0 then if im == "None" then im = "Poison" else im = im..", Poison" end elseif monster.Poison>0 and monster.Poison<100 then if re == "None" then re = "Poison" else re = re..", Poison" end elseif monster.Poison>100 then if vu == "None" then vu = "Poison" else vu = vu..", Poison" end else end end if im ~= "None" then s = s.."\r\nImmunity: "..im end if re ~= "None" then s = s.."\r\nResistance: "..re end if vu ~= "None" then s = s.."\r\nVulnerability: "..vu end if monster.Special ~= "None" and monster.SpecialCH > 0 then s = s.."\r\n"..monster.Special.." "..tostring(math.floor(monster.SpecialCH)).."%" end return s end function sortitems() local i, j, k, found local kinds = {} local sorted = {} local list = {} if next(tINVENTORY) ~= nil then for i = 1, #tINVENTORY, 1 do k = tINVENTORY[i].Type sorted[i] = false found = false if next(kinds) ~= nil then for j = 1, #kinds, 1 do if kinds[j] == k then found = true end end end if found == false then table.insert(kinds, k) end end table.sort(kinds) for j = 1, #kinds, 1 do repeat found = 0 k = -1 for i = 1, #tINVENTORY, 1 do if tINVENTORY[i].Type == kinds[j] and tINVENTORY[i].Value > k and sorted[i] == false then found = i k = tINVENTORY[i].Value end end if found ~= 0 then table.insert(list, deepcopy(tINVENTORY[found])) sorted[found] = true end until found == 0 end tINVENTORY = deepcopy(list) end gINV_SELECTED = 0 tINV_MENU = {"Sort Items", "- - -", "- - -", "- - -", "Exit"} gINV_MENU = 1 gINV_SELECT = 1 gINV_CURSOR = 1 end function equipitem() local i local slot = 0 local new_item, old_item = nil, nil if tINVENTORY[gINV_SELECTED] ~= nil then new_item = deepcopy(tINVENTORY[gINV_SELECTED]) end if new_item ~= nil then for i = 1, 8, 1 do if new_item.Type == tEQUIPSLOTS[i] then slot = i end end if slot ~= 0 then if tEQUIPPED[slot] ~= nil then old_item = deepcopy(tEQUIPPED[slot]) end tEQUIPPED[slot] = deepcopy(new_item) table.remove(tINVENTORY, gINV_SELECTED) table.insert(tINVENTORY, deepcopy(old_item)) if checkinventory() == "Weight Exceeded" then table.remove(tINVENTORY) table.insert(tINVENTORY, deepcopy(new_item)) tEQUIPPED[slot] = deepcopy(old_item) else addcommentary("120120120"..new_item.Name.." equipped") end end gINV_SELECTED = 0 tINV_MENU = {"Sort Items", "- - -", "- - -", "- - -", "Exit"} gINV_MENU = 1 gINV_SELECT = 1 gINV_CURSOR = 1 end i = getregen() if i > 0 then tPLAYER.RegenCount = math.ceil((10 * gFPS) / i) else tPLAYER.RegenCount = 0 end end function unequipitem() local i, item if tEQUIPPED[gEQUIP_SELECTED] ~= nil then item = tEQUIPPED[gEQUIP_SELECTED] table.insert(tINVENTORY, deepcopy(item)) tEQUIPPED[gEQUIP_SELECTED] = nil if checkinventory() ~= "OK" then table.remove(tINVENTORY) tEQUIPPED[gEQUIP_SELECTED] = deepcopy(item) else addcommentary("120120120"..item.Name.." unequipped") end gEQUIP_SELECTED = 0 tINV_MENU = {"Sort Items", "- - -", "- - -", "- - -", "Exit"} gINV_MENU = 1 gINV_SELECT = 1 gINV_CURSOR = 1 end i = getregen() if i > 0 then tPLAYER.RegenCount = math.ceil((10 * gFPS) / i) else tPLAYER.RegenCount = 0 end end function dropitem() local item = tINVENTORY[gINV_SELECTED] if item ~= nil then item.X = tPLAYER.X item.Y = tPLAYER.Y table.remove(tINVENTORY, gINV_SELECTED) table.insert(tITEMS, deepcopy(item)) gINV_SELECTED = 0 tINV_MENU = {"Sort Items", "- - -", "- - -", "- - -", "Exit"} gINV_MENU = 1 gINV_SELECT = 1 gINV_CURSOR = 1 addcommentary("120120120"..item.Name.." dropped") end end function useitem() local i local item = tINVENTORY[gINV_SELECTED] if item ~= nil then if item.Name == "Health Potion" then i = tPLAYER.Wounds tPLAYER.Wounds = math.max(tPLAYER.Wounds-25, 0) addfloatytext("Potion consumed", tPLAYER.X, tPLAYER.Y) addcommentary("000255000"..(i-tPLAYER.Wounds).." health recovered") table.remove(tINVENTORY, gINV_SELECTED) elseif item.Name == "Mana Potion" then i = tPLAYER.UsedMana tPLAYER.UsedMana = math.max(tPLAYER.UsedMana-25, 0) addfloatytext("Potion consumed", tPLAYER.X, tPLAYER.Y) addcommentary("000150255"..(i-tPLAYER.UsedMana).." mana recovered") table.remove(tINVENTORY, gINV_SELECTED) elseif item.Name == "Tome of Strength" then tPLAYER.STR = tPLAYER.STR + 1 addfloatytext("Strength Increased", tPLAYER.X, tPLAYER.Y) addcommentary("000150255You feel stronger") table.remove(tINVENTORY, gINV_SELECTED) elseif item.Name == "Tome of Dexterity" then tPLAYER.DEX = tPLAYER.DEX + 1 addfloatytext("Dexterity Increased", tPLAYER.X, tPLAYER.Y) addcommentary("000150255You feel more nimble") table.remove(tINVENTORY, gINV_SELECTED) elseif item.Name == "Tome of Constitution" then tPLAYER.CON = tPLAYER.CON + 1 addfloatytext("Constitution Increased", tPLAYER.X, tPLAYER.Y) addcommentary("000150255You feel vitalised") table.remove(tINVENTORY, gINV_SELECTED) elseif item.Name == "Tome of Intelligence" then tPLAYER.INT = tPLAYER.INT + 1 if tPLAYER.INT > 10 then tPLAYER.SpellPoints = tPLAYER.SpellPoints + 1 end addfloatytext("Intelligence Increased", tPLAYER.X, tPLAYER.Y) addcommentary("000150255You feel wiser") table.remove(tINVENTORY, gINV_SELECTED) else end end gINV_SELECTED = 0 tINV_MENU = {"Sort Items", "- - -", "- - -", "- - -", "Exit"} gINV_MENU = 1 gINV_SELECT = 1 gINV_CURSOR = 1 end function trymove(vx,vy) local x = tPLAYER.X local y = tPLAYER.Y tPLAYER.VX = vx tPLAYER.VY = vy local tx = x + vx local ty = y + vy local ethereal = false local i local check = checkinventory() tPLAYER.SearchCount = gFPS if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Ethereal" and tPLAYER.Effects[i].Active == true then ethereal = true end end end if next(tTILES) ~= nil and check == "OK" then if getmonster(tx,ty)>0 then if tPLAYER.Recoil == 0 then attack() end elseif tTILES[tx][ty].Solid == false then if tx > 1 and tx < gGRIDSIZE and ty > 1 and ty < gGRIDSIZE then tPLAYER.X = tx tPLAYER.Y = ty if tTILES[tx][ty].Type == "Trap" and tTILES[tx][ty].Triggered == false then triggertrap(tx,ty) end end elseif tTILES[tx][ty].Type == "Shop" then gGAMEMODE = "Shop" gSHOP_SELECTED = 0 gINV_SELECTED = 0 gSHOP_CURSOR = 1 gINV_CURSOR = 1 if next(tINVENTORY) ~= nil then gINV_MENU = 1 else gINV_MENU = 2 end gFADE=255 elseif tTILES[tx][ty].Type == "Closed Door" then if tTILES[tx][ty].Locked == true then addfloatytext("Locked", tx, ty) else createtile("Open Door", tx, ty) end elseif tTILES[tx][ty].Type == "Closed Chest" then if tTILES[tx][ty].Locked == true then addfloatytext("Locked", tx, ty) else openchest() createtile("Open Chest", tx, ty) end elseif tTILES[tx][ty].Type == "Start" then addfloatytext("No way back", tx, ty) elseif tTILES[tx][ty].Type == "Fountain Blue" and tPLAYER.UsedMana > 0 then createtile("Fountain Empty", tx, ty) tPLAYER.UsedMana = 0 addfloatytext("Mana Restored", tPLAYER.X, tPLAYER.Y) addcommentary("000255000The fountain restores your Mana") elseif tTILES[tx][ty].Type == "Fountain Red" and tPLAYER.Wounds > 0 then createtile("Fountain Empty", tx, ty) tPLAYER.Wounds = 0 addfloatytext("Health Restored", tPLAYER.X, tPLAYER.Y) addcommentary("000255000The fountain restores your Health") elseif tTILES[tx][ty].Type == "Fountain Empty" then addfloatytext("The Fountain Is Dry", tPLAYER.X, tPLAYER.Y) elseif tTILES[tx][ty].Solid == true and ethereal == true then if tx > 1 and tx < gGRIDSIZE and ty > 1 and ty < gGRIDSIZE then tPLAYER.X = tx tPLAYER.Y = ty end else end elseif check == "Weight Exceeded" then addcommentary("120120120You are overladen and cannot move") else end end function triggertrap(x,y) local d = math.random(10) local i = math.floor((getdex()-10)/2) local r = getroom(x,y) local l = {} local t = math.max(math.ceil(gLEVEL*0.66)-math.random(5),1) if (d+i) >= math.floor(gLEVEL/4)+5 then addcommentary("120120120"..d.." + "..i.." = *AVOIDED TRAP*") tTILES[x][y].Flagged=true tTILES[x][y].Image=iACTIVE else addcommentary("120120120"..d.." + "..i.." = *TRIGGERED TRAP*") addfloatytext("Trap Triggered",x,y) i = math.random(7) if x>tROOMS[r].X then table.insert(l,1) end if y>tROOMS[r].Y then table.insert(l,2) end if xtROOMS[r].X then createprojectile("Star",getdiceroll(t,2),tROOMS[r].X,y,1,0,"Neutral",tROOMS[r].Width+2) end if y>tROOMS[r].Y then createprojectile("Star",getdiceroll(t,2),x,tROOMS[r].Y,0,1,"Neutral",tROOMS[r].Height+2) end if xtROOMS[r].Y+tROOMS[r].Height-1 then createprojectile("Star",getdiceroll(t,2),x,tROOMS[r].Y+tROOMS[r].Height-1,0,-1,"Neutral",tROOMS[r].Height+2) end else -- Lightning 1d6 per level if d == 1 then createprojectile("Lightning",getdiceroll(t,6),tROOMS[r].X,y,1,0,"Neutral",tROOMS[r].Width+2) elseif d == 2 then createprojectile("Lightning",getdiceroll(t,6),x,tROOMS[r].Y,0,1,"Neutral",tROOMS[r].Height+2) elseif d == 3 then createprojectile("Lightning",getdiceroll(t,6),tROOMS[r].X+tROOMS[r].Width-1,y,-1,0,"Neutral",tROOMS[r].Width+2) else createprojectile("Lightning",getdiceroll(t,6),x,tROOMS[r].Y+tROOMS[r].Height-1,0,-1,"Neutral",tROOMS[r].Height+2) end end tTILES[x][y].Triggered = true tTILES[x][y].Image = iDEACTIVE end end function castspell(n) local i, j, x, y local adj = {} local ran = 0 local chain = {} if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Hide in Shadows" then tPLAYER.Effects[i].Active = false end end end if getmana() >= tSPELLS[n].Cost then if tPLAYER.Effects[n].Count == 0 then addcommentary("000150255You cast "..tSPELLS[n].Name) addfloatytext(tSPELLS[n].Name, tPLAYER.X, tPLAYER.Y) tPLAYER.ManaCount = getmanacount() tPLAYER.Effects[n].Name = tSPELLS[n].Name tPLAYER.Effects[n].Active = true tPLAYER.Effects[n].Count = tSPELLS[n].Duration * gFPS tPLAYER.UsedMana = tPLAYER.UsedMana + tSPELLS[n].Cost j = getmonster(tPLAYER.X, tPLAYER.Y+1) if j ~= 0 then table.insert(adj, j) end j = getmonster(tPLAYER.X, tPLAYER.Y-1) if j ~= 0 then table.insert(adj, j) end j = getmonster(tPLAYER.X+1, tPLAYER.Y) if j ~= 0 then table.insert(adj, j) end j = getmonster(tPLAYER.X-1, tPLAYER.Y) if j ~= 0 then table.insert(adj, j) end if next(adj) ~= nil then ran = adj[math.random(#adj)] end if tSPELLS[n].Name == "Acid Splash" and (tPLAYER.VX ~= 0 or tPLAYER.VY ~= 0) then createprojectile("Orb", getdiceroll(3,4), tPLAYER.X, tPLAYER.Y, tPLAYER.VX, tPLAYER.VY, "Player", 5) elseif tSPELLS[n].Name == "Bolt" and (tPLAYER.VX ~= 0 or tPLAYER.VY ~= 0) then i = math.min(tPLAYER.Level, 5) createprojectile("Lightning", getdiceroll(i,8), tPLAYER.X, tPLAYER.Y, tPLAYER.VX, tPLAYER.VY, "Player", 7) elseif tSPELLS[n].Name == "Chain Lightning" and (tPLAYER.VX ~= 0 or tPLAYER.VY ~= 0) then i = math.min(tPLAYER.Level, 8) for x = 1, gGRIDSIZE, 1 do chain[x] = {} for y = 1, gGRIDSIZE, 1 do chain[x][y] = false end end chain[tPLAYER.X][tPLAYER.Y] = true j = false while j == false do j = false for x = 2, gGRIDSIZE-1, 1 do for y = 2, gGRIDSIZE-1, 1 do if getmonster(x,y) > 0 and (chain[x][y+1]==true or chain[x+1][y]==true or chain[x][y-1]==true or chain[x-1][y]==true) and chain[x][y] == false then createprojectile("Lightning", getdiceroll(i,12), x, y, 0, 0, "Player", 1) j = true chain[x][y] = true end end end end elseif tSPELLS[n].Name == "Cure Minor Wounds" then tPLAYER.Wounds = math.max(tPLAYER.Wounds-5, 0) elseif tSPELLS[n].Name == "Cure Light Wounds" then tPLAYER.Wounds = math.max(tPLAYER.Wounds-10, 0) elseif tSPELLS[n].Name == "Cure Moderate Wounds" then tPLAYER.Wounds = math.max(tPLAYER.Wounds-25, 0) elseif tSPELLS[n].Name == "Cure Serious Wounds" then tPLAYER.Wounds = math.max(tPLAYER.Wounds-50, 0) elseif tSPELLS[n].Name == "Cure Major Wounds" then tPLAYER.Wounds = math.max(tPLAYER.Wounds-100, 0) elseif tSPELLS[n].Name == "Curse" then j = getroom(tPLAYER.X,tPLAYER.Y) if next(tMONSTERS) ~= nil then for i = 1, #tMONSTERS, 1 do if getroom(tMONSTERS[i].X,tMONSTERS[i].Y) == j then tMONSTERS[i].Cursed = true end end end elseif tSPELLS[n].Name == "Daze" then j = getroom(tPLAYER.X,tPLAYER.Y) if next(tMONSTERS) ~= nil then for i = 1, #tMONSTERS, 1 do if getroom(tMONSTERS[i].X,tMONSTERS[i].Y) == j and tMONSTERS[i].Level <= 5 then tMONSTERS[i].MOVCount = tMONSTERS[i].MOVCount + (6*gFPS) tMONSTERS[i].ATKCount = tMONSTERS[i].ATKCount + (6*gFPS) end end end elseif tSPELLS[n].Name == "Delayed Blast" then createprojectile("Bomb", 0, tPLAYER.X, tPLAYER.Y, 0, 0, "Player", 6) elseif tSPELLS[n].Name == "Detect Traps" then j = getroom(tPLAYER.X,tPLAYER.Y) for x = tROOMS[j].X-1, tROOMS[j].X+tROOMS[j].Width, 1 do for y = tROOMS[j].Y-1, tROOMS[j].Y+tROOMS[j].Height, 1 do if withingrid(x,y) then tDISCOVERED[x][y] = true if tTILES[x][y].Type == "Trap" and tTILES[x][y].Triggered == false then tTILES[x][y].Image = iACTIVE tTILES[x][y].Flagged = true addcommentary("120120120Trap detected") end end end end elseif tSPELLS[n].Name == "Disarm Traps" then j = getroom(tPLAYER.X,tPLAYER.Y) for x = tROOMS[j].X, tROOMS[j].X+tROOMS[j].Width-1, 1 do for y = tROOMS[j].Y, tROOMS[j].Y+tROOMS[j].Height-1, 1 do if tTILES[x][y].Type == "Trap" and tTILES[x][y].Triggered == false and tTILES[x][y].Flagged == true then tTILES[x][y].Triggered = true tTILES[x][y].Image = iDEACTIVE addcommentary("120120120Trap disarmed") end end end elseif tSPELLS[n].Name == "Fear" then j = getroom(tPLAYER.X,tPLAYER.Y) if next(tMONSTERS) ~= nil then for i = 1, #tMONSTERS, 1 do if getroom(tMONSTERS[i].X,tMONSTERS[i].Y) == j and tMONSTERS[i].Level <= 15 then tMONSTERS[i].Feared = true end end end elseif tSPELLS[n].Name == "Fireball" then i = math.min(tPLAYER.Level, 6) createprojectile("Fireball", getdiceroll(i,10), tPLAYER.X, tPLAYER.Y, tPLAYER.VX, tPLAYER.VY, "Player", 7) elseif tSPELLS[n].Name == "Firewall" then for x = math.max(tPLAYER.X-3,1), math.min(tPLAYER.X+3,gGRIDSIZE), 1 do for y = math.max(tPLAYER.Y-3,1), math.min(tPLAYER.Y+3,gGRIDSIZE), 1 do i = distancebetween(x,y,tPLAYER.X,tPLAYER.Y) if i > 1.4 and i < 2.8 then createprojectile("Flame", math.random(40,80), x, y, 0, 0, "Neutral", 30) end end end elseif tSPELLS[n].Name == "Freeze" then j = getroom(tPLAYER.X,tPLAYER.Y) if j > 0 then for x = tROOMS[j].X, tROOMS[j].X+tROOMS[j].Width-1, 1 do for y = tROOMS[j].Y, tROOMS[j].Y+tROOMS[j].Height-1, 1 do j = getmonster(x,y) if j > 0 then tMONSTERS[j].MOVCount = tMONSTERS[j].MOVCount + (10*gFPS) end end end end elseif tSPELLS[n].Name == "Heal" then tPLAYER.Wounds = 0 elseif tSPELLS[n].Name == "Lightning Ray" and (tPLAYER.VX ~= 0 or tPLAYER.VY ~= 0) then i = math.min(tPLAYER.Level, 6) createprojectile("Lightning", getdiceroll(i,12), tPLAYER.X, tPLAYER.Y, tPLAYER.VX, tPLAYER.VY, "Player", 7) elseif tSPELLS[n].Name == "Magic Missiles" then i = math.min(tPLAYER.Level, 6) createprojectile("Star", getdiceroll(i,4), tPLAYER.X, tPLAYER.Y, 0, 1, "Player", 10) createprojectile("Star", getdiceroll(i,4), tPLAYER.X, tPLAYER.Y, 0, -1, "Player", 10) createprojectile("Star", getdiceroll(i,4), tPLAYER.X, tPLAYER.Y, 1, 0, "Player", 10) createprojectile("Star", getdiceroll(i,4), tPLAYER.X, tPLAYER.Y, -1, 0, "Player", 10) elseif tSPELLS[n].Name == "Melf's Acid Arrow" and (tPLAYER.VX ~= 0 or tPLAYER.VY ~= 0) then i = math.min(tPLAYER.Level, 10) createprojectile("Blast", getdiceroll(i,5), tPLAYER.X, tPLAYER.Y, tPLAYER.VX, tPLAYER.VY, "Player", 7) elseif tSPELLS[n].Name == "Meteor Shower" then i = getroom(tPLAYER.X, tPLAYER.Y) if i > 0 then j = math.ceil(tROOMS[i].Width*tROOMS[i].Height/10) for x = 1, j, 1 do spawnmeteor(i) end end elseif tSPELLS[n].Name == "Open Lock" then x,y = tPLAYER.X, tPLAYER.Y tTILES[x][y+1].Locked = false tTILES[x][y-1].Locked = false tTILES[x+1][y].Locked = false tTILES[x-1][y].Locked = false elseif tSPELLS[n].Name == "Poison Gas" then i = getroom(tPLAYER.X, tPLAYER.Y) if i > 0 then for x = tROOMS[i].X, tROOMS[i].X+tROOMS[i].Width-1, 1 do for y = tROOMS[i].Y, tROOMS[i].Y+tROOMS[i].Height-1, 1 do if x~=tPLAYER.X or y~=tPLAYER.Y then createprojectile("Gas",math.random(10,20),x,y,0,0,"Neutral",30) end end end end elseif tSPELLS[n].Name == "Ray of Frost" and (tPLAYER.VX ~= 0 or tPLAYER.VY ~= 0) then i = math.min(tPLAYER.Level, 4) createprojectile("Ice", getdiceroll(i,4), tPLAYER.X, tPLAYER.Y, tPLAYER.VX, tPLAYER.VY, "Player", 7) elseif tSPELLS[n].Name == "Reveal Maze" then for x = 1, gGRIDSIZE, 1 do for y = 1, gGRIDSIZE, 1 do tDISCOVERED[x][y] = true end end elseif tSPELLS[n].Name == "Slow" then j = getroom(tPLAYER.X, tPLAYER.Y) if next(tMONSTERS) ~= nil then for i = 1, #tMONSTERS, 1 do if getroom(tMONSTERS[i].X,tMONSTERS[i].Y) == j and tMONSTERS[i].Slowed == false then tMONSTERS[i].Slowed = true tMONSTERS[i].MOVSpeed = tMONSTERS[i].MOVSpeed * 2 tMONSTERS[i].ATKSpeed = tMONSTERS[i].ATKSpeed * 2 end end end elseif tSPELLS[n].Name == "Snakebite" then if ran > 0 then i = getdiceroll(10,5) damagemonster(ran, i, "Poison") else addfloatytext("Spell failed", tPLAYER.X, tPLAYER.Y) addcommentary("120120120There is no adjacent monster to attack") end elseif tSPELLS[n].Name == "Spark" then i = math.min(tPLAYER.Level, 4) createprojectile("Flame", getdiceroll(i,3), tPLAYER.X, tPLAYER.Y+1, 0, 0, "Player", 1) createprojectile("Flame", getdiceroll(i,3), tPLAYER.X, tPLAYER.Y-1, 0, 0, "Player", 1) createprojectile("Flame", getdiceroll(i,3), tPLAYER.X+1, tPLAYER.Y, 0, 0, "Player", 1) createprojectile("Flame", getdiceroll(i,3), tPLAYER.X-1, tPLAYER.Y, 0, 0, "Player", 1) elseif tSPELLS[n].Name == "Teleport Other" then if ran > 0 then repeat x = math.random(2, gGRIDSIZE-1) y = math.random(2, gGRIDSIZE-1) until tTILES[x][y].Solid == false and getmonster(x,y) == 0 and (tPLAYER.X~=x or tPLAYER.Y~=y) tMONSTERS[ran].X = x tMONSTERS[ran].Y = y else addfloatytext("Spell failed", tPLAYER.X, tPLAYER.Y) addcommentary("120120120There are no adjacent creatures to teleport") end elseif tSPELLS[n].Name == "Teleport Self" then repeat x = math.random(2, gGRIDSIZE-1) y = math.random(2, gGRIDSIZE-1) until tTILES[x][y].Solid == false and getmonster(x,y) == 0 and (tPLAYER.X~=x or tPLAYER.Y~=y) tPLAYER.X = x tPLAYER.Y = y elseif tSPELLS[n].Name == "Three Daggers" and (tPLAYER.VX ~= 0 or tPLAYER.VY ~= 0) then i = math.min(tPLAYER.Level, 10) createprojectile("Arrow",getdiceroll(i,8),tPLAYER.X,tPLAYER.Y,tPLAYER.VX,tPLAYER.VY,"Player",7) if tPLAYER.VX ~= 0 then createprojectile("Arrow",getdiceroll(i,8),tPLAYER.X,tPLAYER.Y+1,tPLAYER.VX,tPLAYER.VY,"Player",7) createprojectile("Arrow",getdiceroll(i,8),tPLAYER.X,tPLAYER.Y-1,tPLAYER.VX,tPLAYER.VY,"Player",7) else createprojectile("Arrow",getdiceroll(i,8),tPLAYER.X+1,tPLAYER.Y,tPLAYER.VX,tPLAYER.VY,"Player",7) createprojectile("Arrow",getdiceroll(i,8),tPLAYER.X-1,tPLAYER.Y,tPLAYER.VX,tPLAYER.VY,"Player",7) end elseif tSPELLS[n].Name == "Time Stop" then j = getroom(tPLAYER.X,tPLAYER.Y) if next(tMONSTERS) ~= nil then for i = 1, #tMONSTERS, 1 do if getroom(tMONSTERS[i].X,tMONSTERS[i].Y) == j then tMONSTERS[i].MOVCount = tMONSTERS[i].MOVCount + (12*gFPS) tMONSTERS[i].ATKCount = tMONSTERS[i].ATKCount + (12*gFPS) end end end elseif tSPELLS[n].Name == "Touch of Death" then if ran > 0 then if tMONSTERS[ran].Level <= 40 then tMONSTERS[ran].Wounds = tMONSTERS[ran].Life else tMONSTERS[ran].Wounds = tMONSTERS[ran].Wounds + math.ceil((tMONSTERS[ran].Life-tMONSTERS[ran].Wounds)/2) end else addfloatytext("Spell failed", tPLAYER.X, tPLAYER.Y) addcommentary("120120120There is no adjacent monster to attack") end elseif tSPELLS[n].Name == "Wolfbite" then if ran > 0 then i = getdiceroll(math.min(tPLAYER.Level,10),8) damagemonster(ran,i,"Physical") tPLAYER.Wounds = math.max(tPLAYER.Wounds-i,0) else addfloatytext("Spell failed", tPLAYER.X, tPLAYER.Y) addcommentary("120120120There is no adjacent monster to attack") end else end if tPLAYER.Effects[n].Count == 0 then if tPLAYER.Effects[n].Name == "Fear" and next(tMONSTERS) ~= nil then for i = 1, #tMONSTERS, 1 do tMONSTERS[i].Feared = false end end tPLAYER.Effects[n].Active = false tPLAYER.Effects[n].Name = "" end else addcommentary("120120120You cannot duplicate this spell effect") addfloatytext("Cannot cast spell", tPLAYER.X, tPLAYER.Y) end else addcommentary("120120120Not enough mana to the cast spell") addfloatytext("Not enough mana", tPLAYER.X, tPLAYER.Y) end end function attack() local vx, vy = tPLAYER.VX, tPLAYER.VY local tx, ty = tPLAYER.X + vx, tPLAYER.Y + vy local mon, dmg, i local att, roll, hit local cleave = 1 local cluster = 1 local destroy = false tPLAYER.RecoilMax = getweaponspeed() tPLAYER.Recoil = tPLAYER.RecoilMax if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Cleave" and tPLAYER.Effects[i].Active == true then cleave = 4 end if tPLAYER.Effects[i].Name == "Destroy Armour" and tPLAYER.Effects[i].Active == true then destroy = true end if tPLAYER.Effects[i].Name == "Cluster of Arrows" and tPLAYER.Effects[i].Active == true then cluster = 4 end if tPLAYER.Effects[i].Name == "Hide in Shadows" then tPLAYER.Effects[i].Active = false end end end if tEQUIPPED[4] ~= nil and (tPLAYER.VX ~= 0 or tPLAYER.VY ~= 0) then if tEQUIPPED[4].Ranged == true and tEQUIPPED[4].Ammo ~= "None" then if string.find(tEQUIPPED[4].Name,"Wand") or string.find(tEQUIPPED[4].Name,"Sceptre") then dmg = getmagicdmg() else dmg = math.random(getmindmg(), getmaxdmg()) end for i = 1, cluster, 1 do if i == 1 and cluster == 4 then tx, ty = tPLAYER.X, tPLAYER.Y+1 vx, vy = 0, 1 elseif i == 2 then tx, ty = tPLAYER.X+1, tPLAYER.Y vx, vy = 1, 0 elseif i == 3 then tx, ty = tPLAYER.X, tPLAYER.Y-1 vx, vy = 0, -1 elseif i == 4 then tx, ty = tPLAYER.X-1, tPLAYER.Y vx, vy = -1, 0 else end if getmonster(tx,ty)==0 then createprojectile(tEQUIPPED[4].Ammo, dmg, tPLAYER.X, tPLAYER.Y, vx, vy, "Player", 7) elseif cluster == 1 then addfloatytext("Too close", tPLAYER.X, tPLAYER.Y) addcommentary("200200200You must equip a melee weapon") else end end else for i = 1, cleave, 1 do if cleave == 1 then mon = getmonster(tx, ty) elseif i == 1 then mon = getmonster(tPLAYER.X,tPLAYER.Y+1) elseif i == 2 then mon = getmonster(tPLAYER.X,tPLAYER.Y-1) elseif i == 3 then mon = getmonster(tPLAYER.X+1,tPLAYER.Y) elseif i == 4 then mon = getmonster(tPLAYER.X-1,tPLAYER.Y) else end if mon > 0 then addcommentary("120120120You attack the "..tMONSTERS[mon].Class.." "..tMONSTERS[mon].Name) gTARGET_MONSTER = deepcopy(tMONSTERS[mon]) gTARGET_TIMER = 400 roll = math.random(20) att = getattackbonus() if roll == 20 then hit = 2 addcommentary("120120120"..roll.." + "..att.." = *CRITICAL HIT*") elseif roll == 1 then hit = 0 addcommentary("120120120"..roll.." + "..att.." = *CRITICAL MISS*") elseif roll+att > tMONSTERS[mon].Armour then hit = 1 addcommentary("120120120"..roll.." + "..att.." = *HIT*") else hit = 0 addcommentary("120120120"..roll.." + "..att.." = *MISS*") end if hit >= 1 then att = false dmg = math.random(getmindmg(), getmaxdmg()) if dmg > 0 then damagemonster(mon, dmg*hit, "Physical") end dmg = getmagicdmg() if dmg > 0 then damagemonster(mon, dmg*hit, "Magic") end dmg = getfiredmg() if dmg > 0 then damagemonster(mon, dmg*hit, "Fire") end dmg = geticedmg() if dmg > 0 then damagemonster(mon, dmg*hit, "Ice") end dmg = getvampdmg() if dmg > 0 then damagemonster(mon, dmg*hit, "Vampire") end dmg = getpoisdmg() if dmg > 0 then damagemonster(mon, dmg*hit, "Poison") end if tEQUIPPED[4].Vampire > 0 then tPLAYER.Wounds = math.max(0, tPLAYER.Wounds-tEQUIPPED[4].Vampire) end if destroy == true then tMONSTERS[mon].Armour = tMONSTERS[mon].Armour - 1 end end end end end else addfloatytext("Equip a weapon", tPLAYER.X, tPLAYER.Y) addcommentary("200200200You must equip a weapon before you attack") end end function createprojectile(kind, dmg, x, y, vx, vy, source, dist) local i local file = "No file" if next(tPROJECTILES)~=nil then i=#tPROJECTILES+1 else i=1 end tPROJECTILES[i]={} if vx==0 and (vy==1 or vy==0) then file="projectiles/"..kind.."3.png" elseif vx==1 and vy==0 then file="projectiles/"..kind.."2.png" elseif vx==0 and vy==-1 then file="projectiles/"..kind.."1.png" elseif vx==-1 and vy==0 then file="projectiles/"..kind.."4.png" else end if love.filesystem.getInfo(file, "file") then tPROJECTILES[i].Image=love.graphics.newImage(file) else tPROJECTILES[i].Image=iPLUS end tPROJECTILES[i].X=x tPROJECTILES[i].Y=y tPROJECTILES[i].VX=vx tPROJECTILES[i].VY=vy tPROJECTILES[i].Type=kind tPROJECTILES[i].DMG=dmg tPROJECTILES[i].Source=source tPROJECTILES[i].Dist=dist tPROJECTILES[i].Hit=false if kind == "Arrow" then tPROJECTILES[i].Speed=5 tPROJECTILES[i].DMGTYPE="Physical" elseif kind == "Blast" then tPROJECTILES[i].Speed=5 tPROJECTILES[i].DMGTYPE="Poison" elseif kind == "Bomb" then tPROJECTILES[i].Speed=gFPS tPROJECTILES[i].DMGTYPE="Fire" elseif kind == "Flame" then tPROJECTILES[i].Speed=gFPS tPROJECTILES[i].DMGTYPE="Fire" elseif kind == "Fireball" then tPROJECTILES[i].Speed=6 tPROJECTILES[i].DMGTYPE="Fire" elseif kind == "Frost" then tPROJECTILES[i].Speed=8 tPROJECTILES[i].DMGTYPE="Ice" elseif kind == "Gas" then tPROJECTILES[i].Speed=gFPS tPROJECTILES[i].DMGTYPE="Poison" elseif kind == "Gem" then tPROJECTILES[i].Speed=6 tPROJECTILES[i].DMGTYPE="Magic" elseif kind == "Ice" then tPROJECTILES[i].Speed=5 tPROJECTILES[i].DMGTYPE="Ice" elseif kind == "Lightning" then tPROJECTILES[i].Speed=3 tPROJECTILES[i].DMGTYPE="Magic" elseif kind == "Meteor" then tPROJECTILES[i].Speed=10 tPROJECTILES[i].DMGTYPE="Fire" elseif kind == "Orb" then tPROJECTILES[i].Speed=8 tPROJECTILES[i].DMGTYPE="Poison" elseif kind == "Star" then tPROJECTILES[i].Speed=7 tPROJECTILES[i].DMGTYPE="Magic" else tPROJECTILES[i].Speed=5 tPROJECTILES[i].DMGTYPE="Physical" end tPROJECTILES[i].Count=tPROJECTILES[i].Speed end function specialattack(special, mon, dmg) local i, j local x, y local list = {} local x_nesw = {0,1,0,-1} local y_nesw = {1,0,-1,0} if special == "Breeds" then for i = 1, 4, 1 do x = tMONSTERS[mon].X+x_nesw[i] y = tMONSTERS[mon].Y+y_nesw[i] if withingrid(x,y) then if getmonster(x,y)==0 and tTILES[x][y].Solid==false and ((x~=tPLAYER.X)or(y~=tPLAYER.Y)) then table.insert(list,i) end end end if next(list) ~= nil then j = list[math.random(#list)] i = #tMONSTERS + 1 tMONSTERS[i] = deepcopy(tMONSTERS[mon]) tMONSTERS[i].Wounds = 0 addfloatytext("Breeds",tMONSTERS[i].X,tMONSTERS[i].Y) tMONSTERS[i].X = tMONSTERS[i].X + x_nesw[j] tMONSTERS[i].Y = tMONSTERS[i].Y + y_nesw[j] end elseif special == "Eats equipment" then for i = 1, 8, 1 do if tEQUIPPED[i] ~= nil then table.insert(list, i) end end if next(list) ~= nil then i = list[math.random(#list)] addfloatytext("Equipment eaten!", tPLAYER.X, tPLAYER.Y) addcommentary("255000255"..tEQUIPPED[i].Class.." "..tEQUIPPED[i].Name.." has been consumed!") tEQUIPPED[i] = nil end elseif special == "Freeze" then addfloatytext("Frozen", tPLAYER.X, tPLAYER.Y) addcommentary("255000255"..tMONSTERS[mon].Name.." casts freeze") tPLAYER.FreezeCount = tPLAYER.FreezeCount + (gFPS * 3) tPLAYER.Recoil = tPLAYER.Recoil + (gFPS * 3) createprojectile("Frost", 0, tPLAYER.X, tPLAYER.Y, 0, 0, "Monster", 7) elseif special == "Vampiric" then tMONSTERS[mon].Wounds = math.max(0, tMONSTERS[mon].Wounds-dmg) addfloatytext("Vampiric",tMONSTERS[mon].X,tMONSTERS[mon].Y) else end end function damagemonster(m, amount, kind) local dmg = amount local arm = tMONSTERS[m].Armour if kind == "Physical" then dmg = dmg - math.floor((dmg*arm/50)+0.5) elseif kind == "Magic" then dmg = dmg * (tMONSTERS[m].Magic / 100) elseif kind == "Fire" then dmg = dmg * (tMONSTERS[m].Fire / 100) elseif kind == "Ice" then dmg = dmg * (tMONSTERS[m].Ice / 100) elseif kind == "Poison" then dmg = dmg * (tMONSTERS[m].Poison / 100) else end dmg = math.floor(dmg) if dmg > 0 then addfloatytext(dmg.." "..kind.." damage", tMONSTERS[m].X, tMONSTERS[m].Y) addcommentary("200200200"..tMONSTERS[m].Class.." "..tMONSTERS[m].Name.." suffers "..dmg.." "..kind.." damage") tMONSTERS[m].Wounds = tMONSTERS[m].Wounds + dmg else addcommentary("120120120"..tMONSTERS[m].Class.." "..tMONSTERS[m].Name.." resists the damage unscathed") end end function damageplayer(amount, kind) local dmg = amount local arm = getarmour() if kind == "Physical" and arm > 0 then dmg = dmg - math.floor((dmg*arm/50)+0.5) elseif kind == "Magic" then dmg = dmg - getmagicres() elseif kind == "Fire" then dmg = dmg - getfireres() elseif kind == "Ice" then dmg = dmg - geticeres() elseif kind == "Poison" then dmg = dmg - getpoisres() else end dmg = math.floor(dmg) if dmg > 0 then addfloatytext(dmg.." "..kind.." damage", tPLAYER.X, tPLAYER.Y) addcommentary("255000000You suffer "..dmg.." "..kind.." damage") tPLAYER.Wounds = tPLAYER.Wounds + dmg tPLAYER.HealthCount = gethealthcount() else addcommentary("120120120You resist the damage unscathed") end tPLAYER.Resting = false end function pickupitems() local i, check if next(tITEMS) ~= nil then for i = #tITEMS, 1, -1 do if tITEMS[i].X == tPLAYER.X and tITEMS[i].Y == tPLAYER.Y then if tITEMS[i].Type == "Gold" then tPLAYER.Gold = tPLAYER.Gold + tITEMS[i].Value addcommentary("255215000You gained "..tITEMS[i].Value.." gold coins") table.remove(tITEMS, i) else table.insert(tINVENTORY, deepcopy(tITEMS[i])) check = checkinventory() if check == "OK" then addcommentary("255215000"..tITEMS[i].Name.." picked up") table.remove(tITEMS, i) else table.remove(tINVENTORY) addfloatytext(check, tPLAYER.X, tPLAYER.Y) end end end end end end function readitems() local i = 0 if love.filesystem.getInfo("data/items.txt", "file") then for line in love.filesystem.lines("data/items.txt") do if string.find(line, "Name=") then i = i + 1 tTEMPLATES[i] = {} tTEMPLATES[i].Name = string.sub(line,6) tTEMPLATES[i].Min = 0 tTEMPLATES[i].Max = 0 tTEMPLATES[i].Ranged = false tTEMPLATES[i].Ammo = "None" tTEMPLATES[i].ExtraCost = 0 tTEMPLATES[i].Weight = 0 elseif string.find(line, "Type=") then tTEMPLATES[i].Type = string.sub(line,6) elseif string.find(line, "Min=") then tTEMPLATES[i].Min = tonumber(string.sub(line,5)) elseif string.find(line, "Max=") then tTEMPLATES[i].Max = tonumber(string.sub(line,5)) elseif string.find(line, "Ranged") then tTEMPLATES[i].Ranged = true elseif string.find(line, "Ammo=") then tTEMPLATES[i].Ammo = string.sub(line,6) elseif string.find(line, "ExtraCost=") then tTEMPLATES[i].ExtraCost = tonumber(string.sub(line,11)) elseif string.find(line, "Weight=") then tTEMPLATES[i].Weight = tonumber(string.sub(line,8)) else end end end addcommentary("120120120Items loaded") end function readcreatures() local i = 0 if love.filesystem.getInfo("data/monsters.txt", "file") then for line in love.filesystem.lines("data/monsters.txt") do if string.find(line, "Name=") then i = i + 1 tCREATURES[i] = {} tCREATURES[i].Name = string.sub(line,6) tCREATURES[i].Family = "None" tCREATURES[i].Min = 0 tCREATURES[i].MinGR = 0 tCREATURES[i].Max = 1 tCREATURES[i].MaxGR = 0 tCREATURES[i].Ranged = false tCREATURES[i].Ammo = "None" tCREATURES[i].DMGType = "Physical" tCREATURES[i].MOVSpeed = 100 tCREATURES[i].ATKSpeed = 100 tCREATURES[i].Life = 1 tCREATURES[i].LifeGR = 1 tCREATURES[i].Armour = 0 tCREATURES[i].ArmourGR = 0 tCREATURES[i].AttackBonus = 1 tCREATURES[i].AttackGR = 1 tCREATURES[i].Special = "None" tCREATURES[i].SpecialCH = 0 tCREATURES[i].Magic = 100 tCREATURES[i].Fire = 100 tCREATURES[i].Ice = 100 tCREATURES[i].Poison = 100 tCREATURES[i].Earshot = 5 tCREATURES[i].From = 0 tCREATURES[i].To = 1000 tCREATURES[i].Group = 10 elseif string.find(line, "Family=") then tCREATURES[i].Family=string.sub(line,8) elseif string.find(line, "Min=") then tCREATURES[i].Min=tonumber(string.sub(line,5)) elseif string.find(line, "MinGR=") then tCREATURES[i].MinGR=tonumber(string.sub(line,7)) elseif string.find(line, "Max=") then tCREATURES[i].Max=tonumber(string.sub(line,5)) elseif string.find(line, "MaxGR=") then tCREATURES[i].MaxGR=tonumber(string.sub(line,7)) elseif string.find(line, "Ranged") then tCREATURES[i].Ranged=true elseif string.find(line, "Ammo=") then tCREATURES[i].Ammo=string.sub(line,6) elseif string.find(line, "DMGType=") then tCREATURES[i].DMGType=string.sub(line,9) elseif string.find(line, "MOVSpeed=") then tCREATURES[i].MOVSpeed=tonumber(string.sub(line,10)) elseif string.find(line, "ATKSpeed=") then tCREATURES[i].ATKSpeed=tonumber(string.sub(line,10)) elseif string.find(line, "Life=") then tCREATURES[i].Life=tonumber(string.sub(line,6)) elseif string.find(line, "LifeGR=") then tCREATURES[i].LifeGR=tonumber(string.sub(line,8)) elseif string.find(line, "Attack=") then tCREATURES[i].AttackBonus=tonumber(string.sub(line,8)) elseif string.find(line, "AttackGR=") then tCREATURES[i].AttackGR=tonumber(string.sub(line,10)) elseif string.find(line, "Armour=") then tCREATURES[i].Armour=tonumber(string.sub(line,8)) elseif string.find(line, "ArmourGR=") then tCREATURES[i].ArmourGR=tonumber(string.sub(line,10)) elseif string.find(line, "Special=") then tCREATURES[i].Special=string.sub(line,9) elseif string.find(line, "Chance=") then tCREATURES[i].SpecialCH=tonumber(string.sub(line,8)) elseif string.find(line, "Magic=") then tCREATURES[i].Magic=tonumber(string.sub(line,7)) elseif string.find(line, "Fire=") then tCREATURES[i].Fire=tonumber(string.sub(line,6)) elseif string.find(line, "Ice=") then tCREATURES[i].Ice=tonumber(string.sub(line,5)) elseif string.find(line, "Poison=") then tCREATURES[i].Poison=tonumber(string.sub(line,8)) elseif string.find(line, "Earshot=") then tCREATURES[i].Earshot=tonumber(string.sub(line,9)) elseif string.find(line, "From=") then tCREATURES[i].From=tonumber(string.sub(line,6)) elseif string.find(line, "To=") then tCREATURES[i].To=tonumber(string.sub(line,4)) elseif string.find(line, "Group=") then tCREATURES[i].Group=tonumber(string.sub(line,7)) else end end end addcommentary("120120120Monsters loaded") end function readclasses() local i if love.filesystem.getInfo("data/itemclasses.txt", "file") then i = 0 for line in love.filesystem.lines("data/itemclasses.txt") do if string.find(line, "Class=") then i = i + 1 tITEMCLASS[i] = {} tITEMCLASS[i].Class = string.sub(line,7) tITEMCLASS[i].Threshold = 0 tITEMCLASS[i].R = 255 tITEMCLASS[i].G = 255 tITEMCLASS[i].B = 255 elseif string.find(line, "Threshold=") then tITEMCLASS[i].Threshold = tonumber(string.sub(line,11)) elseif string.find(line, "R=") then tITEMCLASS[i].R = tonumber(string.sub(line,3)) elseif string.find(line, "G=") then tITEMCLASS[i].G = tonumber(string.sub(line,3)) elseif string.find(line, "B=") then tITEMCLASS[i].B = tonumber(string.sub(line,3)) else end end end if love.filesystem.getInfo("data/monsterclasses.txt", "file") then i = 0 for line in love.filesystem.lines("data/monsterclasses.txt") do if string.find(line, "Class=") then i = i + 1 tMONSTERCLASS[i] = {} tMONSTERCLASS[i].Class = string.sub(line,7) tMONSTERCLASS[i].Threshold = 0 elseif string.find(line, "Threshold=") then tMONSTERCLASS[i].Threshold = tonumber(string.sub(line,11)) elseif string.find(line, "R=") then tMONSTERCLASS[i].R = tonumber(string.sub(line,3)) elseif string.find(line, "G=") then tMONSTERCLASS[i].G = tonumber(string.sub(line, 3)) elseif string.find(line, "B=") then tMONSTERCLASS[i].B = tonumber(string.sub(line, 3)) else end end end end function readspells() local i, j, new if love.filesystem.getInfo("data/spells.txt", "file") then i = 0 for line in love.filesystem.lines("data/spells.txt") do if string.find(line,"Name=") then i = i + 1 tSPELLS[i] = {} tSPELLS[i].Name = string.sub(line,6) tSPELLS[i].Image = love.graphics.newImage("spells/"..tSPELLS[i].Name..".png") tSPELLS[i].School = "None" tSPELLS[i].Level = 1 tSPELLS[i].Description = "None" tSPELLS[i].Cost = 10 tSPELLS[i].Duration = 1 elseif string.find(line,"School=") then tSPELLS[i].School=string.sub(line,8) elseif string.find(line,"Level=") then tSPELLS[i].Level=tonumber(string.sub(line,7)) elseif string.find(line,"Description=") then tSPELLS[i].Description=string.sub(line,13) elseif string.find(line,"Cost=") then tSPELLS[i].Cost=tonumber(string.sub(line,6)) elseif string.find(line,"Duration=") then tSPELLS[i].Duration=tonumber(string.sub(line,10)) else end end end if love.filesystem.getInfo("data/spellschools.txt", "file") then i = 0 for line in love.filesystem.lines("data/spellschools.txt") do if string.find(line,"Name=") then i = i + 1 tSCHOOLS[i] = {} tSCHOOLS[i].Name = string.sub(line,6) tSCHOOLS[i].Image = love.graphics.newImage("spells/"..tSCHOOLS[i].Name..".png") tSCHOOLS[i].R = 255 tSCHOOLS[i].G = 255 tSCHOOLS[i].B = 255 elseif string.find(line,"R=") then tSCHOOLS[i].R=tonumber(string.sub(line,3)) elseif string.find(line,"G=") then tSCHOOLS[i].G=tonumber(string.sub(line,3)) elseif string.find(line,"B=") then tSCHOOLS[i].B=tonumber(string.sub(line,3)) else end end end end function getmaxhealth() local h = tPLAYER.MaxHealth local i if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Iron Fist" and tPLAYER.Effects[i].Active == true then h = h * 0.8 end if tPLAYER.Effects[i].Name == "Juggernaut" and tPLAYER.Effects[i].Active == true then h = h * 0.6 end end for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Aid" and tPLAYER.Effects[i].Active == true then h = h + 10 end end end return h end function gethealth() local h = getmaxhealth() local i h = h - tPLAYER.Wounds return h end function gethealthcount() local c = (gFPS*22)*math.exp(-0.1*getcon()) if tPLAYER.Resting == true then c = c / 5 end return math.floor(c) end function getmana() local m = tPLAYER.MaxMana m = m - tPLAYER.UsedMana return m end function getmanacount() local c = (gFPS*22)*math.exp(-0.1*getint()) if tPLAYER.Resting == true then c = c / 5 end return math.floor(c) end function getarmour() local a = math.floor((getdex() - 10)/2) local i for i = 1, 8, 1 do if tEQUIPPED[i] ~= nil then if tEQUIPPED[i].AC ~= nil then a = a + tEQUIPPED[i].AC end end end if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Shadow Armour" and tPLAYER.Effects[i].Active == true then a = a + 2 end if tPLAYER.Effects[i].Name == "Dragon's Bane" and tPLAYER.Effects[i].Active == true and gTARGET_MONSTER ~= nil then if gTARGET_MONSTER.Name == "Dragon" then a = a + 10 end end end end a = math.min(a,50) return a end function getmindmg() local i local d = 0 if tEQUIPPED[4] ~= nil then if tEQUIPPED[4].MinDMG ~= nil then d = tEQUIPPED[4].MinDMG end end d = d * (1+((getstr()-10)/10)) if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Iron Fist" and tPLAYER.Effects[i].Active == true then d = d * 1.1 end if tPLAYER.Effects[i].Name == "Juggernaut" and tPLAYER.Effects[i].Active == true then d = d * 1.25 end if tPLAYER.Effects[i].Name == "Double Attack" and tPLAYER.Effects[i].Active == true then d = d * 2 end end for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Bless" and tPLAYER.Effects[i].Active == true then d = d + 1 end if tPLAYER.Effects[i].Name == "Dragon's Bane" and tPLAYER.Effects[i].Active == true and gTARGET_MONSTER ~= nil then if gTARGET_MONSTER.Name == "Dragon" then d = d + 25 end end end end return math.floor(d) end function getmaxdmg() local i local d = 0 if tEQUIPPED[4] ~= nil then if tEQUIPPED[4].MaxDMG ~= nil then d = tEQUIPPED[4].MaxDMG end end d = d * (1+((getstr()-10)/10)) if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Iron Fist" and tPLAYER.Effects[i].Active == true then d = d * 1.1 end if tPLAYER.Effects[i].Name == "Juggernaut" and tPLAYER.Effects[i].Active == true then d = d * 1.2 end if tPLAYER.Effects[i].Name == "Double Attack" and tPLAYER.Effects[i].Active == true then d = d * 2 end end for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Bless" and tPLAYER.Effects[i].Active == true then d = d + 1 end if tPLAYER.Effects[i].Name == "Dragon's Bane" and tPLAYER.Effects[i].Active == true and gTARGET_MONSTER ~= nil then if gTARGET_MONSTER.Name == "Dragon" then d = d + 25 end end end end return math.floor(d) end function getbonusdmg() local d = 0 d = d + getmagicdmg() d = d + getfiredmg() d = d + geticedmg() d = d + getvampdmg() d = d + getpoisdmg() return d end function getmagicdmg() local d = 0 local i if tEQUIPPED[4] ~= nil then d = d + tEQUIPPED[4].Magic if string.find(tEQUIPPED[4].Name,"Wand") or string.find(tEQUIPPED[4].Name,"Sceptre") then d = d * (1+((getint()-10)/10)) end end if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Iron Fist" and tPLAYER.Effects[i].Active == true then d = d * 1.1 end if tPLAYER.Effects[i].Name == "Juggernaut" and tPLAYER.Effects[i].Active == true then d = d * 1.2 end if tPLAYER.Effects[i].Name == "Double Attack" and tPLAYER.Effects[i].Active == true then d = d * 2 end end end return math.floor(d) end function getfiredmg() local d = 0 local i if tEQUIPPED[4] ~= nil then d = d + tEQUIPPED[4].Fire end if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Iron Fist" and tPLAYER.Effects[i].Active == true then d = d * 1.1 end if tPLAYER.Effects[i].Name == "Juggernaut" and tPLAYER.Effects[i].Active == true then d = d * 1.2 end if tPLAYER.Effects[i].Name == "Double Attack" and tPLAYER.Effects[i].Active == true then d = d * 2 end end end return math.floor(d) end function geticedmg() local d = 0 local i if tEQUIPPED[4] ~= nil then d = d + tEQUIPPED[4].Ice end if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Iron Fist" and tPLAYER.Effects[i].Active == true then d = d * 1.1 end if tPLAYER.Effects[i].Name == "Juggernaut" and tPLAYER.Effects[i].Active == true then d = d * 1.2 end if tPLAYER.Effects[i].Name == "Double Attack" and tPLAYER.Effects[i].Active == true then d = d * 2 end end end return math.floor(d) end function getvampdmg() local d = 0 local i if tEQUIPPED[4] ~= nil then d = d + tEQUIPPED[4].Vampire end if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Iron Fist" and tPLAYER.Effects[i].Active == true then d = d * 1.1 end if tPLAYER.Effects[i].Name == "Juggernaut" and tPLAYER.Effects[i].Active == true then d = d * 1.2 end if tPLAYER.Effects[i].Name == "Double Attack" and tPLAYER.Effects[i].Active == true then d = d * 2 end end end return math.floor(d) end function getpoisdmg() local d = 0 local i if tEQUIPPED[4] ~= nil then d = d + tEQUIPPED[4].Poison end if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Iron Fist" and tPLAYER.Effects[i].Active == true then d = d * 1.1 end if tPLAYER.Effects[i].Name == "Juggernaut" and tPLAYER.Effects[i].Active == true then d = d * 1.2 end if tPLAYER.Effects[i].Name == "Double Attack" and tPLAYER.Effects[i].Active == true then d = d * 2 end end for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Poison Tip" and tPLAYER.Effects[i].Active == true then d = d + 2 end end end return math.floor(d) end function getmagicres() local r = 0 local i for i = 1, 8, 1 do if tEQUIPPED[i] ~= nil and i ~= 4 then r = r + (tEQUIPPED[i].Magic*2) end end if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Lesser Magic Shield" and tPLAYER.Effects[i].Active == true then r = r + 25 end if tPLAYER.Effects[i].Name == "Greater Magic Shield" and tPLAYER.Effects[i].Active == true then r = r + 50 end if tPLAYER.Effects[i].Name == "Immunity to Magic" and tPLAYER.Effects[i].Active == true then r = r + 100 end end end r = r + getcon() - 10 r = math.max(r, 0) return math.floor(r) end function getfireres() local r = 0 local i for i = 1, 8, 1 do if tEQUIPPED[i] ~= nil and i ~= 4 then r = r + (tEQUIPPED[i].Fire*2) end end if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Lesser Fire Shield" and tPLAYER.Effects[i].Active == true then r = r + 25 end if tPLAYER.Effects[i].Name == "Greater Fire Shield" and tPLAYER.Effects[i].Active == true then r = r + 50 end if tPLAYER.Effects[i].Name == "Immunity to Fire" and tPLAYER.Effects[i].Active == true then r = r + 100 end end end r = r + getcon() - 10 r = math.max(r, 0) return math.floor(r) end function geticeres() local r = 0 local i for i = 1, 8, 1 do if tEQUIPPED[i] ~= nil and i ~= 4 then r = r + (tEQUIPPED[i].Ice*2) end end if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Lesser Ice Shield" and tPLAYER.Effects[i].Active == true then r = r + 25 end if tPLAYER.Effects[i].Name == "Greater Ice Shield" and tPLAYER.Effects[i].Active == true then r = r + 50 end if tPLAYER.Effects[i].Name == "Immunity to Ice" and tPLAYER.Effects[i].Active == true then r = r + 100 end end end r = r + getcon() - 10 r = math.max(r, 0) return math.floor(r) end function getpoisres() local r = 0 local i for i = 1, 8, 1 do if tEQUIPPED[i] ~= nil and i ~= 4 then r = r + (tEQUIPPED[i].Poison*2) end end if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Lesser Poison Shield" and tPLAYER.Effects[i].Active == true then r = r + 25 end if tPLAYER.Effects[i].Name == "Greater Poison Shield" and tPLAYER.Effects[i].Active == true then r = r + 50 end if tPLAYER.Effects[i].Name == "Immunity to Poison" and tPLAYER.Effects[i].Active == true then r = r + 100 end end end r = r + getcon() - 10 r = math.max(r, 0) return math.floor(r) end function getcarriednumber() local carried = 0 if next(tINVENTORY) ~= nil then carried = carried + #tINVENTORY end return carried end function getcarriedweight() local i local weight = 0 for i = 1, 8, 1 do if tEQUIPPED[i] ~= nil then if tEQUIPPED[i].Weight ~= nil then weight = weight + tEQUIPPED[i].Weight end end end if next(tINVENTORY) ~= nil then for i = 1, #tINVENTORY, 1 do if tINVENTORY[i].Weight ~= nil then weight = weight + tINVENTORY[i].Weight end end end return weight end function getmaxweight() return 100*(getstr()/10) end function getstr() local i local str = tPLAYER.STR for i = 1, 8, 1 do if tEQUIPPED[i] ~= nil then if tEQUIPPED[i].BonusSTR ~= nil then str = str + tEQUIPPED[i].BonusSTR end end end if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Bull's Strength" and tPLAYER.Effects[i].Active == true then str = 18 end end end return str end function getdex() local i local dex = tPLAYER.DEX for i = 1, 8, 1 do if tEQUIPPED[i] ~= nil then if tEQUIPPED[i].BonusDEX ~= nil then dex = dex + tEQUIPPED[i].BonusDEX end end end if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Cat's Grace" and tPLAYER.Effects[i].Active == true then dex = 18 end end end return dex end function getcon() local i local con = tPLAYER.CON for i = 1, 8, 1 do if tEQUIPPED[i] ~= nil then if tEQUIPPED[i].BonusCON ~= nil then con = con + tEQUIPPED[i].BonusCON end end end if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Dog's Endurance" and tPLAYER.Effects[i].Active == true then con = 18 end end end return con end function getint() local i local int = tPLAYER.INT for i = 1, 8, 1 do if tEQUIPPED[i] ~= nil then if tEQUIPPED[i].BonusINT ~= nil then int = int + tEQUIPPED[i].BonusINT end end end if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Fox's Cunning" and tPLAYER.Effects[i].Active == true then int = 18 end end end return int end function getattackbonus() local a = tPLAYER.Level local i a = a + math.ceil((getstr()-11)/2) if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Bless" and tPLAYER.Effects[i].Active == true then a = a + 1 end if tPLAYER.Effects[i].Name == "Aid" and tPLAYER.Effects[i].Active == true then a = a + 2 end end end return a end function getsight() local i local sight = tPLAYER.SightRange for i = 1, 8, 1 do if tEQUIPPED[i] ~= nil then if tEQUIPPED[i].Sight ~= nil then sight = sight + tEQUIPPED[i].Sight end end end if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Illuminate" and tPLAYER.Effects[i].Active == true then sight = sight + 2 end end end sight = math.min(sight,5) return sight end function getregen() local i local r = 0 for i = 1, 8, 1 do if tEQUIPPED[i] ~= nil then if tEQUIPPED[i].Regenerate ~= nil then r = r + tEQUIPPED[i].Regenerate end end end if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Lesser Regeneration" and tPLAYER.Effects[i].Active == true then r = r + 60 end if tPLAYER.Effects[i].Name == "Greater Regeneration" and tPLAYER.Effects[i].Active == true then r = r + 120 end end end return r end function getweaponspeed() local s = (gFPS*1.66)*math.exp(-0.05*getdex()) + (gFPS/2) local i if next(tPLAYER.Effects) ~= nil then for i = 1, #tPLAYER.Effects, 1 do if tPLAYER.Effects[i].Name == "Haste" and tPLAYER.Effects[i].Active == true then s = s / 2 end end end return math.floor(s) end function getmaxspelllevel(school) local l = 0 local i if next(tSPELLS) ~= nil then for i = 1, #tSPELLS, 1 do if tSPELLS[i].School == school and tSPELLS[i].Level > l then l = tSPELLS[i].Level end end end return l end function getspellsbylevel(school,level) local n = 0 local i if next(tSPELLS) ~= nil then for i = 1, #tSPELLS, 1 do if tSPELLS[i].School == school and tSPELLS[i].Level == level then n = n + 1 end end end return n end function getinvitem(name) local i local n = 0 if next(tINVENTORY) ~= nil then for i = 1, #tINVENTORY, 1 do if tINVENTORY[i].Name == name then n = i end end end return n end function addfloatytext(text, x, y) entry = {} entry.Text = text entry.X = x entry.Y = y entry.Timer = gFLOAT_TIMER table.insert(tTEXT, entry) end function addcommentary(text) table.insert(sCOMMENTARY, text) if gCOMMENTARY == #sCOMMENTARY - 1 then gCOMMENTARY = #sCOMMENTARY end end function getbaseitem(basename) local i local item = {} if next(tTEMPLATES) ~= nil then for i = 1, #tTEMPLATES, 1 do if tTEMPLATES[i].Name == basename then item.Name = tTEMPLATES[i].Name item.Base = tTEMPLATES[i].Name item.Type = tTEMPLATES[i].Type item.Ranged = tTEMPLATES[i].Ranged item.Ammo = tTEMPLATES[i].Ammo item.ExtraCost = tTEMPLATES[i].ExtraCost item.Weight = tTEMPLATES[i].Weight item.Image = love.graphics.newImage("items/"..item.Base..".png") item.MinDMG = 0 item.MaxDMG = 0 item.Magic = 0 item.Fire = 0 item.Ice = 0 item.BonusSTR = 0 item.BonusDEX = 0 item.BonusCON = 0 item.BonusINT = 0 item.Vampire = 0 item.Poison = 0 item.Regenerate = 0 if item.Name == "Torch" then item.Sight = 1.5 else item.Sight = 0 end item.Class = "None" if item.Type == "Helmet" or item.Type == "Armour" or item.Type == "Shield" or item.Type == "Boots" or item.Type == "Gloves" then item.AC = math.random(tTEMPLATES[i].Min, tTEMPLATES[i].Max) else item.AC = 0 end if item.Type == "Weapon" then if (string.find(item.Name,"Wand") or string.find(item.Name,"Sceptre")) then item.Magic = math.random(tTEMPLATES[i].Min, tTEMPLATES[i].Max) else item.MinDMG = tTEMPLATES[i].Min item.MaxDMG = tTEMPLATES[i].Max end end item.Value = valueitem(item) end end end return item end function createrandomitem(x, y) local i local item = {} if next(tTEMPLATES) ~= nil then i = math.random(#tTEMPLATES) item = getbaseitem(tTEMPLATES[i].Name) item.X = x item.Y = y end return item end function createspecialitem(name,x,y,gold) local item = {} local i item.X = x item.Y = y item.Image = love.graphics.newImage("items/"..name..".png") item.Name = name item.Base = name item.Sight = 0 item.Ranged = false item.MinDMG = 0 item.MaxDMG = 0 item.AC = 0 item.Magic = 0 item.Fire = 0 item.Ice = 0 item.BonusSTR = 0 item.BonusDEX = 0 item.BonusCON = 0 item.BonusINT = 0 item.Vampire = 0 item.Poison = 0 item.Regenerate = 0 if string.find(name, "Tome") then item.Value = 500 item.ExtraCost = 500 item.Type = "Tome" item.Class = "Usable Item" item.Weight = 1 elseif name == "Gold" then item.Value = gold item.ExtraCost = gold item.Name = tostring(gold).." Gold" item.Type = "Gold" item.Class = "Treasure" item.Weight = 0 elseif string.find(name, "Potion") then item.Value = 100 item.ExtraCost = 100 item.Type = "Potion" item.Class = "Usable Item" item.Weight = 1 elseif name == "Torch" then item.Value = 0 item.ExtraCost = 0 item.Type = "Shield" item.Class = "Common" item.Sight = 1 item.Weight = 1 elseif name == "Resurrection Stone" then item.Value = ((tPLAYER.Resurrection + 1) ^ 2) * 100 item.ExtraCost = ((tPLAYER.Resurrection + 1) ^ 2) * 100 item.Type = "Resurrection Stone" item.Class = "Legendary" item.Weight = 1 else end return item end function addbonus(item) local b = math.random(11) if b == 1 then item.BonusSTR = item.BonusSTR + math.random(5) elseif b == 2 then item.BonusDEX = item.BonusDEX + math.random(5) elseif b == 3 then item.BonusCON = item.BonusCON + math.random(5) elseif b == 4 then item.BonusINT = item.BonusINT + math.random(5) elseif b == 5 and item.Ranged == false then item.Magic = item.Magic + math.random(5) elseif b == 6 and item.Ranged == false then item.Fire = item.Fire + math.random(5) elseif b == 7 and item.Ranged == false then item.Ice = item.Ice + math.random(5) elseif b == 8 and item.Type == "Weapon" and item.Ranged == false then item.Vampire = item.Vampire + 1 elseif b == 9 and item.Type == "Weapon" and item.Ranged == false then item.Poison = item.Poison + 1 elseif b == 10 then item.Regenerate = item.Regenerate + 1 elseif b == 11 then item.Sight = item.Sight + 0.5 else end end function valueitem(item) local value = 0 local i local wand = false local DMG = (item.MinDMG + item.MaxDMG) / 2 if (string.find(item.Type, "Wand") or string.find(item.Type, "Sceptre")) then wand = true end value = value + ((DMG * 10) ^ 1.05) value = value + ((item.AC * 15) ^ 1.2) if item.Magic > 0 then if wand == false then value = value + 100 end value = value + ((item.Magic * 12) ^ 1.15) end if item.Fire > 0 then value = value + 150 + ((item.Fire * 12) ^ 1.15) end if item.Ice > 0 then value = value + 150 + ((item.Ice * 12) ^ 1.15) end value = value + ((item.BonusSTR * 100) ^ 1.2) value = value + ((item.BonusDEX * 100) ^ 1.2) value = value + ((item.BonusCON * 100) ^ 1.2) value = value + ((item.BonusINT * 100) ^ 1.2) if item.Vampire > 0 then value = value + 250 + ((item.Vampire * 125) ^ 1.2) end if item.Poison > 0 then value = value + 200 + ((item.Poison * 100) ^ 1.2) end if item.Regenerate > 0 then value = value + 500 + ((item.Regenerate * 250) ^ 1.2) end if item.Sight > 0 then value = value + 50 + ((item.Sight * 50) ^ 1.2) end value = value + item.ExtraCost if next(tITEMCLASS) ~= nil then for i = 1, #tITEMCLASS, 1 do if value >= tITEMCLASS[i].Threshold then item.Class = tITEMCLASS[i].Class end end end if item.Ranged == true then value = value * 1.5 end if item.Name == "Torch" then value = 0 end return math.floor(value + 0.5) end function nameitem(item) local s if item.Base ~= nil then s = item.Base if item.Regenerate>=1 then s="Regenerating "..s end if item.Poison>=1 then s="Poisonous "..s end if item.Vampire>=1 then s="Vampiric "..s end if item.BonusINT>=1 and item.BonusINT<=5 then s="Adept "..s elseif item.BonusINT>=6 and item.BonusINT<=10 then s="Clever "..s elseif item.BonusINT>=11 and item.BonusINT<=15 then s="Astute "..s elseif item.BonusINT>=16 and item.BonusINT<=20 then s="Brilliant "..s elseif item.BonusINT>=21 then s="Expert "..s else end if item.BonusCON>=1 and item.BonusCON<=5 then s="Hearty "..s elseif item.BonusCON>=6 and item.BonusCON<=10 then s="Zesty "..s elseif item.BonusCON>=11 and item.BonusCON<=15 then s="Healthy "..s elseif item.BonusCON>=16 and item.BonusCON<=20 then s="Vigorous "..s elseif item.BonusCON>=21 then s="Flourishing "..s else end if item.BonusDEX>=1 and item.BonusDEX<=5 then s="Deft "..s elseif item.BonusDEX>=6 and item.BonusDEX<=10 then s="Skilful "..s elseif item.BonusDEX>=11 and item.BonusDEX<=15 then s="Nimble "..s elseif item.BonusDEX>=16 and item.BonusDEX<=20 then s="Agile "..s elseif item.BonusDEX>=21 then s="Dextrous "..s else end if item.BonusSTR>=1 and item.BonusSTR<=5 then s="Strong "..s elseif item.BonusSTR>=6 and item.BonusSTR<=10 then s="Mighty "..s elseif item.BonusSTR>=11 and item.BonusSTR<=15 then s="Powerful "..s elseif item.BonusSTR>=16 and item.BonusSTR<=20 then s="Giant's "..s elseif item.BonusSTR>=21 then s="Titan's "..s else end if item.Sight==0.5 then s="Perceiving "..s elseif item.Sight==1 then s="Visible "..s elseif item.Sight==1.5 then s="Seeing "..s elseif item.Sight==2 then s="Vision "..s elseif item.Sight>=2.5 then s="Farseeing "..s else end if item.Fire>=1 then s=s.." of " end if item.Fire>=1 and item.Fire<=5 then s=s.."Ember" elseif item.Fire>=6 and item.Fire<=10 then s=s.."Sparks" elseif item.Fire>=11 and item.Fire<=15 then s=s.."Flame" elseif item.Fire>=16 and item.Fire<=20 then s=s.."Burning" elseif item.Fire>=21 then s=s.."Fire" else end if item.Fire>=1 and item.Ice>=1 and item.Magic>=1 then s=s..", " elseif item.Fire>=1 and item.Ice>=1 then s=s.." and " elseif item.Ice>=1 then s=s.." of " else end if item.Ice>=1 and item.Ice<=5 then s=s.."Cold" elseif item.Ice>=6 and item.Ice<=10 then s=s.."Frost" elseif item.Ice>=11 and item.Ice<=15 then s=s.."Chilling" elseif item.Ice>=16 and item.Ice<=20 then s=s.."Ice" elseif item.Ice>=21 then s=s.."Freezing" else end if (item.Ice>=1 or item.Fire>=1) and item.Magic>=1 then s=s.." and " elseif item.Magic>=1 then s=s.." of " else end if item.Magic>=1 and item.Magic<=5 then s=s.."Spells" elseif item.Magic>=6 and item.Magic<=10 then s=s.."Magic" elseif item.Magic>=11 and item.Magic<=15 then s=s.."Sorcery" elseif item.Magic>=16 and item.Magic<=20 then s=s.."Wizardry" elseif item.Magic>=21 then s=s.."Power" else end end return s end function generateitems() local min, max local i tTREASURE = {} if gLEVEL>5 then min = math.floor((1.15^(gLEVEL-5))*gLOOT) else min = 0 end max = math.ceil((1.2^gLEVEL)*gLOOT) for i = 1, 1000, 1 do tTREASURE[i] = createrandomitem(0, 0) tTREASURE[i].Value = valueitem(tTREASURE[i]) while tTREASURE[i].Value < min do addbonus(tTREASURE[i]) tTREASURE[i].Value = valueitem(tTREASURE[i]) end tTREASURE[i].Name = nameitem(tTREASURE[i]) end for i = 1000, 1, -1 do if tTREASURE[i].Value > max then table.remove(tTREASURE, i) end end end function openchest() local i = math.random(100) local j, k local min, max if gLEVEL>5 then min = math.floor((1.15^(gLEVEL-5))*25*gWEALTH) else min = 1 end max=math.floor((1.15^gLEVEL)*25*gWEALTH) if next(tITEMS) ~= nil then k = #tITEMS+1 else k = 1 end if i <= (gDROPITEM*100) then if next(tTREASURE) ~= nil then j = math.random(#tTREASURE) tITEMS[k] = deepcopy(tTREASURE[j]) tITEMS[k].X = tPLAYER.X tITEMS[k].Y = tPLAYER.Y table.remove(tTREASURE, j) else addfloatytext("Empty Chest", tPLAYER.X, tPLAYER.Y) end elseif i>(gDROPITEM*100) and i<=((gDROPITEM+gDROPPOTION)*100) then if math.random(2)==1 then tITEMS[k] = createspecialitem("Health Potion",tPLAYER.X,tPLAYER.Y,0) else tITEMS[k] = createspecialitem("Mana Potion",tPLAYER.X,tPLAYER.Y,0) end elseif i>((gDROPITEM+gDROPPOTION)*100) and i<=((gDROPITEM+gDROPPOTION+gDROPBOOK)*100) then i = math.random(4) if i == 1 then tITEMS[k] = createspecialitem("Tome of Strength",tPLAYER.X,tPLAYER.Y,0) elseif i == 2 then tITEMS[k] = createspecialitem("Tome of Dexterity",tPLAYER.X,tPLAYER.Y,0) elseif i == 3 then tITEMS[k] = createspecialitem("Tome of Constitution",tPLAYER.X,tPLAYER.Y,0) else tITEMS[k] = createspecialitem("Tome of Intelligence",tPLAYER.X,tPLAYER.Y,0) end elseif i>((gDROPITEM+gDROPPOTION+gDROPBOOK)*100) and i<=((gDROPITEM+gDROPPOTION+gDROPBOOK+gDROPTORCH)*100) then tITEMS[k] = createspecialitem("Torch",tPLAYER.X,tPLAYER.Y,0) else tITEMS[k] = createspecialitem("Gold", tPLAYER.X, tPLAYER.Y, math.random(min, max)) end end function awardxp(level) local xp = level*gXP_AMOUNT local diff = level - tPLAYER.Level local mult diff = math.min(diff, 5) diff = math.max(diff, -5) if diff>=0 then mult = (10+diff)/10 else mult=(10+(1.8*diff))/10 end xp = math.floor(xp * mult) tPLAYER.XP = tPLAYER.XP + xp addcommentary("255215000You gain "..xp.." xp") addfloatytext(xp.."XP", tPLAYER.X, tPLAYER.Y) end function levelup() tPLAYER.Level = tPLAYER.Level + 1 tPLAYER.UnusedPoints = tPLAYER.UnusedPoints + 1 tPLAYER.MaxHealth = tPLAYER.MaxHealth + math.floor(tPLAYER.CON*gHEALTHGROWTH) tPLAYER.Wounds = 0 tPLAYER.MaxMana = tPLAYER.MaxMana + math.floor(tPLAYER.INT*gMANAGROWTH) tPLAYER.UsedMana = 0 addfloatytext("Level Up", tPLAYER.X, tPLAYER.Y) addcommentary("000255000You have gained a level of experience") addcommentary("255000000You gained "..tPLAYER.CON.." health") addcommentary("000150255You gained "..tPLAYER.INT.." mana") addcommentary("255215000Press C to use your "..tPLAYER.UnusedPoints.." ability points") end function playgamemusic() mTITLE:stop() mLEVEL:stop() mEND:stop() if gMUSICON == true then mLEVEL:play() end end function playtitlemusic() mTITLE:stop() mLEVEL:stop() mEND:stop() if gMUSICON == true then mTITLE:play() end end function playendmusic() mTITLE:stop() mLEVEL:stop() mEND:stop() if gMUSICON == true then mEND:play() end end function deepcopy(orig) local orig_type = type(orig) local copy if orig_type == 'table' then copy = {} for orig_key, orig_value in next, orig, nil do copy[deepcopy(orig_key)] = deepcopy(orig_value) end setmetatable(copy, deepcopy(getmetatable(orig))) else copy = orig end -- number, string, boolean, etc return copy end function getdiceroll(n, d) local i, r r = 0 for i = 1, n, 1 do r = r + math.random(d) end return r end