core.declare("inf_arena", {} )
--enemy scaling for each wave: note that game difficulty will modify scaling independently
local mob_scale_factor = 0.5
--customize min_lev/max_lev/weight of each enemy (defaults given)
--for names of beings, check Object IDs in the modding documentation
--be aware that JC auto-ends the game unless modified directly
local mobGenStats = {
{ being = "former", min_lev = 0, max_lev = 12, weight = 10 },
{ being = "sergeant", min_lev = 2, max_lev = 15, weight = 10 },
{ being = "captain", min_lev = 8, max_lev = 15, weight = 10 },
{ being = "imp", min_lev = 0, max_lev = 17, weight = 8 },
{ being = "demon", min_lev = 4, max_lev = 20, weight = 6 },
{ being = "lostsoul", min_lev = 6, max_lev = 16, weight = 10 },
{ being = "knight", min_lev = 9, max_lev = 15, weight = 6 },
{ being = "cacodemon", min_lev = 10, max_lev = 50, weight = 6 },
{ being = "commando", min_lev = 12, max_lev = 17, weight = 6 },
{ being = "pain", min_lev = 12, max_lev = 17, weight = 2 },
{ being = "baron", min_lev = 12, max_lev = 200, weight = 6 },
{ being = "arachno", min_lev = 13, max_lev = 50, weight = 4 },
{ being = "revenant", min_lev = 13, max_lev = 200, weight = 5 },
{ being = "mancubus", min_lev = 15, max_lev = 200, weight = 7 },
{ being = "arch", min_lev = 16, max_lev = 200, weight = 4 },
{ being = "nimp", min_lev = 30, max_lev = 60, weight = 8 },
{ being = "ndemon", min_lev = 40, max_lev = 200, weight = 6 },
{ being = "ncacodemon", min_lev = 51, max_lev = 200, weight = 6 },
{ being = "narachno", min_lev = 50, max_lev = 200, weight = 5 },
{ being = "narch", min_lev = 90, max_lev = 200, weight = 3 },
{ being = "bruiser", min_lev = 50, max_lev = 200, weight = 6 },
{ being = "lava_elemental", min_lev = 70, max_lev = 200, weight = 1 },
{ being = "shambler", min_lev = 80, max_lev = 200, weight = 3 },
{ being = "agony", min_lev = 80, max_lev = 200, weight = 1 },
{ being = "cyberdemon", min_lev = 80, max_lev = 200, weight = 1 },
{ being = "arenamaster", min_lev = 0, max_lev = 0, weight = 0 },
{ being = "angel", min_lev = 0, max_lev = 0, weight = 0 },
{ being = "jc", min_lev = 0, max_lev = 0, weight = 0 },
}
--item scaling for each wave
local item_scale_factor = 0.5
--customize level/weight of items (defaults given)
--for names of items, check Object IDs in the modding documentation
local itemGenStats = {
--Commons
--weapons
{ item = "knife", level = 1, weight = 640 },
{ item = "pistol", level = 1, weight = 70 },
{ item = "shotgun", level = 2, weight = 180 },
{ item = "ashotgun", level = 2, weight = 160 },
{ item = "dshotgun", level = 4, weight = 100 },
{ item = "chaingun", level = 5, weight = 200 },
{ item = "bazooka", level = 7, weight = 200 },
{ item = "plasma", level = 12, weight = 70 },
--ammo/ammo packs
{ item = "ammo", level = 1, weight = 500 },
{ item = "pammo", level = 3, weight = 700 },
{ item = "shell", level = 2, weight = 400 },
{ item = "pshell", level = 4, weight = 200 },
{ item = "rocket", level = 5, weight = 60 },
{ item = "procket", level = 7, weight = 60 },
{ item = "cell", level = 8, weight = 36 },
{ item = "pcell", level = 10, weight = 18 },
--armor/boots
{ item = "garmor", level = 1, weight = 400 },
{ item = "barmor", level = 4, weight = 240 },
{ item = "rarmor", level = 7, weight = 150 },
{ item = "sboots", level = 4, weight = 240 },
{ item = "pboots", level = 7, weight = 150 },
{ item = "psboots", level = 11, weight = 80 },
--consumables
{ item = "smed", level = 1, weight = 600 },
{ item = "lmed", level = 5, weight = 400 },
{ item = "phase", level = 5, weight = 200 },
{ item = "hphase", level = 7, weight = 100 },
{ item = "epack", level = 5, weight = 100 },
{ item = "nuke", level = 10, weight = 40 },
{ item = "lava_element", level = 23, weight = 0 },
{ item = "mod_power", level = 7, weight = 120 },
{ item = "mod_tech", level = 6, weight = 120 },
{ item = "mod_bulk", level = 6, weight = 120 },
{ item = "mod_agility", level = 5, weight = 120 },
--powerups
{ item = "shglobe", level = 1, weight = 900 },
{ item = "lhglobe", level = 6, weight = 330 },
{ item = "scglobe", level = 4, weight = 150 },
{ item = "bpack", level = 1, weight = 200 },
{ item = "iglobe", level = 7, weight = 200 },
{ item = "msglobe", level = 16, weight = 60 },
{ item = "map", level = 1, weight = 200 },
{ item = "pmap", level = 1, weight = 80 },
{ item = "ashard", level = 5, weight = 700 },
{ item = "backpack", level = 7, weight = 0 },
--Exotics
--weapons
{ item = "chainsaw", level = 12, weight = 3 },
{ item = "ublaster", level = 8, weight = 2 },
{ item = "ucpistol", level = 4, weight = 6 },
{ item = "uashotgun", level = 6, weight = 6 },
{ item = "upshotgun", level = 12, weight = 4 },
{ item = "udshotgun", level = 10, weight = 5 },
{ item = "uminigun", level = 10, weight = 6 },
{ item = "umbazooka", level = 10, weight = 6 },
{ item = "unapalm", level = 10, weight = 6 },
{ item = "ulaser", level = 12, weight = 5 },
{ item = "unplasma", level = 15, weight = 4 },
{ item = "utristar", level = 12, weight = 4 },
{ item = "bfg9000", level = 20, weight = 2 },
{ item = "unbfg9000", level = 22, weight = 2 },
{ item = "utrans", level = 14, weight = 3 },
--armor/boots
{ item = "uoarmor", level = 7, weight = 4 },
{ item = "uparmor", level = 10, weight = 6 },
{ item = "upboots", level = 8, weight = 6 },
{ item = "ugarmor", level = 15, weight = 6 },
{ item = "ugboots", level = 10, weight = 6 },
{ item = "umedarmor", level = 5, weight = 6 },
{ item = "uduelarmor", level = 5, weight = 6 },
{ item = "ubulletarmor", level = 2, weight = 4 },
{ item = "uballisticarmor", level = 2, weight = 5 },
{ item = "ueshieldarmor", level = 5, weight = 3 },
{ item = "uplasmashield", level = 10, weight = 3 },
{ item = "uenergyshield", level = 8, weight = 3 },
{ item = "ubalshield", level = 6, weight = 3 },
{ item = "uacidboots", level = 8, weight = 5 },
--consumables
{ item = "uswpack", level = 5, weight = 10 },
{ item = "ubskull", level = 5, weight = 8 },
{ item = "ufskull", level = 7, weight = 8 },
{ item = "uhskull", level = 9, weight = 8 },
{ item = "umod_firestorm", level = 10, weight = 4 },
{ item = "umod_sniper", level = 10, weight = 4 },
{ item = "umod_nano", level = 10, weight = 4 },
{ item = "umod_onyx", level = 10, weight = 4 },
--Uniques
--weapons
{ item = "ubutcher", level = 1, weight = 2 },
{ item = "spear", level = 16, weight = 0 },
{ item = "uscythe", level = 16, weight = 0 },
{ item = "udragon", level = 16, weight = 1 },
{ item = "utrigun", level = 8, weight = 2 },
{ item = "ujackal", level = 10, weight = 2 },
{ item = "uberetta", level = 6, weight = 3 },
{ item = "usjack", level = 12, weight = 2 },
{ item = "urbazooka", level = 12, weight = 2 },
{ item = "uacid", level = 12, weight = 3 },
{ item = "urailgun", level = 15, weight = 2 },
{ item = "ubfg10k", level = 20, weight = 1 },
--armor/boots
{ item = "umarmor", level = 15, weight = 3 },
{ item = "ucarmor", level = 10, weight = 2 },
{ item = "unarmor", level = 10, weight = 3 },
{ item = "umedparmor", level = 10, weight = 2 },
{ item = "ulavaarmor", level = 12, weight = 2 },
{ item = "uenviroboots", level = 10, weight = 2 },
{ item = "ushieldarmor", level = 10, weight = 2 },
{ item = "uberarmor", level = 10, weight = 1 },
{ item = "aarmor", level = 22, weight = 0 },
--consumables
{ item = "uhwpack", level = 10, weight = 4 },
{ item = "umodstaff", level = 15, weight = 4 },
{ item = "uarenastaff", level = 4, weight = 0 },
}
--changes the generation stats of enemies based on mobGenStats
for _,v in ipairs(mobGenStats) do
beings[v.being].min_lev = v.min_lev
beings[v.being].max_lev = v.max_lev
beings[v.being].weight = v.weight
end
--changes the generation stats of items based on itemGenStats
for _,v in ipairs(itemGenStats) do
items[v.item].level = v.level
items[v.item].weight = v.weight
end
--add your own announcer lines here
local anncrMsg = {
--displays whenever player completes wave
success = {
{
"The voice booms, \"Congratulations mortal!",
"The voice booms, \"Impressive mortal!",
"The voice booms, \"Most impressive.",
"The voice booms, \"You are a formidable warrior!",
},
{
"Each of your triumphs is a work of art!",
"Your ability to survive is incredible!",
"You've given us a great show!",
"You would make a terrific hell warrior!",
},
{
"But can you keep going?\"",
"How much longer can you go?\"",
"Will you fight with us a little more?\"",
"I can let you go now if you like, or...\"",
}
},
--displays whenever player decides to continue to another wave
choice = {
{
"The voice booms, \"I like it! Let the show go on!\"",
"The voice booms, \"Excellent! May the fight begin!!!\"",
},
{
"You hear screams everywhere! \"More Blood! More BLOOD!\"",
"You hear screams everywhere! \"Kill, Kill, KILL!\"",
}
}
}
--add your own crowd lines here
--displays whenever enemy is killed
local crowdMsg = {
"The crowd goes wild! \"BLOOD! BLOOD!\"",
"The crowd cheers! \"Blood! Blood!\"",
"The crowd cheers! \"Kill! Kill!\"",
"The crowd hisses. \"We came for a REAL fight!\"",
"The crowd boos. \"No skill, no kill!\"",
}
local function build_announcerMsg(MSG)
for _,msgNum in ipairs(MSG) do
ui.msg(table.random_pick(msgNum))
end
end
--from Skulltag Arena, credit goes to yaflhdztioxo
--initializes table of cells that contains only corpses
local corpseCells = {}
local function get_corpses()
for i = 1, #cells do
if cells[i] and cells[i].flags then
if cells[i].flag_set[CF_CORPSE] == true then
table.insert(corpseCells, i) --i == sID's numeric value
end
end
end
end
--removes corpses and blood-like cells
local function clear_corpses()
--fade away all blood
Generator.transmute("blood", "floor")
Generator.transmute("bloodpool", "blood")
--changes corpses to blood
for i = 1, #corpseCells do
Generator.transmute(corpseCells[i], "bloodpool")
end
end
--changes player equipment
--add "nil" for any slot that should be empty
--always refreshes all slots: do not use to change only one equipment slot
local function build_gear(weap,prep,body,foot)
player.eq:clear()
if weap then player.eq.weapon = item.new(weap) end --main weapon
if prep then player.eq.prepared = item.new(prep) end --prepared weapon
if body then player.eq.armor = item.new(body) end --body armor
if foot then player.eq.boots = item.new(foot) end --boots
end
--changes player inventory
--always refreshes all slots: do not use to change only one equipment slot
--[[
input is an array of tables with two fields:
-name is the identifier of the item that goes in the inventory
-amt is how many items should be added (or how many units of ammo)
example table (based on default inventory):
local starter_pack = {
{name = "ammo", amt = 24},
{name = "smed", amt = 2},
}
--]]
local function build_pack(itemPack)
player.inv:clear()
for _,part in ipairs(itemPack) do
if items[part.name].type == ITEMTYPE_AMMO then
--ammo is handled separately, loops for however many stacks are needed
for n=1,math.ceil(part.amt/items[part.name].ammomax) do
local pack = item.new(part.name)
if part.amt < pack.ammomax then
--remainder (or single) stack
pack.ammo = part.amt
else
--filled (and/or multiple) stacks
pack.ammo = pack.ammomax
part.amt = part.amt - pack.ammomax
end
player.inv:add(pack)
end
else
--loops for however many items are needed
for n=1,part.amt do
player.inv:add(part.name)
end
end
end
end
function inf_arena.OnEnter()
--inventory table used for build_pack()
local itemPack = {
{name = "smed", amt = 2},
{name = "shell", amt = 50},
}
--set up starting eq/inv
build_gear("shotgun","pistol",nil,nil)
build_pack(itemPack)
--Print announcer messages
ui.msg("A devilish voice announces: \"Welcome to Hell's Arena, mortal! " ..
"\"You are either very brave or very foolish. Either way I like it! " ..
"\"And so do the crowds!\" Suddenly you hear screams everywhere! " ..
"\"Blood! Blood! BLOOD!\" \"Kill all enemies and I shall reward thee!\"")
--spawn first wave
Level.flood_monsters(Generator.being_weight()*mob_scale_factor)
Level.result(1)
end
function inf_arena.OnKill(being)
--random message from crowdMsg array
ui.msg(table.random_pick(crowdMsg))
end
function inf_arena.OnKillAll()
--print more announcer stuff
if Level.result() == 1 then
ui.msg("The voice booms, \"Not bad mortal! For a weakling that you are, " ..
"you show some determination.\" You hear screams everywhere! " ..
"\"More Blood! More BLOOD!\" The voice continues, \"I can now " ..
"let you go free, or you may try to complete the challenge!\"")
elseif Level.result() == 2 then
ui.msg("The voice booms, \"Impressive mortal! Your determination to " ..
"survive makes me excited!\" You hear screams everywhere! " ..
"\"More Blood! More BLOOD!\" \"I can let you go now, and give you " ..
"a small reward, or you can choose to fight an additional challenge!\"")
else
--random message from anncrMsg.success array
build_announcerMsg(anncrMsg.success)
end
local choice = ui.msg_confirm("Round " .. Level.result() + 1 .. " awaits. " ..
"Do you want to continue the fight?")
if choice == true then --continuing
--random message from anncrMsg.choice array
build_announcerMsg(anncrMsg.choice)
--set up the danger level for the next wave
Level.result(Level.result() + 1);
Level.danger_level = Level.result();
--spawn items for next wave
Level.flood_items(Generator.item_amount()*item_scale_factor)
--spawn enemies for next wave
Level.flood_monsters(Generator.being_weight()*mob_scale_factor)
else --quitting
if Level.result() == 1 then
ui.msg("The voice booms, \"Coward!\" You hear screams everywhere! " ..
"\"Coward! Coward! COWARD!\"")
elseif Level.result() == 2 then
ui.msg("The voice booms, \"Too bad, you won't make it far then...!\" " ..
"You hear screams everywhere! \"Boooo...\"")
elseif Level.result() < 10 then
ui.msg("The voice booms, \"An impressive run, Mortal! We appreciate " ..
"it!\" The crowd starts to chant! \"Encore! Encore!\"")
else
ui.msg("\"Ladies and gentlemen, your champion, "
.. Player.get_name() .. ". He survived " .. Level.result() ..
" rounds in our arena! That has to be some sort of record. " ..
"Give him a hand folks!\" The crowd starts to chant your name " ..
"and they begin throwing items into the ring!")
Level.flood_items(Generator.item_weight())
end
end
end
function inf_arena.OnExit()
if Level.result() < 10 then
ui.msg("The voice laughs, \"Flee mortal, flee! There's no hiding in hell!\"")
else
ui.msg("The voice laughs, \"Remember to come back once you return to Hell " ..
"for the extended stay\"")
end
--used in .OnMortem()
inf_arena.result = "had enough of the gauntlet at wave "..Level.result()
end
function inf_arena.OnMortem()
local kill = player.killedby --calls kill descriptions from beings
if inf_arena.result then kill = inf_arena.result end
player:mortem_print( " "..player.name..", level "..player.explevel.." "
.." "..klasses[player.klass].name..", "..kill )
--e.g., "Cool Guy, level 1 Marine, had enough of the gauntlet at wave 8"
player:mortem_print(" in the Infinite Arena...")
end
--Creation of Infinite Arena
function inf_arena.run()
Level.name = "Infinite Arena"
Level.name_number = 0
Level.fill("rwall")
local translation = {
["."] = "floor",
["#"] = {"rwall", LFPERMANENT = true},
["X"] = "rwall",
[","] = "blood",
[">"] = "stairs",
}
local map = [[
#######################.............................########################
###########.....................................................############
#####..................................................................#####
##........................................................................##
#..........................................................................#
....,.......................................................................
.................................,...,......................................
.,.....................................,....................................
..,>.,..........................,...........................................
.,..,.................................,.,...................................
................................,..,...,....................................
............................................................................
............................................................................
#..........................................................................#
##........................................................................##
#####..................................................................#####
###########.....................................................############
#######################.............................########################
]]
--change up the column types
local column = {
[[
,..,.,
,XXXX.
.X##X,
.XXXX.
,..,.,
]],
[[
,..,.,
,X##X.
.####,
.X##X.
,..,.,
]],
[[
,..,.,
,####.
.####,
.####.
,..,.,
]]
}
Level.place_tile(translation,map,2,2)
for i=1,11 + math.random(4) do
Level.scatter_put( area.new(5,3,68,15), translation, table.random_pick(column), "floor", 1)
end
Level.scatter(area.FULL_SHRINKED, "floor", "blood", 100)
Level.player(38, 10)
end