From 024f0efa80f51e4f1dc876f76c0833f9a9e53845 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 25 Dec 2017 11:09:37 -0600 Subject: [PATCH 01/45] Add Equipment class to Player --- code/player/player.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/player/player.lua b/code/player/player.lua index 7b68b18..a5da1fd 100644 --- a/code/player/player.lua +++ b/code/player/player.lua @@ -4,6 +4,7 @@ local StatusEffect = require('code.player.status_effect.status_effect') local broadcastEvent = require('code.server.event') local catalogAvailableActions = require('code.player.catalog') local chanceToHit = require('code.player.chanceToHit') +local Equipment = require('code.player.equipment') local Player = class('Player') @@ -27,6 +28,7 @@ function Player:initialize(username, map_zone, y, x) --add account name self.ID = self self.log = Log:new() self.status_effect = StatusEffect:new(self) + self.equipment = Equipment:new(self) map_zone[y][x]:insert(self) end From 11331fa19a5ff55ce334c6ffb1b71f7172fc2b35 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 25 Dec 2017 11:12:10 -0600 Subject: [PATCH 02/45] Split items\equipment into machinery and tools This is to avoid confusion with the similiarly named 'equipment' class that is being built for the player. Former equipment items, are being renamed to machinery as a result. This lets the equipment variable name be associated solely with player equipment and not machinery. --- code/item/items.lua | 15 ++- code/item/items/machinery.lua | 121 +++++++++++++++++++ code/item/items/{equipment.lua => tools.lua} | 114 +---------------- 3 files changed, 132 insertions(+), 118 deletions(-) create mode 100644 code/item/items/machinery.lua rename code/item/items/{equipment.lua => tools.lua} (57%) diff --git a/code/item/items.lua b/code/item/items.lua index beedb17..d22fa23 100644 --- a/code/item/items.lua +++ b/code/item/items.lua @@ -1,19 +1,24 @@ local Crowbar, Bat, Sledge, Knife, Katanna = unpack(require('code.item.items.melee_weaponry')) local Pistol, Magnum, Shotgun, Rifle, Flare, Molotov = unpack(require('code.item.items.ranged_weaponry')) local FAK, Bandage, Syringe, Vaccine, Antidote = unpack(require('code.item.items.medical')) -local Generator, Transmitter, Terminal, Fuel, Barricade, Toolbox = unpack(require('code.item.items.equipment')) +local Generator, Transmitter, Terminal = unpack(require('code.item.items.machinery')) +local Fuel, Barricade, Toolbox = unpack(require('code.item.items.tools')) local Radio, GPS, Flashlight, Sampler = unpack(require('code.item.items.gadget')) local Book, Bottle, Newspaper = unpack(require('code.item.items.junk')) local Magazine, Shell, Clip, Quiver = unpack(require('code.item.items.ammo')) local Leather, Firesuit = unpack(require('code.item.items.armor')) local Items = { - -- WEAPONRY - Crowbar, Bat, Sledge, Knife, Katanna, Pistol, Magnum, Shotgun, Rifle, Flare, Molotov, + -- MELEE_WEAPONRY + Crowbar, Bat, Sledge, Knife, Katanna, + -- RANGED_WEAPONRY + Pistol, Magnum, Shotgun, Rifle, Flare, Molotov, -- MEDICAL FAK, Bandage, Syringe, Vaccine, Antidote, - -- EQUIPMENT - Generator, Transmitter, Terminal, Fuel, Barricade, Toolbox, + -- MACHINERY + Generator, Transmitter, Terminal, + -- TOOLS + Fuel, Barricade, Toolbox, -- GADGET Radio, GPS, Flashlight, Sampler, --'cellphone', 'sampler' -- JUNK diff --git a/code/item/items/machinery.lua b/code/item/items/machinery.lua new file mode 100644 index 0000000..815084d --- /dev/null +++ b/code/item/items/machinery.lua @@ -0,0 +1,121 @@ +local class = require('code.libs.middleclass') +local Item = require('code.item.item') +local broadcastEvent = require('code.server.event') +string.replace = require('code.libs.replace') +local dice = require('code.libs.dice') + +local Generator = class('Generator', Item) + +Generator.FULL_NAME = 'generator' +Generator.WEIGHT = 25 +Generator.DURABILITY = 0 +Generator.CATEGORY = 'engineering' +Generator.ap = {cost = 10, modifier = {tech = -2, power_tech = -4}} + +function Generator:client_criteria(player) + local p_tile = player:getTile() + assert(player:isStaged('inside'), 'Must be inside building to install generator') + assert(not p_tile.generator:isPresent(), 'There is no room for a second generator') +end + +Generator.server_criteria = Generator.client_criteria + +function Generator:activate(player) + local building_tile = player:getTile() + building_tile:insert('generator', self.condition) + + -------------------------------------------- + ----------- M E S S A G E -------------- + -------------------------------------------- + + local self_msg = 'You install a generator.' + local msg = '{player} installs a generator.' + msg = msg:replace(player) + + -------------------------------------------- + --------- B R O A D C A S T ------------ + -------------------------------------------- + + local event = {'generator', player} + player:broadcastEvent(msg, self_msg, event) +end + +------------------------------------------------------------------- + +local Transmitter = class('Transmitter', Item) + +Transmitter.FULL_NAME = 'transmitter' +Transmitter.WEIGHT = 25 +Transmitter.DURABILITY = 0 +Transmitter.CATEGORY = 'engineering' +Transmitter.ap = {cost = 10, modifier = {tech = -2, radio_tech = -4}} + +function Transmitter:client_criteria(player) + local p_tile = player:getTile() + assert(player:isStaged('inside'), 'Must be inside building to install transmitter') + assert(not p_tile.transmitter:isPresent(), 'There is no room for a second transmitter') +end + +Transmitter.server_criteria = Transmitter.client_criteria + +function Transmitter:activate(player) + local building_tile = player:getTile() + building_tile:insert('transmitter', self.condition) + + -------------------------------------------- + ----------- M E S S A G E -------------- + -------------------------------------------- + + local self_msg = 'You install a transmitter.' + local msg = '{player} installs a transmitter.' + msg = msg:replace(player) + + -------------------------------------------- + --------- B R O A D C A S T ------------ + -------------------------------------------- + + local event = {'transmitter', player} + player:broadcastEvent(msg, self_msg, event) +end + +------------------------------------------------------------------- + +local Terminal = class('Terminal', Item) + +Terminal.FULL_NAME = 'terminal' +Terminal.WEIGHT = 25 +Terminal.DURABILITY = 0 +Terminal.CATEGORY = 'engineering' +Terminal.ap = {cost = 10, modifier = {tech = -2, computer_tech = -4}} + +function Terminal:client_criteria(player) + local p_tile = player:getTile() + assert(player:isStaged('inside'), 'Must be inside building to install terminal') + assert(not p_tile.terminal:isPresent(), 'There is no room for a second terminal') +end + +Terminal.server_criteria = Terminal.client_criteria + +function Terminal:activate(player) + local building_tile = player:getTile() + building_tile:insert('terminal', self.condition) + + -------------------------------------------- + ----------- M E S S A G E -------------- + -------------------------------------------- + + local self_msg = 'You install a terminal.' + local msg = '{player} installs a terminal.' + msg = msg:replace(player) + + -------------------------------------------- + --------- B R O A D C A S T ------------ + -------------------------------------------- + + local event = {'terminal', player} + player:broadcastEvent(msg, self_msg, event) +end + +------------------------------------------------------------------- + +return {Generator, Transmitter, Terminal} \ No newline at end of file diff --git a/code/item/items/equipment.lua b/code/item/items/tools.lua similarity index 57% rename from code/item/items/equipment.lua rename to code/item/items/tools.lua index 66906bf..9771cd4 100644 --- a/code/item/items/equipment.lua +++ b/code/item/items/tools.lua @@ -4,118 +4,6 @@ local broadcastEvent = require('code.server.event') string.replace = require('code.libs.replace') local dice = require('code.libs.dice') -local Generator = class('Generator', Item) - -Generator.FULL_NAME = 'generator' -Generator.WEIGHT = 25 -Generator.DURABILITY = 0 -Generator.CATEGORY = 'engineering' -Generator.ap = {cost = 10, modifier = {tech = -2, power_tech = -4}} - -function Generator:client_criteria(player) - local p_tile = player:getTile() - assert(player:isStaged('inside'), 'Must be inside building to install generator') - assert(not p_tile.generator:isPresent(), 'There is no room for a second generator') -end - -Generator.server_criteria = Generator.client_criteria - -function Generator:activate(player) - local building_tile = player:getTile() - building_tile:insert('generator', self.condition) - - -------------------------------------------- - ----------- M E S S A G E -------------- - -------------------------------------------- - - local self_msg = 'You install a generator.' - local msg = '{player} installs a generator.' - msg = msg:replace(player) - - -------------------------------------------- - --------- B R O A D C A S T ------------ - -------------------------------------------- - - local event = {'generator', player} - player:broadcastEvent(msg, self_msg, event) -end - -------------------------------------------------------------------- - -local Transmitter = class('Transmitter', Item) - -Transmitter.FULL_NAME = 'transmitter' -Transmitter.WEIGHT = 25 -Transmitter.DURABILITY = 0 -Transmitter.CATEGORY = 'engineering' -Transmitter.ap = {cost = 10, modifier = {tech = -2, radio_tech = -4}} - -function Transmitter:client_criteria(player) - local p_tile = player:getTile() - assert(player:isStaged('inside'), 'Must be inside building to install transmitter') - assert(not p_tile.transmitter:isPresent(), 'There is no room for a second transmitter') -end - -Transmitter.server_criteria = Transmitter.client_criteria - -function Transmitter:activate(player) - local building_tile = player:getTile() - building_tile:insert('transmitter', self.condition) - - -------------------------------------------- - ----------- M E S S A G E -------------- - -------------------------------------------- - - local self_msg = 'You install a transmitter.' - local msg = '{player} installs a transmitter.' - msg = msg:replace(player) - - -------------------------------------------- - --------- B R O A D C A S T ------------ - -------------------------------------------- - - local event = {'transmitter', player} - player:broadcastEvent(msg, self_msg, event) -end - -------------------------------------------------------------------- - -local Terminal = class('Terminal', Item) - -Terminal.FULL_NAME = 'terminal' -Terminal.WEIGHT = 25 -Terminal.DURABILITY = 0 -Terminal.CATEGORY = 'engineering' -Terminal.ap = {cost = 10, modifier = {tech = -2, computer_tech = -4}} - -function Terminal:client_criteria(player) - local p_tile = player:getTile() - assert(player:isStaged('inside'), 'Must be inside building to install terminal') - assert(not p_tile.terminal:isPresent(), 'There is no room for a second terminal') -end - -Terminal.server_criteria = Terminal.client_criteria - -function Terminal:activate(player) - local building_tile = player:getTile() - building_tile:insert('terminal', self.condition) - - -------------------------------------------- - ----------- M E S S A G E -------------- - -------------------------------------------- - - local self_msg = 'You install a terminal.' - local msg = '{player} installs a terminal.' - msg = msg:replace(player) - - -------------------------------------------- - --------- B R O A D C A S T ------------ - -------------------------------------------- - - local event = {'terminal', player} - player:broadcastEvent(msg, self_msg, event) -end - ------------------------------------------------------------------- local Fuel = class('Fuel', Item) @@ -246,4 +134,4 @@ end ------------------------------------------------------------------- -return {Generator, Transmitter, Terminal, Fuel, Barricade, Toolbox} \ No newline at end of file +return {Fuel, Barricade, Toolbox} \ No newline at end of file From d963115574baa753da3cf7da0fbad9aa42871f33 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 25 Dec 2017 13:31:12 -0600 Subject: [PATCH 03/45] Add IsArmor mixin to Item --- code/item/mixin/is_armor.lua | 8 ++++++ code/work-in-progress/armor/item_class.lua | 32 ---------------------- 2 files changed, 8 insertions(+), 32 deletions(-) create mode 100644 code/item/mixin/is_armor.lua delete mode 100644 code/work-in-progress/armor/item_class.lua diff --git a/code/item/mixin/is_armor.lua b/code/item/mixin/is_armor.lua new file mode 100644 index 0000000..5096854 --- /dev/null +++ b/code/item/mixin/is_armor.lua @@ -0,0 +1,8 @@ +local IsArmor = {} + +function IsArmor:getProtection(damage_type) + local resistance, condition = self.armor.RESISTANCE, self.condition + return (resistance[condition] and resistance[condition][damage_type]) or resistance[damage_type] or 0 +end + +return IsArmor \ No newline at end of file diff --git a/code/work-in-progress/armor/item_class.lua b/code/work-in-progress/armor/item_class.lua deleted file mode 100644 index 09d040f..0000000 --- a/code/work-in-progress/armor/item_class.lua +++ /dev/null @@ -1,32 +0,0 @@ -local class = require('code.libs.middleclass') -local Item = require('code.item.item') -local armor = require('code.player.armor.class') - -local item_armor = class('item_armor', armor) - -function item_armor:initialize(player) - armor.initialize(self, player) -end - -function item_armor:equip(name, condition) - if self:isPresent() then self:remove() end -- unequips the old armor and puts it back into the inventory - self.name, self.condition = name, condition -end - -function item_armor:remove() - local player, armor_type, condition = self.player, self.name, self.condition - local armor_INST = Item[armor_type]:new(condition) - - player.inventory:insert(armor_INST) - self.name, self.condition = nil, nil -end - -function item_armor:degrade(player) - self.condition = self.condition - 1 - if 0 > self.condition then -- armor is destroyed - self.name, self.condition = nil, nil - return -- something to tell that armor is destroyed? - end -end - -return item_armor \ No newline at end of file From 10d18c49cf9fb3831bd41ee4b410af872f72dd3b Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 25 Dec 2017 13:31:31 -0600 Subject: [PATCH 04/45] Add Equipment class --- code/player/equipment.lua | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 code/player/equipment.lua diff --git a/code/player/equipment.lua b/code/player/equipment.lua new file mode 100644 index 0000000..a9ee1f8 --- /dev/null +++ b/code/player/equipment.lua @@ -0,0 +1,19 @@ +local class = require('code.libs.middleclass') +local Equipment = class('Equipment') + +-- clothing slots for (feet, hands, eye, mask, helmet, back, suit) +-- armor slot for (exo_suit) + +function Equipment:initialize(player) + self.player = player +end + +function Equipment:add(section, object) + self[section] = object +end + +function Equipment:remove(section) self[section] = nil end + +function Equipment:isPresent(section) return self[section] end + +return Equipment \ No newline at end of file From abf689a096201114e1a1905e8b9f9c87ea577fbf Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 25 Dec 2017 13:41:24 -0600 Subject: [PATCH 05/45] Change items\armor.lua to have a base armor class --- code/item/items/armor.lua | 48 ++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/code/item/items/armor.lua b/code/item/items/armor.lua index f17c5f1..36f94c5 100644 --- a/code/item/items/armor.lua +++ b/code/item/items/armor.lua @@ -3,54 +3,44 @@ local Item = require('code.item.item') local broadcastEvent = require('code.server.event') string.replace = require('code.libs.replace') -local Leather = class('Leather', Item) +------------------------------------------------------------------- -Leather.FULL_NAME = 'leather jacket' -Leather.DURABILITY = 0 -Leather.CATEGORY = 'military' -Leather.ap = {cost = 1} +local Armor = class('Armor', Item) -- this is the base class for Armor objects -function Leather:activate(player) - player.armor:equip('leather', self.condition) +Armor.ap = {cost = 1} + +function Armor:activate(player) + --player.armor:equip('leather', self.condition) -- not sure how this will be handled... wait until equipment code is written for player -------------------------------------------- ----------- M E S S A G E -------------- -------------------------------------------- - local msg = 'You equip a leather jacket.' - + local msg = 'You equip a {armor}.' + msg = msg:replace(self) -- This should work? Needs to be tested + -------------------------------------------- --------- B R O A D C A S T ------------ -------------------------------------------- - local event = {'leather', player} + local event = {'armor', player} player.log:insert(msg, event) end ------------------------------------------------------------------- -local Firesuit = class('Firesuit', Item) +local Leather = class('Leather', Armor) + +Leather.FULL_NAME = 'leather jacket' +Leather.DURABILITY = 0 +Leather.CATEGORY = 'military' + +------------------------------------------------------------------- + +local Firesuit = class('Firesuit', Armor) Firesuit.FULL_NAME = 'firesuit' Firesuit.DURABILITY = 0 Firesuit.CATEGORY = 'military' -Firesuit.ap = {cost = 1} - -function Firesuit:activate(player) - player.armor:equip('firesuit', self.condition) - - -------------------------------------------- - ----------- M E S S A G E -------------- - -------------------------------------------- - - local msg = 'You equip a firesuit.' - - -------------------------------------------- - --------- B R O A D C A S T ------------ - -------------------------------------------- - - local event = {'firesuit', player} - player.log:insert(msg, event) -end return {Leather, Firesuit} \ No newline at end of file From fde48b299ca457a0aa59ca3c5f086824b4361bc2 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 25 Dec 2017 13:54:37 -0600 Subject: [PATCH 06/45] Add armor IsArmor mixin, resistance and durability --- code/item/items/armor.lua | 16 +++++++++--- code/work-in-progress/armor/is_armor.lua | 8 ++++++ code/work-in-progress/armor/item_list.lua | 31 ----------------------- 3 files changed, 21 insertions(+), 34 deletions(-) create mode 100644 code/work-in-progress/armor/is_armor.lua delete mode 100644 code/work-in-progress/armor/item_list.lua diff --git a/code/item/items/armor.lua b/code/item/items/armor.lua index 36f94c5..1012d4a 100644 --- a/code/item/items/armor.lua +++ b/code/item/items/armor.lua @@ -1,11 +1,12 @@ local class = require('code.libs.middleclass') local Item = require('code.item.item') +local IsArmor = require('code.item.mixin.is_armor') local broadcastEvent = require('code.server.event') string.replace = require('code.libs.replace') ------------------------------------------------------------------- -local Armor = class('Armor', Item) -- this is the base class for Armor objects +local Armor = class('Armor', Item):include(IsArmor) -- this is the base class for Armor objects Armor.ap = {cost = 1} @@ -32,15 +33,24 @@ end local Leather = class('Leather', Armor) Leather.FULL_NAME = 'leather jacket' -Leather.DURABILITY = 0 +Leather.DURABILITY = 32 Leather.CATEGORY = 'military' +Leather.armor.resistance = {blunt=1} + ------------------------------------------------------------------- local Firesuit = class('Firesuit', Armor) Firesuit.FULL_NAME = 'firesuit' -Firesuit.DURABILITY = 0 +Firesuit.DURABILITY = 4 Firesuit.CATEGORY = 'military' +Firesuit.armor.resistance = { + {acid=1}, + {acid=2}, + {acid=3}, + {acid=4}, +} + return {Leather, Firesuit} \ No newline at end of file diff --git a/code/work-in-progress/armor/is_armor.lua b/code/work-in-progress/armor/is_armor.lua new file mode 100644 index 0000000..0032357 --- /dev/null +++ b/code/work-in-progress/armor/is_armor.lua @@ -0,0 +1,8 @@ +local IsArmor = {} + +function IsArmor:getProtection(damage_type) + local resistance, condition = self.armor.resistance, self.condition + return (resistance[condition] and resistance[condition][damage_type]) or resistance[damage_type] or 0 +end + +return IsArmor \ No newline at end of file diff --git a/code/work-in-progress/armor/item_list.lua b/code/work-in-progress/armor/item_list.lua deleted file mode 100644 index 40c3fbe..0000000 --- a/code/work-in-progress/armor/item_list.lua +++ /dev/null @@ -1,31 +0,0 @@ -local armor = {} - ---[[ - full_name = 'insert name' - durability = num (average # of attacks it takes to wear armor out) - resistance = { - condition = {protection=num}, - } - - ** As condition becomes worse armor starts to lose resistance (with the exception of a few armors) ---]] - -armor.leather = {} -armor.leather.durability = 32 -armor.leather.resistance = { - [1] = {blunt=1}, - [2] = {blunt=1}, - [3] = {blunt=1}, - [4] = {blunt=1}, -} - -armor.firesuit = {} -armor.firesuit.durability = 4 -armor.firesuit.resistance = { - [1] = {acid=1}, - [2] = {acid=2}, - [3] = {acid=3}, - [4] = {acid=4}, -} - -return armor \ No newline at end of file From e2912c705bcd30976441cfd5da4e1afe7eb303c9 Mon Sep 17 00:00:00 2001 From: Timothy Date: Tue, 26 Dec 2017 16:27:29 -0600 Subject: [PATCH 07/45] Add old armor removal when armor is activated --- code/item/items/armor.lua | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/code/item/items/armor.lua b/code/item/items/armor.lua index 1012d4a..ccb98e2 100644 --- a/code/item/items/armor.lua +++ b/code/item/items/armor.lua @@ -6,12 +6,16 @@ string.replace = require('code.libs.replace') ------------------------------------------------------------------- -local Armor = class('Armor', Item):include(IsArmor) -- this is the base class for Armor objects +local Armor = class('Armor', Item):include(IsArmor) -Armor.ap = {cost = 1} +Armor.ap = {cost = 1} -- default AP cost for armor function Armor:activate(player) - --player.armor:equip('leather', self.condition) -- not sure how this will be handled... wait until equipment code is written for player + if player.equipment:isActive('armor') then -- remove old armor and put into inventory + local old_armor = player.equipment.armor + player.inventory:insert(old_armor) + end + player.equipment:add('armor', self) -------------------------------------------- ----------- M E S S A G E -------------- @@ -24,8 +28,8 @@ function Armor:activate(player) --------- B R O A D C A S T ------------ -------------------------------------------- - local event = {'armor', player} - player.log:insert(msg, event) + local event = {'armor', player} + player.log:insert(msg, event) end ------------------------------------------------------------------- From 85c31a66f086e097222e3fd84ff83b07a7996b81 Mon Sep 17 00:00:00 2001 From: Timothy Date: Tue, 26 Dec 2017 17:53:22 -0600 Subject: [PATCH 08/45] Add OrganicArmor to Zombie class --- code/player/zombie/organic_armor.lua | 113 +++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 code/player/zombie/organic_armor.lua diff --git a/code/player/zombie/organic_armor.lua b/code/player/zombie/organic_armor.lua new file mode 100644 index 0000000..a7472da --- /dev/null +++ b/code/player/zombie/organic_armor.lua @@ -0,0 +1,113 @@ +local class = require('code.libs.middleclass') +local Item = require('code.item.item') +local IsArmor = require('code.item.mixin.is_armor') + +------------------------------------------------------------------- + +local OrganicArmor = class('OrganicArmor', Item):include(IsArmor) -- remove Item superclass... do we need the methods? +OrganicArmor.ap = {cost = 5, modifier={armor_adv = -2}} + +function OrganicArmor:client_criteria(player) + assert(player.skills:check('armor'), 'Must have "armor" skill to create armor') + -- add feed/corpse asserts here +end + +function OrganicArmor:server_criteria(player, armor) + assert(player.skills:check('armor'), 'Must have "armor" skill to create armor') + assert(not armor or player.skills:check('armor_adv'), 'Must have "armor_adv" skill to select armor') + -- add feed/corpse asserts here +end + +function OrganicArmor:activate(player) + -- run feed/corpse code + -- init armor obj + -- give armor obj condition? + + player.equipment:add('armor', self) + + -------------------------------------------- + ----------- M E S S A G E -------------- + -------------------------------------------- + + local msg = 'You mutate a corpse and gain a {armor}.' + msg = msg:replace(self) -- This should work? Needs to be tested + + -------------------------------------------- + --------- B R O A D C A S T ------------ + -------------------------------------------- + + local event = {'armor', player} + player.log:insert(msg, event) +end + +------------------------------------------------------------------- + +local Scale = class('Scale', OrganicArmor) + +Scale.FULL_NAME = 'scale' +Scale.DURABILITY = 8 + +Scale.armor.resistance = { + {bullet=1, pierce=1}, + {bullet=2, blunt=1, pierce=2}, + {bullet=3, blunt=2, pierce=3}, + {bullet=5, blunt=4, pierce=4}, +} + +------------------------------------------------------------------- + +local Blubber = class('Blubber', OrganicArmor) + +Blubber.FULL_NAME = 'firesuit' +Blubber.DURABILITY = 16 + +Blubber.armor.resistance = { + { blunt=1, pierce=1}, + {bullet=1, blunt=1, pierce=1}, + {bullet=1, blunt=1, pierce=2}, + {bullet=2, blunt=1, pierce=2}, +} + +------------------------- ------------------------------------------ + +local Gel = class('Gel', OrganicArmor) +{ +Gel.FULL_NAME = 'gel' +Gel.DURABILITY = 32 + +Gel.armor.resistance = { + { blunt=1, pierce=1, scorch=4}, + { blunt=1, pierce=1, scorch=4}, + {bullet=1, blunt=1, pierce=1, scorch=4}, + {bullet=1, blunt=1, pierce=1, scorch=4}, +} + +------------------------------------------------------------------- + +local Bone = class('Bone', OrganicArmor) + +Bone.FULL_NAME = 'bone' +Bone.DURABILITY = 8 + +Bone.armor.resistance = { + {damage_melee_attacker=1}, + {damage_melee_attacker=1}, + {damage_melee_attacker=1}, + {damage_melee_attacker=2}, +} + +------------------------------------------------------------------- + +--[[ +local Stretch = class('Stretch', OrganicArmor) + +Stretch.FULL_NAME = 'stretch' +Stretch.DURABILITY = 8 +Stretch.armor.resistance = { + {bullet=1} +} +--]] + +------------------------------------------------------------------- + +return {Scale, Blubber, Gel, Bone} -- Stretch,} \ No newline at end of file From c80a7c9c0edf820845b0640a4af571594b5da0d2 Mon Sep 17 00:00:00 2001 From: Timothy Date: Tue, 26 Dec 2017 18:22:59 -0600 Subject: [PATCH 09/45] Add getCorpses method to Tile --- code/location/tile/tile.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/code/location/tile/tile.lua b/code/location/tile/tile.lua index 35b97a9..451cc51 100644 --- a/code/location/tile/tile.lua +++ b/code/location/tile/tile.lua @@ -104,6 +104,21 @@ function Tile:getPlayers(setting, filter) return next(players) and players or nil end +function Tile:getCorpses(setting) + local corpses, players = {} + + if setting == 'outside' then players = self.outside_players + elseif setting == 'inside' then players = self.inside_players + else error('Tile:getCorpses setting arg not present') + end + + for player in pairs(players) do + if not player:isStanding() then corpses[#corpses+1] = player end + end + + return next(corpses) and corpses or nil +end + function Tile:isIntegrity(setting) if self:isBuilding() then return self.integrity:getState() == setting else return 'intact' == setting From af1d00ac53fe5fd2b8ad33f3949ee202248a02cf Mon Sep 17 00:00:00 2001 From: Timothy Date: Tue, 26 Dec 2017 18:23:38 -0600 Subject: [PATCH 10/45] Add getCorpses method in feed action --- code/player/zombie/action/advanced.lua | 39 +++++++++++++------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/code/player/zombie/action/advanced.lua b/code/player/zombie/action/advanced.lua index 0afe611..f0fef69 100644 --- a/code/player/zombie/action/advanced.lua +++ b/code/player/zombie/action/advanced.lua @@ -34,14 +34,14 @@ end local feed = {name='feed', ap={cost=1}} function feed.client_criteria(player) - local p_tile, p_stage = player:getTile(), player:getStage() - local corpse_n = p_tile:countCorpses(p_stage) - assert(corpse_n > 0, 'No available corpses to eat') + local p_tile = player:getTile() + local p_stage = player:getStage() + local corpses = p_tile:getCorpses(p_stage) + assert(corpses, 'No available corpses to eat') local edible_corpse_present - local tile_player_group = p_tile:getPlayers(p_stage) - for tile_player in pairs(tile_player_group) do - if not tile_player:isStanding() and tile_player:isMobType('human') and tile_player.carcass:edible(player) then + for corpse in pairs(corpses) do + if corpse:isMobType('human') and corpse.carcass:edible(player) then edible_corpse_present = true break end @@ -50,19 +50,19 @@ function feed.client_criteria(player) end function feed.server_criteria(player) - local p_tile, p_stage = player:getTile(), player:getStage() - local corpse_n = p_tile:countCorpses(p_stage) - assert(corpse_n > 0, 'No available corpses to eat') + local p_tile = player:getTile() + local p_stage = player:getStage() + local corpses = p_tile:getCorpses(p_stage) + assert(corpses, 'No available corpses to eat') local edible_corpse_present - local tile_player_group = p_tile:getPlayers(p_stage) - for tile_player in pairs(tile_player_group) do - if not tile_player:isStanding() and tile_player:isMobType('human') and tile_player.carcass:edible(player) then + for corpse in pairs(corpses) do + if corpse:isMobType('human') and corpse.carcass:edible(player) then edible_corpse_present = true break end end - assert(edible_corpse_present, 'All corpses have been eaten') + assert(edible_corpse_present, 'All corpses have been eaten') end local corpse_effects = { @@ -73,18 +73,19 @@ local corpse_effects = { } function feed.activate(player) - local p_tile, p_stage = player:getTile(), player:getStage() - local tile_player_group = p_tile:getPlayers(p_stage) + local p_tile = player:getTile() + local p_stage = player:getStage() + local corpses = p_tile:getCorpses() local target local lowest_scavenger_num = 5 -- finds the corpse with the lowest number of scavengers (fresh meat) - for tile_player in pairs(tile_player_group) do + for corpse in pairs(corpses) do - if not tile_player:isStanding() and tile_player:isMobType('human') and tile_player.carcass:edible(player) then - local corpse_scavenger_num = #tile_player.carcass.carnivour_list + if corpse:isMobType('human') and corpse.carcass:edible(player) then + local corpse_scavenger_num = #corpse.carcass.carnivour_list if lowest_scavenger_num > corpse_scavenger_num then - target = tile_player + target = corpse lowest_scavenger_num = corpse_scavenger_num end end From 70ad4410b4dd2a3d2d79ca99cbbdfe6b37681b2e Mon Sep 17 00:00:00 2001 From: Timothy Date: Tue, 26 Dec 2017 19:05:33 -0600 Subject: [PATCH 11/45] Add edible_corpse code to OrganicArmor --- code/player/zombie/organic_armor.lua | 30 ++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/code/player/zombie/organic_armor.lua b/code/player/zombie/organic_armor.lua index a7472da..737daf9 100644 --- a/code/player/zombie/organic_armor.lua +++ b/code/player/zombie/organic_armor.lua @@ -9,13 +9,39 @@ OrganicArmor.ap = {cost = 5, modifier={armor_adv = -2}} function OrganicArmor:client_criteria(player) assert(player.skills:check('armor'), 'Must have "armor" skill to create armor') - -- add feed/corpse asserts here + + local p_tile = player:getTile() + local p_stage = player:getStage() + local corpses = p_tile:getCorpses(p_stage) + assert(corpses, 'No available corpses to eat') + + local edible_corpse_present + for corpse in pairs(corpses) do + if corpse:isMobType('human') and corpse.carcass:edible(player) then + edible_corpse_present = true + break + end + end + assert(edible_corpse_present, 'All corpses have been eaten') end function OrganicArmor:server_criteria(player, armor) assert(player.skills:check('armor'), 'Must have "armor" skill to create armor') assert(not armor or player.skills:check('armor_adv'), 'Must have "armor_adv" skill to select armor') - -- add feed/corpse asserts here + + local p_tile = player:getTile() + local p_stage = player:getStage() + local corpses = p_tile:getCorpses(p_stage) + assert(corpses, 'No available corpses to eat') + + local edible_corpse_present + for corpse in pairs(corpses) do + if corpse:isMobType('human') and corpse.carcass:edible(player) then + edible_corpse_present = true + break + end + end + assert(edible_corpse_present, 'All corpses have been eaten') end function OrganicArmor:activate(player) From f4aed5b2fa5f3ea58f948e24c6c06ac3db09ea43 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 27 Dec 2017 18:19:24 -0600 Subject: [PATCH 12/45] Create FAQ.md --- FAQ.md | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 FAQ.md diff --git a/FAQ.md b/FAQ.md new file mode 100644 index 0000000..e269ca2 --- /dev/null +++ b/FAQ.md @@ -0,0 +1,70 @@ +### Q: What is the difference between the ZomboTropolis remake and Urbandead/Quarantine2019? + +*(Note - I will here forth refer to ZomboTropolis as ZT, Urbandead as UD, and Quarantine2019 as Q)* + +>Multiple major and distinct differences. + +>**Platform:** ZT is going to be an app for mobile. Browser based games are dying, any remake needs to address this. The app market has a huge playerbase that keeps growing, and for games such as this, the complexity of getting a decent user interface for mobile is pretty doable. Push notifications also present a major advantage over browsers when it comes to in game events. + +>**Graphics:** ZT is going to be using sprites for the characters, locations, and skills from free art assets. (Space Station 13, game-icons.net, etc.) This is a __MUST HAVE__ for an app on the app store. Without graphics there would be no playerbase! (although the hardcore vets will still play regardless) + +>**Gameplay for UD:** +>UD was a simple game, with basic math calculations and combat. Survivors had items, safehouses, and equipment. Zombies had abilities that were rather... plain. The skills for both sides complemented the above rather well, but none of it was groundbreaking. Neither side in the game could truly win. When one side started to win, the code in the game would nerf the other side. What gave this game so much life was the *community*. They were so active and fun to play with and it gave the game a rich and immersive history. The map for the game was huge! There were endless suburbs and buildings, not to mention distinct landmarks such as malls, churches, and mansions that were fun to discover and explore. One problem with a map this size was population. If population for the game dipped to low (and it did) then large portions of the map became ghost towns. Kevan (the developer) did test out new maps with permadeath enabled. This briefly revitalized the playerbase, although each of these maps are now over with. + +>**Gameplay for Q:** +>Q was a remake of UD with the intention of adding more complexity, features, and a end goal for both sides. With Q, you could actually win the game for your side! By playing through a round based system, zombies could either eliminate all humans, or humans could research the cure to win the game. Maps for Q were much smaller and tailored to the size of the population. One notable thing that Q did was to split skills into classes. Certain zombies were given abilities that others did not have, and vice-versa for humans. While this was a great idea, I believe it was executed poorly. Some skills were worthless, others were unbalanced. Some classes only had one utility they were good for and nothing else. (which made gameplay dull and repetitive for that class) Other features and systems seemed to be designed without proper planning. Staircases and multi-level buildings served no purpose, infection was unrealistic and unpractical, and resource points for buildings was just plain weird. It had it's flaws but I respected what the developers of Q were trying to do. UD had been neglected with updates, and Q was trying to branch off into a much better version. And to be fair, Q did come up with some really great stuff! Power plant buildings that powered entire suburbs, computers could network with ISP buildings, items had durability, etc. etc. Q only had a fraction of the population that UD had, so their rounds and maps were rather quick and small. Still lots of fun to play back in the day though! + +>**Gameplay for ZT:** +>ZT seeks to take both of these games a step further and add roguelike features and complexity to the code. All skills, abilities, and items in the game use dice rolls and dice modifiers to function. This has been implemented in a (mostly) balanced fashion. + +>Just like UD, there is a persistent world, but with rubber banding enabled that stretches the map based on population size. Respawns for the game are always enabled, but a player will lose all their items, abilities, and skills upon permadeath. Permadeath is triggered for humans upon death, and zombies upon starvation. The goal is to follow a prey/predator model of graphing. + +>Leveling is based on time. Players are no longer forced to heal, fight, or repair things to gain experience. The longer a player's character survives in the game, the more experience they earn to unlock skills. The skill system is setup to exponentially increase the skill cost after prior skills have been purchased. With enough time, a player can even unlock a special class with it's own special abilities to enhance a certain playstyle. + +>Items and equipment in the game possess a condition value that will enhance or degrade its functionality. Each class can see relevant condition data based on the type of object. (military class can see weapon conditions, engineering class can see equipment and barricade conditions, etc.) Subsequent uses of an item or equipment eventually decreases the condition, yielding lower dice rolls or performance results. For instance, a generator that is "pristine" condition will use fuel more efficiently than the "ruined" condition. Additionally, searching in buildings when they are ruined yields items of lower quality. (including lowered search rates) + +>A lot more features have been added to ZT than in Q and UD. A quick list as follows, + +>+ Hunter zombie function as scouts. They can hide in unlit buildings, track players scent, free-run from ruined buildings into unruined buildings, move faster than other zombies (movement cost 1 AP), blood vision (x-ray) to see wounded characters from outside. +>+ Brute zombies function as tanks. They can maim humans (reduce their hp permanently), generate organic armor from corpses, drag prey out into the streets, and destroy barricades/equipment/armor more effectively +>+ Hive zombies function as support. They can ruin buildings, corrode human inventory with acid, deliver infection with bites, and communicate with all zombies via the hivemind. + +>+ Engineers are builders. They can repair ruins, barricade to higher levels, and install equipment faster. +>+ Military are fighters. They can master any weapon, maim zombies, and give a bonus to safehouse defenses. +>+ Researchers are healers. They can heal efficiently, scan zombies, use terminals (gives info about surroundings), and create antidotes. + +>While humans generally do not have restrictions to their actions, certain actions will greatly benefit from skills from one class. + +### Q: Roguelike?! With permadeath, dice and stuff? + +>Yes. If you die (as a human) or starve (as a zombie) then it's game over. Fortunately, respawning is easy and you won't be completely useless with a new character. With ZT, your goal is to see how long you can survive, and if I have developed the game correctly, this should be hard for both sides. + +>Regarding dice, I felt like both UD and Q suffered from using what I call 'basic' math. Weapons and items always did `x` amount of effect. That wasn't realistic and pretty boring for gameplay. So by adding dice it would allow ZT to be more dynamic! Weapons in better condition do more damage or have better accuracy. Skills either boost accuracy or grant rerolls to weapon attacks that successfully land. This is a powerful system that works well and allows for interesting possibilities. + +### Q: Will this be free? What is the monetization plan? + +>Free for freedom! Yes, it will be free. The monetization plan I have in mind is to have an occasional ad inserted into the game. (probably after AP is used) Another source of funding is to have cosmetic items in game that can be unlocked via purchasing tokens or surviving for `x` amount of days. + +>Money will not give a person an in game advantage. This will keep the game true to it's predecessors! :) + +### Q: When will the game be playable/finished? + +>I'm aiming for development to be finished around Spring 2018. The app should launch shortly after that time frame. + +### Q: How long has this been in development? + +>I have been developing ZT for a few years off and on in my free time. This last year I have made tremendous progress, and the game is now close to being finished. I have worked on other smaller projects, but this game has been my most ambitious yet. + +### Q: What about modding? + +>I will be looking at modding ZT to other themes since my API and source code is pretty robust. It shouldn't be that hard to switch it to something like say, Ninjas vs Samurais, heh. + +### Q: How can I help? + +>I need help with the following: + +>+ Playtesters in a few months +>+ Setting up a ZT game wiki +>+ People to bounce ideas off + +>I am **not** looking for other coders or artists to contribute at this time. After launch this may change. From 040f83361bb6c789cb360fff1e3ccab1fcd21ce7 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 27 Dec 2017 18:25:10 -0600 Subject: [PATCH 13/45] Update FAQ.md --- FAQ.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FAQ.md b/FAQ.md index e269ca2..f8966e9 100644 --- a/FAQ.md +++ b/FAQ.md @@ -17,7 +17,7 @@ >**Gameplay for ZT:** >ZT seeks to take both of these games a step further and add roguelike features and complexity to the code. All skills, abilities, and items in the game use dice rolls and dice modifiers to function. This has been implemented in a (mostly) balanced fashion. ->Just like UD, there is a persistent world, but with rubber banding enabled that stretches the map based on population size. Respawns for the game are always enabled, but a player will lose all their items, abilities, and skills upon permadeath. Permadeath is triggered for humans upon death, and zombies upon starvation. The goal is to follow a prey/predator model of graphing. +>Just like UD, there is a persistent world, but with rubber banding enabled that stretches the map based on population size. Respawns for the game are always enabled, but a player will lose all their items, abilities, and skills upon permadeath. Permadeath is triggered for humans upon death, and zombies upon starvation. The goal is to follow a [prey/predator model](http://www.tiem.utk.edu/~gross/bioed/bealsmodules/pred-prey.gph1.gif) of graphing. >Leveling is based on time. Players are no longer forced to heal, fight, or repair things to gain experience. The longer a player's character survives in the game, the more experience they earn to unlock skills. The skill system is setup to exponentially increase the skill cost after prior skills have been purchased. With enough time, a player can even unlock a special class with it's own special abilities to enhance a certain playstyle. From 832612e14f203e39b448858560aa6734376a0036 Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 28 Dec 2017 08:24:19 -0600 Subject: [PATCH 14/45] Fix Blubber.FULL_NAME typo --- code/player/zombie/organic_armor.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/player/zombie/organic_armor.lua b/code/player/zombie/organic_armor.lua index 737daf9..0312523 100644 --- a/code/player/zombie/organic_armor.lua +++ b/code/player/zombie/organic_armor.lua @@ -84,7 +84,7 @@ Scale.armor.resistance = { local Blubber = class('Blubber', OrganicArmor) -Blubber.FULL_NAME = 'firesuit' +Blubber.FULL_NAME = 'blubber' Blubber.DURABILITY = 16 Blubber.armor.resistance = { From f79e5ed93e4ccbb2775f23a41cf39d9a62620c69 Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 28 Dec 2017 08:25:03 -0600 Subject: [PATCH 15/45] Change MAX_FEEDINGS for corpse to 4 --- code/player/human/carcass.lua | 2 +- code/player/zombie/action/advanced.lua | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/player/human/carcass.lua b/code/player/human/carcass.lua index fb5fe63..6e9b0f6 100644 --- a/code/player/human/carcass.lua +++ b/code/player/human/carcass.lua @@ -1,7 +1,7 @@ local class = require('code.libs.middleclass') local Carcass = class('Carcass') -local MAX_FEEDINGS = 5 +local MAX_FEEDINGS = 4 function Carcass:initialize(player) self.player = player diff --git a/code/player/zombie/action/advanced.lua b/code/player/zombie/action/advanced.lua index f0fef69..741931d 100644 --- a/code/player/zombie/action/advanced.lua +++ b/code/player/zombie/action/advanced.lua @@ -67,9 +67,9 @@ end local corpse_effects = { -- First come, first serve! (less xp and decay loss as corpse becomes more devoured) - xp = {'1d10+5', '1d9+3', '1d7+2', '1d5+1', '1d3'}, - satiation = {'1d400+600', '1d400+500', '1d400+400', '1d400+300', '1d400+200'}, - description = {'very fresh', 'fresh', '', 'old', 'very old'} + xp = {'1d10+5', '1d9+3', '1d7+2', '1d5+1'}, + satiation = {'1d400+600', '1d400+500', '1d400+400', '1d400+300'}, + description = {'very fresh', 'fresh', 'old', 'very old'} } function feed.activate(player) From fbebceb07e7f1d61e681e2226300ca0a1e26ea64 Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 28 Dec 2017 08:29:15 -0600 Subject: [PATCH 16/45] Fix getCorpses missing stage --- code/player/zombie/action/advanced.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/player/zombie/action/advanced.lua b/code/player/zombie/action/advanced.lua index 741931d..635ae86 100644 --- a/code/player/zombie/action/advanced.lua +++ b/code/player/zombie/action/advanced.lua @@ -75,7 +75,7 @@ local corpse_effects = { function feed.activate(player) local p_tile = player:getTile() local p_stage = player:getStage() - local corpses = p_tile:getCorpses() + local corpses = p_tile:getCorpses(p_stage) local target local lowest_scavenger_num = 5 From 31c86a2c1439ec31e2822246a2742c3f5fb38eb9 Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 28 Dec 2017 08:34:51 -0600 Subject: [PATCH 17/45] Fix corpse scavenger num to 4 --- code/player/zombie/action/advanced.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/player/zombie/action/advanced.lua b/code/player/zombie/action/advanced.lua index 635ae86..4c14909 100644 --- a/code/player/zombie/action/advanced.lua +++ b/code/player/zombie/action/advanced.lua @@ -77,7 +77,7 @@ function feed.activate(player) local p_stage = player:getStage() local corpses = p_tile:getCorpses(p_stage) local target - local lowest_scavenger_num = 5 + local lowest_scavenger_num = 4 -- finds the corpse with the lowest number of scavengers (fresh meat) for corpse in pairs(corpses) do From 364271c2a3f3ed6709cee0e7e22474dfa221dee7 Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 28 Dec 2017 17:22:25 -0600 Subject: [PATCH 18/45] Fix GPS durability code --- code/player/human/action/basic.lua | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/code/player/human/action/basic.lua b/code/player/human/action/basic.lua index 85c860b..6e1a591 100644 --- a/code/player/human/action/basic.lua +++ b/code/player/human/action/basic.lua @@ -45,7 +45,7 @@ function move.activate(player, dir) local y, x = player:getPos() local map = player:getMap() local dir_y, dir_x = getNewPos(y, x, dir) - local GPS_usage + local GPS, GPS_usage, condition if player:isStaged('inside') then map[y][x]:remove(player, 'inside') @@ -56,15 +56,14 @@ function move.activate(player, dir) end else -- player is outside local inventory_has_GPS, inv_ID = player.inventory:search('GPS') + GPS = player.inventory:lookup(inv_ID) if inventory_has_GPS then -- the GPS has a chance to avoid wasting ap on movement local GPS_chance = (player.skils:check('gadgets') and GPS_advanced_chance) or GPS_basic_chance local GPS_usage = GPS_chance >= math.random() -- this is pretty much a hack (if a player's ap is 50 then they will NOT receive the ap) if GPS_usage then player:updateStat('ap', 1) end - - local GPS = player.inventory:lookup(inv_ID) - if GPS:failDurabilityCheck(player) then GPS:updateCondition(-1, player, inv_ID) end + condition = player.inventory:updateDurability(inv_ID) end map[y][x]:remove(player) @@ -81,6 +80,12 @@ function move.activate(player, dir) local self_msg = 'You travel {dir} {with_GPS}.' local names = {dir=compass[dir], with_GPS=GPS_str} self_msg = self_msg:replace(names) + + if condition == 0 then + self_msg = self_msg..'Your '..tostring(GPS)..' is destroyed!' + elseif condition and GPS:isConditionVisible(player) then + self_msg = self_msg..'Your '..tostring(GPS)..' degrades to a '..GPS:getConditionState()..' state.' + end -------------------------------------------- --------- B R O A D C A S T ------------ From 023c864be975d7a5df31a7690514ea4912529234 Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 28 Dec 2017 18:44:42 -0600 Subject: [PATCH 19/45] Add organic armor equip on activation for zombie --- code/player/zombie/organic_armor.lua | 42 ++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/code/player/zombie/organic_armor.lua b/code/player/zombie/organic_armor.lua index 0312523..2f9fda3 100644 --- a/code/player/zombie/organic_armor.lua +++ b/code/player/zombie/organic_armor.lua @@ -1,3 +1,4 @@ +local dice = require('code.libs.dice') local class = require('code.libs.middleclass') local Item = require('code.item.item') local IsArmor = require('code.item.mixin.is_armor') @@ -6,6 +7,7 @@ local IsArmor = require('code.item.mixin.is_armor') local OrganicArmor = class('OrganicArmor', Item):include(IsArmor) -- remove Item superclass... do we need the methods? OrganicArmor.ap = {cost = 5, modifier={armor_adv = -2}} +OrganicArmor.list = {} function OrganicArmor:client_criteria(player) assert(player.skills:check('armor'), 'Must have "armor" skill to create armor') @@ -25,9 +27,9 @@ function OrganicArmor:client_criteria(player) assert(edible_corpse_present, 'All corpses have been eaten') end -function OrganicArmor:server_criteria(player, armor) +function OrganicArmor:server_criteria(player, armor_type) assert(player.skills:check('armor'), 'Must have "armor" skill to create armor') - assert(not armor or player.skills:check('armor_adv'), 'Must have "armor_adv" skill to select armor') + assert(not armor_type or player.skills:check('armor_adv'), 'Must have "armor_adv" skill to select armor') local p_tile = player:getTile() local p_stage = player:getStage() @@ -44,12 +46,32 @@ function OrganicArmor:server_criteria(player, armor) assert(edible_corpse_present, 'All corpses have been eaten') end -function OrganicArmor:activate(player) - -- run feed/corpse code - -- init armor obj - -- give armor obj condition? +function OrganicArmor:activate(player, armor_type) + local corpses = p_tile:getCorpses(player:getStage()) + local target + local lowest_scavenger_num = 4 + + -- finds the corpse with the lowest number of scavengers (fresh meat) + for corpse in pairs(corpses) do + if corpse:isMobType('human') and corpse.carcass:edible(player) then + local corpse_scavenger_num = #corpse.carcass.carnivour_list + if lowest_scavenger_num > corpse_scavenger_num then + target = corpse + lowest_scavenger_num = corpse_scavenger_num + end + end + end - player.equipment:add('armor', self) + local nutrition_LV = target.carcass:devour(player) + local armor_dice = dice:new('1d'..nutrition_LV) + + if player.skills:check('armor_adv') then armor_dice = armor_dice ^ 1 end + local condition = armor_dice:roll() + + armor_type = armor_type or OrganicArmor.list[math.random(1, #OrganicArmor.list)] + armor = OrganicArmor.subclass[armor]:new(condition) -- This should work... + + player.equipment:add('armor', armor) -------------------------------------------- ----------- M E S S A G E -------------- @@ -69,6 +91,7 @@ end ------------------------------------------------------------------- local Scale = class('Scale', OrganicArmor) +OrganicArmor.list[#OrganicArmor.list+1] = 'Scale' Scale.FULL_NAME = 'scale' Scale.DURABILITY = 8 @@ -83,6 +106,7 @@ Scale.armor.resistance = { ------------------------------------------------------------------- local Blubber = class('Blubber', OrganicArmor) +OrganicArmor.list[#OrganicArmor.list+1] = 'Blubber' Blubber.FULL_NAME = 'blubber' Blubber.DURABILITY = 16 @@ -97,7 +121,8 @@ Blubber.armor.resistance = { ------------------------- ------------------------------------------ local Gel = class('Gel', OrganicArmor) -{ +OrganicArmor.list[#OrganicArmor.list+1] = 'Gel' + Gel.FULL_NAME = 'gel' Gel.DURABILITY = 32 @@ -111,6 +136,7 @@ Gel.armor.resistance = { ------------------------------------------------------------------- local Bone = class('Bone', OrganicArmor) +OrganicArmor.list[#OrganicArmor.list+1] = 'Bone' Bone.FULL_NAME = 'bone' Bone.DURABILITY = 8 From df742d8a0586981c0e0764aeddba416c3953afb1 Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 28 Dec 2017 18:45:11 -0600 Subject: [PATCH 20/45] Add degrade_multiplier to Item:failDurabilityCheck --- code/item/item.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/code/item/item.lua b/code/item/item.lua index 1efaeaa..cc55f08 100644 --- a/code/item/item.lua +++ b/code/item/item.lua @@ -37,7 +37,8 @@ function Item:isReloadable() return self.reload or false end function Item:isSingleUse() return self.DURABILITY == 0 end -function Item:failDurabilityCheck(player) +function Item:failDurabilityCheck(player, degrade_multiplier) + local degrade_multiplier = multiplier or 1 local durability -- need to add a Item.DURABILITY_SKILL for items that are not weapons and check them here with weapons @@ -47,7 +48,7 @@ function Item:failDurabilityCheck(player) durability = player.skills:check(self.weapon.MASTER_SKILL) and math.floor(self.DURABILITY*1.2 + 0.5) or durability end end - return dice.roll(durability or self.DURABILITY) <= 1 + return dice.roll(durability or self.DURABILITY) <= degrade_multiplier end function Item:updateCondition(num) From 77076bdca6946082d01e3fe7530c8e1a8c22875a Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 28 Dec 2017 18:45:34 -0600 Subject: [PATCH 21/45] Add updateArmorDurability method to IsArmor --- code/item/mixin/is_armor.lua | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/code/item/mixin/is_armor.lua b/code/item/mixin/is_armor.lua index 5096854..334fb4c 100644 --- a/code/item/mixin/is_armor.lua +++ b/code/item/mixin/is_armor.lua @@ -1,5 +1,14 @@ local IsArmor = {} +function IsArmor:updateArmorDurability(degrade_multiplier) -- god this method name is horrible, think of something better + local failed_durability_test = self:failDurabilityCheck(player, degrade_multiplier) + local condition + + if failed_durability_test then condition = self:updateCondition(-1) end + + return condition +end + function IsArmor:getProtection(damage_type) local resistance, condition = self.armor.RESISTANCE, self.condition return (resistance[condition] and resistance[condition][damage_type]) or resistance[damage_type] or 0 From 4ca067b0a83c108e78ec59ce800404ed565cf18f Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 28 Dec 2017 18:46:14 -0600 Subject: [PATCH 22/45] Add armor durability code to zombie/human attack --- code/player/human/action/basic.lua | 24 ++++++++++++++++-------- code/player/zombie/action/basic.lua | 17 ++++++++++++----- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/code/player/human/action/basic.lua b/code/player/human/action/basic.lua index 6e1a591..9e08306 100644 --- a/code/player/human/action/basic.lua +++ b/code/player/human/action/basic.lua @@ -131,21 +131,21 @@ function attack.server_criteria(player, target, weapon, inv_ID) assert(player:isSameLocation(target), 'Target has moved out of range') end -local ARMOR_DAMAGE_MOD = 2.5 - function attack.activate(player, target, weapon, inv_ID) local target_class = target:getClassName() local attack, damage, critical = combat(player, target, weapon) - local condition + local armor_condition, condition + local armor if attack then - if target.armor:isPresent() and not weapon:isHarmless() then + if target.equipment:isPresent('armor') and not weapon:isHarmless() then + armor = target.equipment.armor local damage_type = weapon:getDamageType() - local resistance = target.armor:getProtection(damage_type) + local resistance = armor:getProtection(damage_type) damage = damage - resistance -- do we need to add a desc if resistance is working? (ie absorbing damage in battle log?) - local retailation_damage = target.armor:getProtection('damage_melee_attacker') + local retailation_damage = armor:getProtection('damage_melee_attacker') local is_melee_attack = weapon:getStyle() == 'melee' if is_melee_attack and retailation_damage > 0 then local retailation_hp_loss = -1*dice.roll(retailation_damage) @@ -153,8 +153,9 @@ function attack.activate(player, target, weapon, inv_ID) -- insert some type of event? end - local degrade_chance = math.floor(damage/ARMOR_DAMAGE_MOD) + 1 -- might wanna change this later? Damage affects degrade chance? - if target.armor:failDurabilityCheck(degrade_chance) then target.armor:degrade(target) end + local degrade_multiplier = 1 -- player.skills:check() some armor breaking skill? + armor_condition = armor:updateArmorDurability(degrade_multiplier) + if armor_condiiton == 0 then target.equipment:remove('armor') end end if target.skills:check('track') then @@ -199,6 +200,13 @@ function attack.activate(player, target, weapon, inv_ID) self_msg = self_msg..'Your '..tostring(weapon)..' degrades to a '..weapon:getConditionState()..' state.' end + if armor_condition == 0 then + self_msg = self_msg..'Their '..tostring(armor)..' is destroyed!' end + target_msg = target_msg..'Your '..tostring(armor)..' is destroyed!' + --elseif armor_condition and armor:isConditionVisible(target) then (should organic armor condition be visible to zombies?) + -- target_msg = target_msg..'Your '..tostring(armor)..' degrades to a '..armor:getConditionState()..' state.' + end + -------------------------------------------- --------- B R O A D C A S T ------------ -------------------------------------------- diff --git a/code/player/zombie/action/basic.lua b/code/player/zombie/action/basic.lua index 6acc62a..2f26e22 100644 --- a/code/player/zombie/action/basic.lua +++ b/code/player/zombie/action/basic.lua @@ -117,12 +117,11 @@ function attack.server_criteria(player, target, weapon) end end -local ARMOR_DAMAGE_MOD = 2.5 - function attack.activate(player, target, weapon) local target_class = target:getClassName() local attack, damage, critical = combat(player, target, weapon) local caused_infection + local armor_condition, armor if attack then if target_class == 'player' then @@ -140,8 +139,9 @@ function attack.activate(player, target, weapon) -- insert some type of event? end - local degrade_chance = math.floor(damage/ARMOR_DAMAGE_MOD) + 1 -- might wanna change this later? Damage affects degrade chance? - if target.armor:failDurabilityCheck(degrade_chance) then target.armor:degrade(target) end + local degrade_multiplier = player.skills:check('power_claw') and 2 or 1 + armor_condition = armor:updateArmorDurability(degrade_multiplier) + if armor_condiiton == 0 then target.equipment:remove('armor') end end if player.skills:check('track') then @@ -200,7 +200,14 @@ function attack.activate(player, target, weapon) -- infection message to the ZOMBIE only! (human isn't notified until incubation wears off) if caused_infection then self_msg = self_msg .. ' They become infected.' end - + + if armor_condition == 0 then + self_msg = self_msg..'Their '..tostring(armor)..' is destroyed!' end + target_msg = target_msg..'Your '..tostring(armor)..' is destroyed!' + elseif armor_condition and armor:isConditionVisible(target) then + target_msg = target_msg..'Your '..tostring(armor)..' degrades to a '..armor:getConditionState()..' state.' + end + -------------------------------------------- --------- B R O A D C A S T ------------ -------------------------------------------- From 8f7c3bf9981f27de51256d83a93a762bc6424e97 Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 28 Dec 2017 22:06:35 -0600 Subject: [PATCH 23/45] Fix armor classes missing armor table field --- code/item/items/armor.lua | 2 ++ code/player/zombie/organic_armor.lua | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/code/item/items/armor.lua b/code/item/items/armor.lua index ccb98e2..1c88570 100644 --- a/code/item/items/armor.lua +++ b/code/item/items/armor.lua @@ -40,6 +40,7 @@ Leather.FULL_NAME = 'leather jacket' Leather.DURABILITY = 32 Leather.CATEGORY = 'military' +Leather.armor = {} Leather.armor.resistance = {blunt=1} ------------------------------------------------------------------- @@ -50,6 +51,7 @@ Firesuit.FULL_NAME = 'firesuit' Firesuit.DURABILITY = 4 Firesuit.CATEGORY = 'military' +Firesuit.armor = {} Firesuit.armor.resistance = { {acid=1}, {acid=2}, diff --git a/code/player/zombie/organic_armor.lua b/code/player/zombie/organic_armor.lua index 2f9fda3..1086bf0 100644 --- a/code/player/zombie/organic_armor.lua +++ b/code/player/zombie/organic_armor.lua @@ -96,6 +96,7 @@ OrganicArmor.list[#OrganicArmor.list+1] = 'Scale' Scale.FULL_NAME = 'scale' Scale.DURABILITY = 8 +Scale.armor = {} Scale.armor.resistance = { {bullet=1, pierce=1}, {bullet=2, blunt=1, pierce=2}, @@ -111,6 +112,7 @@ OrganicArmor.list[#OrganicArmor.list+1] = 'Blubber' Blubber.FULL_NAME = 'blubber' Blubber.DURABILITY = 16 +Blubber.armor = {} Blubber.armor.resistance = { { blunt=1, pierce=1}, {bullet=1, blunt=1, pierce=1}, @@ -126,6 +128,7 @@ OrganicArmor.list[#OrganicArmor.list+1] = 'Gel' Gel.FULL_NAME = 'gel' Gel.DURABILITY = 32 +Gel.armor = {} Gel.armor.resistance = { { blunt=1, pierce=1, scorch=4}, { blunt=1, pierce=1, scorch=4}, @@ -141,6 +144,7 @@ OrganicArmor.list[#OrganicArmor.list+1] = 'Bone' Bone.FULL_NAME = 'bone' Bone.DURABILITY = 8 +Bone.armor = {} Bone.armor.resistance = { {damage_melee_attacker=1}, {damage_melee_attacker=1}, From 076ab31a5bc610d6fb89a3f8e8a9d66e7f8b440c Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 28 Dec 2017 22:10:13 -0600 Subject: [PATCH 24/45] Fix end statement typo --- code/player/human/action/basic.lua | 2 +- code/player/zombie/action/basic.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/player/human/action/basic.lua b/code/player/human/action/basic.lua index 9e08306..9db9011 100644 --- a/code/player/human/action/basic.lua +++ b/code/player/human/action/basic.lua @@ -201,7 +201,7 @@ function attack.activate(player, target, weapon, inv_ID) end if armor_condition == 0 then - self_msg = self_msg..'Their '..tostring(armor)..' is destroyed!' end + self_msg = self_msg..'Their '..tostring(armor)..' is destroyed!' target_msg = target_msg..'Your '..tostring(armor)..' is destroyed!' --elseif armor_condition and armor:isConditionVisible(target) then (should organic armor condition be visible to zombies?) -- target_msg = target_msg..'Your '..tostring(armor)..' degrades to a '..armor:getConditionState()..' state.' diff --git a/code/player/zombie/action/basic.lua b/code/player/zombie/action/basic.lua index 2f26e22..3a64f28 100644 --- a/code/player/zombie/action/basic.lua +++ b/code/player/zombie/action/basic.lua @@ -202,7 +202,7 @@ function attack.activate(player, target, weapon) if caused_infection then self_msg = self_msg .. ' They become infected.' end if armor_condition == 0 then - self_msg = self_msg..'Their '..tostring(armor)..' is destroyed!' end + self_msg = self_msg..'Their '..tostring(armor)..' is destroyed!' target_msg = target_msg..'Your '..tostring(armor)..' is destroyed!' elseif armor_condition and armor:isConditionVisible(target) then target_msg = target_msg..'Your '..tostring(armor)..' degrades to a '..armor:getConditionState()..' state.' From 0eed21104d9dbf76b8d0b93a43863b54e23e993d Mon Sep 17 00:00:00 2001 From: Timothy Date: Thu, 28 Dec 2017 22:11:36 -0600 Subject: [PATCH 25/45] Remove old armor code --- code/work-in-progress/armor/class.lua | 36 -------- code/work-in-progress/armor/is_armor.lua | 8 -- code/work-in-progress/armor/organic_class.lua | 83 ------------------- code/work-in-progress/armor/organic_list.lua | 46 ---------- 4 files changed, 173 deletions(-) delete mode 100644 code/work-in-progress/armor/class.lua delete mode 100644 code/work-in-progress/armor/is_armor.lua delete mode 100644 code/work-in-progress/armor/organic_class.lua delete mode 100644 code/work-in-progress/armor/organic_list.lua diff --git a/code/work-in-progress/armor/class.lua b/code/work-in-progress/armor/class.lua deleted file mode 100644 index 2f03b5a..0000000 --- a/code/work-in-progress/armor/class.lua +++ /dev/null @@ -1,36 +0,0 @@ -local dice = require('code.libs.dice') -local item_armor_list = require('code.player.armor.item_list') -local class = require('code.libs.middleclass') - -local armor = class('armor') - -function armor:initialize(player) - self.player = player -end - --- Possibly consider redoing armor for the zombies? Make it similiar to human armor or less complex... if it's made to be similiar to human armor, it will shrink --- down the code in this file quite a bit, no need to differenate between human/zombie mobtypes - -function armor:failDurabilityCheck(degrade_chance) - local player, protection = self.player - - if player:isMobType('human') then return dice.roll(item_armor_list[self.name].durability) <= degrade_chance - elseif player:isMobType('zombie') then return dice.roll(self.durability) <= degrade_chance - end -end - -function armor:getProtection(damage_type) - local player, protection = self.player - - if player:isMobType('human') then return item_armor_list[self.name].resistance[self.condition][damage_type] or 0 - elseif player:isMobType('zombie') then return self.protection[damage_type] or 0 - end -end - -function armor:isPresent() - if player:isMobType('human') then return self.name and true or false - elseif player:isMobType('zombie') then return self.protection and true or false - end -end - -return armor \ No newline at end of file diff --git a/code/work-in-progress/armor/is_armor.lua b/code/work-in-progress/armor/is_armor.lua deleted file mode 100644 index 0032357..0000000 --- a/code/work-in-progress/armor/is_armor.lua +++ /dev/null @@ -1,8 +0,0 @@ -local IsArmor = {} - -function IsArmor:getProtection(damage_type) - local resistance, condition = self.armor.resistance, self.condition - return (resistance[condition] and resistance[condition][damage_type]) or resistance[damage_type] or 0 -end - -return IsArmor \ No newline at end of file diff --git a/code/work-in-progress/armor/organic_class.lua b/code/work-in-progress/armor/organic_class.lua deleted file mode 100644 index 72c72cd..0000000 --- a/code/work-in-progress/armor/organic_class.lua +++ /dev/null @@ -1,83 +0,0 @@ -local class = require('code.libs.middleclass') -local organic_armor_list = require('code.player.armor.organic_list') -local armor = require('code.player.armor.class') - -local organic_armor = class('organic_armor', armor) - -function organic_armor:initialize(player) - armor.initialize(self, player) - self.layers = {} - self.player = player -end - -local LAYER_STACKING_MULTIPLYER = {0, 1/8, 2/8, 4/8} - -local function calculateDurability(layers) - local mean = 0 - for _, armor_type in ipairs(layers) do - local stack = layers[armor_type] - local multiplyer = 1 + LAYER_STACKING_MULTIPLYER[stack] - mean = mean + (organic_armor_list[armor_type].durability * multiplyer) - end - return math.floor(mean/#layers + 0.5) -- returns a rounded integer -end - --- PER LEVEL OF ARMOR -local organic_resistance_values = {bullet=2, blunt=1, pierce=1, scorch=1, damage_melee_attacker=1} - -function organic_armor:equip(armor_name) - self.protection = self.protection or {} - - local resistance = organic_armor_list[armor_name].resistance - if resistance then - local value = organic_resistance_values[resistance] - self.protection[resistance] = (self.protection[resistance] or 0) + value - end - - self.layers[#self.layers+1] = armor_name - self.layers[armor_name] = (self.layers[armor_name] or 0) + 1 - - self.durability = calculateDurability(self.layers) -end - -function organic_armor:degrade() - local armor_name = self.layers[#self.layers] - local resistance = organic_armor_list[armor_name].resistance - - if resistance then - self.protection[resistance] = self.protection[resistance] - organic_resistance_values[resistance] - end - - self.layers[#self.layers] = nil - self.layers[armor_name] = self.layers[armor_name] - 1 - - if #self.layers == 0 then -- armor is destroyed - local player = self.player - player.armor = organic_armor:new(player) - return -- something?? - else - self.durability = calculateDurability(self.layers) - end -end - -local MAX_ORGANIC_LAYERS = 4 - -function organic_armor:hasRoomForLayer() return MAX_ORGANIC_LAYERS > #self.layers end - -function organic_armor:getAvailableArmors() - local list = {} - for armor_type in pairs(organic_armor_list) do - local skill = organic_armor_list[armor_type].required_skill - local cost, ep = self.player:getCost('ep', armor_type), self.player:getStat('ep') - list[armor_type] = (self.player.skills:check(skill) and ep >= cost) or nil - print(armor_type, list[armor_type]) - end - - print() - print('THIS IS OUR ARMOR LIST') - for k,v in pairs(list) do print(k,v) end - - return list -end - -return organic_armor \ No newline at end of file diff --git a/code/work-in-progress/armor/organic_list.lua b/code/work-in-progress/armor/organic_list.lua deleted file mode 100644 index c0d0579..0000000 --- a/code/work-in-progress/armor/organic_list.lua +++ /dev/null @@ -1,46 +0,0 @@ -local armor = {} - ---[[ - full_name = 'insert name' - resistance = bullet/pierce/blunt/scorch/damage_melee_attacker/nil - durability = num (average # of attacks it takes to wear armor out) - required_skill = 'skill name' ---]] - -armor.scale = {} -armor.scale.full_name = 'scale' -armor.scale.resistance = 'pierce' -armor.scale.durability = 16 -armor.scale.required_skill = 'armor' - -armor.blubber = {} -armor.blubber.full_name = 'blubber' -armor.blubber.resistance = 'blunt' -- dampens impact energy -armor.blubber.durability = 16 -armor.blubber.required_skill = 'armor' - -armor.stretch = {} -armor.stretch.full_name = 'stretch' -armor.stretch.resistance = 'bullet' -armor.stretch.durability = 8 -armor.stretch.required_skill = 'ranged_armor' - -armor.gel = {} -armor.gel.full_name = 'gel' -armor.gel.resistance = 'scorch' -armor.gel.durability = 16 -armor.gel.required_skill = 'liquid_armor' - -armor.sticky = {} -armor.sticky.full_name = 'sticky' -armor.sticky.resistance = nil -- sticky armor lacks resistance but greatly improves durability -armor.sticky.durability = 32 -armor.sticky.required_skill = 'liquid_armor' - -armor.bone = {} -armor.bone.full_name = 'bone' -armor.bone.resistance = 'damage_melee_attacker' -armor.bone.durability = 8 -armor.bone.required_skill = 'pain_armor' - -return armor \ No newline at end of file From 02ba1e8621de073b82211027e78e8fadd2792d11 Mon Sep 17 00:00:00 2001 From: Timothy Date: Sat, 30 Dec 2017 13:40:47 -0600 Subject: [PATCH 26/45] Add discord server to README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index dc8b0c9..b17f2ed 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ ZomboTropolis ============= +Join the [Discord Server](https://discord.gg/cnHUgMt) + An **unfinished** zombie survival MMO using Corona and Lua. Play as either a zombie or a human in a fight for survival. The game is set to replicate a [prey-predator model](http://www.tiem.utk.edu/~gross/bioed/bealsmodules/pred-prey.gph1.gif) of population. Human Survivor From d2e3957dca2eeb60cc9806dc292d1afc844c33e0 Mon Sep 17 00:00:00 2001 From: Timothy Date: Sat, 30 Dec 2017 13:41:27 -0600 Subject: [PATCH 27/45] Add "What about PK'ing" question --- FAQ.md | 75 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/FAQ.md b/FAQ.md index f8966e9..b598bc1 100644 --- a/FAQ.md +++ b/FAQ.md @@ -2,69 +2,80 @@ *(Note - I will here forth refer to ZomboTropolis as ZT, Urbandead as UD, and Quarantine2019 as Q)* ->Multiple major and distinct differences. +Multiple major and distinct differences. ->**Platform:** ZT is going to be an app for mobile. Browser based games are dying, any remake needs to address this. The app market has a huge playerbase that keeps growing, and for games such as this, the complexity of getting a decent user interface for mobile is pretty doable. Push notifications also present a major advantage over browsers when it comes to in game events. +**Platform:** ZT is going to be an app for mobile. Browser based games are dying, any remake needs to address this. The app market has a huge playerbase that keeps growing, and for games such as this, the complexity of getting a decent user interface for mobile is pretty doable. Push notifications also present a major advantage over browsers when it comes to in game events. ->**Graphics:** ZT is going to be using sprites for the characters, locations, and skills from free art assets. (Space Station 13, game-icons.net, etc.) This is a __MUST HAVE__ for an app on the app store. Without graphics there would be no playerbase! (although the hardcore vets will still play regardless) +**Graphics:** ZT is going to be using sprites for the characters, locations, and skills from free art assets. (Space Station 13, game-icons.net, etc.) This is a __MUST HAVE__ for an app on the app store. Without graphics there would be no playerbase! (although the hardcore vets will still play regardless) ->**Gameplay for UD:** ->UD was a simple game, with basic math calculations and combat. Survivors had items, safehouses, and equipment. Zombies had abilities that were rather... plain. The skills for both sides complemented the above rather well, but none of it was groundbreaking. Neither side in the game could truly win. When one side started to win, the code in the game would nerf the other side. What gave this game so much life was the *community*. They were so active and fun to play with and it gave the game a rich and immersive history. The map for the game was huge! There were endless suburbs and buildings, not to mention distinct landmarks such as malls, churches, and mansions that were fun to discover and explore. One problem with a map this size was population. If population for the game dipped to low (and it did) then large portions of the map became ghost towns. Kevan (the developer) did test out new maps with permadeath enabled. This briefly revitalized the playerbase, although each of these maps are now over with. +**Gameplay for UD:** +UD was a simple game, with basic math calculations and combat. Survivors had items, safehouses, and equipment. Zombies had abilities that were rather... plain. The skills for both sides complemented the above rather well, but none of it was groundbreaking. Neither side in the game could truly win. When one side started to win, the code in the game would nerf the other side. What gave this game so much life was the *community*. They were so active and fun to play with and it gave the game a rich and immersive history. The map for the game was huge! There were endless suburbs and buildings, not to mention distinct landmarks such as malls, churches, and mansions that were fun to discover and explore. One problem with a map this size was population. If population for the game dipped to low (and it did) then large portions of the map became ghost towns. Kevan (the developer) did test out new maps with permadeath enabled. This briefly revitalized the playerbase, although each of these maps are now over with. ->**Gameplay for Q:** ->Q was a remake of UD with the intention of adding more complexity, features, and a end goal for both sides. With Q, you could actually win the game for your side! By playing through a round based system, zombies could either eliminate all humans, or humans could research the cure to win the game. Maps for Q were much smaller and tailored to the size of the population. One notable thing that Q did was to split skills into classes. Certain zombies were given abilities that others did not have, and vice-versa for humans. While this was a great idea, I believe it was executed poorly. Some skills were worthless, others were unbalanced. Some classes only had one utility they were good for and nothing else. (which made gameplay dull and repetitive for that class) Other features and systems seemed to be designed without proper planning. Staircases and multi-level buildings served no purpose, infection was unrealistic and unpractical, and resource points for buildings was just plain weird. It had it's flaws but I respected what the developers of Q were trying to do. UD had been neglected with updates, and Q was trying to branch off into a much better version. And to be fair, Q did come up with some really great stuff! Power plant buildings that powered entire suburbs, computers could network with ISP buildings, items had durability, etc. etc. Q only had a fraction of the population that UD had, so their rounds and maps were rather quick and small. Still lots of fun to play back in the day though! +**Gameplay for Q:** +Q was a remake of UD with the intention of adding more complexity, features, and a end goal for both sides. With Q, you could actually win the game for your side! By playing through a round based system, zombies could either eliminate all humans, or humans could research the cure to win the game. Maps for Q were much smaller and tailored to the size of the population. One notable thing that Q did was to split skills into classes. Certain zombies were given abilities that others did not have, and vice-versa for humans. While this was a great idea, I believe it was executed poorly. Some skills were worthless, others were unbalanced. Some classes only had one utility they were good for and nothing else. (which made gameplay dull and repetitive for that class) Other features and systems seemed to be designed without proper planning. Staircases and multi-level buildings served no purpose, infection was unrealistic and unpractical, and resource points for buildings was just plain weird. It had it's flaws but I respected what the developers of Q were trying to do. UD had been neglected with updates, and Q was trying to branch off into a much better version. And to be fair, Q did come up with some really great stuff! Power plant buildings that powered entire suburbs, computers could network with ISP buildings, items had durability, etc. etc. Q only had a fraction of the population that UD had, so their rounds and maps were rather quick and small. Still lots of fun to play back in the day though! ->**Gameplay for ZT:** ->ZT seeks to take both of these games a step further and add roguelike features and complexity to the code. All skills, abilities, and items in the game use dice rolls and dice modifiers to function. This has been implemented in a (mostly) balanced fashion. +**Gameplay for ZT:** +ZT seeks to take both of these games a step further and add roguelike features and complexity to the code. All skills, abilities, and items in the game use dice rolls and dice modifiers to function. This has been implemented in a (mostly) balanced fashion. ->Just like UD, there is a persistent world, but with rubber banding enabled that stretches the map based on population size. Respawns for the game are always enabled, but a player will lose all their items, abilities, and skills upon permadeath. Permadeath is triggered for humans upon death, and zombies upon starvation. The goal is to follow a [prey/predator model](http://www.tiem.utk.edu/~gross/bioed/bealsmodules/pred-prey.gph1.gif) of graphing. +Just like UD, there is a persistent world, but with rubber banding enabled that stretches the map based on population size. Respawns for the game are always enabled, but a player will lose all their items, abilities, and skills upon permadeath. Permadeath is triggered for humans upon death, and zombies upon starvation. The goal is to follow a [prey/predator model](http://www.tiem.utk.edu/~gross/bioed/bealsmodules/pred-prey.gph1.gif) of graphing. ->Leveling is based on time. Players are no longer forced to heal, fight, or repair things to gain experience. The longer a player's character survives in the game, the more experience they earn to unlock skills. The skill system is setup to exponentially increase the skill cost after prior skills have been purchased. With enough time, a player can even unlock a special class with it's own special abilities to enhance a certain playstyle. +Leveling is based on time. Players are no longer forced to heal, fight, or repair things to gain experience. The longer a player's character survives in the game, the more experience they earn to unlock skills. The skill system is setup to exponentially increase the skill cost after prior skills have been purchased. With enough time, a player can even unlock a special class with it's own special abilities to enhance a certain playstyle. ->Items and equipment in the game possess a condition value that will enhance or degrade its functionality. Each class can see relevant condition data based on the type of object. (military class can see weapon conditions, engineering class can see equipment and barricade conditions, etc.) Subsequent uses of an item or equipment eventually decreases the condition, yielding lower dice rolls or performance results. For instance, a generator that is "pristine" condition will use fuel more efficiently than the "ruined" condition. Additionally, searching in buildings when they are ruined yields items of lower quality. (including lowered search rates) +Items and equipment in the game possess a condition value that will enhance or degrade its functionality. Each class can see relevant condition data based on the type of object. (military class can see weapon conditions, engineering class can see equipment and barricade conditions, etc.) Subsequent uses of an item or equipment eventually decreases the condition, yielding lower dice rolls or performance results. For instance, a generator that is "pristine" condition will use fuel more efficiently than the "ruined" condition. Additionally, searching in buildings when they are ruined yields items of lower quality. (including lowered search rates) ->A lot more features have been added to ZT than in Q and UD. A quick list as follows, +A lot more features have been added to ZT than in Q and UD. A quick list as follows, ->+ Hunter zombie function as scouts. They can hide in unlit buildings, track players scent, free-run from ruined buildings into unruined buildings, move faster than other zombies (movement cost 1 AP), blood vision (x-ray) to see wounded characters from outside. ->+ Brute zombies function as tanks. They can maim humans (reduce their hp permanently), generate organic armor from corpses, drag prey out into the streets, and destroy barricades/equipment/armor more effectively ->+ Hive zombies function as support. They can ruin buildings, corrode human inventory with acid, deliver infection with bites, and communicate with all zombies via the hivemind. ++ Hunter zombie function as scouts. They can hide in unlit buildings, track players scent, free-run from ruined buildings into unruined buildings, move faster than other zombies (movement cost 1 AP), blood vision (x-ray) to see wounded characters from outside. ++ Brute zombies function as tanks. They can maim humans (reduce their hp permanently), generate organic armor from corpses, drag prey out into the streets, and destroy barricades/equipment/armor more effectively ++ Hive zombies function as support. They can ruin buildings, corrode human inventory with acid, deliver infection with bites, and communicate with all zombies via the hivemind. ->+ Engineers are builders. They can repair ruins, barricade to higher levels, and install equipment faster. ->+ Military are fighters. They can master any weapon, maim zombies, and give a bonus to safehouse defenses. ->+ Researchers are healers. They can heal efficiently, scan zombies, use terminals (gives info about surroundings), and create antidotes. ++ Engineers are builders. They can repair ruins, barricade to higher levels, and install equipment faster. ++ Military are fighters. They can master any weapon, maim zombies, and give a bonus to safehouse defenses. ++ Researchers are healers. They can heal efficiently, scan zombies, use terminals (gives info about surroundings), and create antidotes. ->While humans generally do not have restrictions to their actions, certain actions will greatly benefit from skills from one class. +While humans generally do not have restrictions to their actions, certain actions will greatly benefit from skills from one class. ### Q: Roguelike?! With permadeath, dice and stuff? ->Yes. If you die (as a human) or starve (as a zombie) then it's game over. Fortunately, respawning is easy and you won't be completely useless with a new character. With ZT, your goal is to see how long you can survive, and if I have developed the game correctly, this should be hard for both sides. +Yes. If you die (as a human) or starve (as a zombie) then it's game over. Fortunately, respawning is easy and you won't be completely useless with a new character. With ZT, your goal is to see how long you can survive, and if I have developed the game correctly, this should be hard for both sides. ->Regarding dice, I felt like both UD and Q suffered from using what I call 'basic' math. Weapons and items always did `x` amount of effect. That wasn't realistic and pretty boring for gameplay. So by adding dice it would allow ZT to be more dynamic! Weapons in better condition do more damage or have better accuracy. Skills either boost accuracy or grant rerolls to weapon attacks that successfully land. This is a powerful system that works well and allows for interesting possibilities. +Regarding dice, I felt like both UD and Q suffered from using what I call 'basic' math. Weapons and items always did `x` amount of effect. That wasn't realistic and pretty boring for gameplay. So by adding dice it would allow ZT to be more dynamic! Weapons in better condition do more damage or have better accuracy. Skills either boost accuracy or grant rerolls to weapon attacks that successfully land. This is a powerful system that works well and allows for interesting possibilities. + +### Q: What about PK'ing? + +Player killing is going to be disabled for both sides. So a human cannot kill other humans, and vice-versa for zombies. It would be too game breaking to have this feature enabled with permadeath functioning. + +Additionally: + +* It is not possible for humans to attack or destroy equipment in buildings. +* Humans can enter buildings regardless of barricade levels (thus no overcade griefing) + +To enable these things would be the trivial task of removing a few lines of code. This may get added as a feature to a new map (such as Monroeville), or in game event (a dark fog), or a map subsection (sewers). Don't expect it to be a normal occurrence in game though. ### Q: Will this be free? What is the monetization plan? ->Free for freedom! Yes, it will be free. The monetization plan I have in mind is to have an occasional ad inserted into the game. (probably after AP is used) Another source of funding is to have cosmetic items in game that can be unlocked via purchasing tokens or surviving for `x` amount of days. +Free for freedom! Yes, it will be free. The monetization plan I have in mind is to have an occasional ad inserted into the game. (probably after AP is used) Another source of funding is to have cosmetic items in game that can be unlocked via purchasing tokens or surviving for `x` amount of days. ->Money will not give a person an in game advantage. This will keep the game true to it's predecessors! :) +Money will not give a person an in game advantage. This will keep the game true to it's predecessors! :) ### Q: When will the game be playable/finished? ->I'm aiming for development to be finished around Spring 2018. The app should launch shortly after that time frame. +I'm aiming for development to be finished around Spring 2018. The app should launch shortly after that time frame. ### Q: How long has this been in development? ->I have been developing ZT for a few years off and on in my free time. This last year I have made tremendous progress, and the game is now close to being finished. I have worked on other smaller projects, but this game has been my most ambitious yet. +I have been developing ZT for a few years off and on in my free time. This last year I have made tremendous progress, and the game is now close to being finished. I have worked on other smaller projects, but this game has been my most ambitious yet. ### Q: What about modding? ->I will be looking at modding ZT to other themes since my API and source code is pretty robust. It shouldn't be that hard to switch it to something like say, Ninjas vs Samurais, heh. +I will be looking at modding ZT to other themes since my API and source code is pretty robust. It shouldn't be that hard to switch it to something like say, Ninjas vs Samurais, heh. ### Q: How can I help? ->I need help with the following: +I need help with the following: ->+ Playtesters in a few months ->+ Setting up a ZT game wiki ->+ People to bounce ideas off ++ Playtesters in a few months ++ Setting up a ZT game wiki ++ People to bounce ideas off ->I am **not** looking for other coders or artists to contribute at this time. After launch this may change. +I am **not** looking for other coders or artists to contribute at this time. After launch this may change. From 39428dae9c58748ab932e554dac73353397bd1d7 Mon Sep 17 00:00:00 2001 From: Timothy Date: Sun, 31 Dec 2017 12:47:32 -0600 Subject: [PATCH 28/45] Change toolbox durability and ap cost --- code/item/items/tools.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/code/item/items/tools.lua b/code/item/items/tools.lua index 9771cd4..ae74854 100644 --- a/code/item/items/tools.lua +++ b/code/item/items/tools.lua @@ -90,12 +90,13 @@ local Toolbox = class('Toolbox', Item) Toolbox.FULL_NAME = 'toolbox' Toolbox.WEIGHT = 15 -Toolbox.DURABILITY = 10 +Toolbox.DURABILITY = 1 Toolbox.CATEGORY = 'engineering' -Toolbox.ap = {cost = 10, modifier = {repair = -2, repair_adv = -3}} --{cost= 5, modifier={repair= -1, repair_adv = -1}} +Toolbox.ap = {cost = 5, modifier = {repair = -1, repair_adv = -2}} function Toolbox:client_criteria(player) assert(player:isStaged('inside'), 'Must be inside building to repair') + -- need to look for door, integrity, and equipment local p_tile = player:getTile() local can_repair_building = p_tile.integrity:canModify(player) assert(can_repair_building, 'Unable to repair building in current state') From 5afd63b6d1cdc3c1e4063177aca31e15b9c52892 Mon Sep 17 00:00:00 2001 From: Timothy Date: Sun, 31 Dec 2017 14:12:39 -0600 Subject: [PATCH 29/45] Change building integrity class ransack/ruin forumla --- code/location/tile/building/integrity.lua | 27 +++++++++-------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/code/location/tile/building/integrity.lua b/code/location/tile/building/integrity.lua index a7ec529..ec3abc9 100644 --- a/code/location/tile/building/integrity.lua +++ b/code/location/tile/building/integrity.lua @@ -2,25 +2,21 @@ local class = require('code.libs.middleclass') local Integrity = class('Integrity') -local BUILDING_MAX_HP = 20 --{15, 20, 30, ???} this is a HP table based on building sizes -local RANSACK_VALUE = BUILDING_MAX_HP - 10 -local MAX_DECAY = -60 - function Integrity:initialize(building) self.building = building - self.hp = BUILDING_MAX_HP -- Update this later to the size of the building (all buildilng are 1 tile sized right now) + self.hp = building.MAX_INTEGRITY end function Integrity:updateHP(num) - self.hp = math.min(math.max(self.hp+num, MAX_DECAY), BUILDING_MAX_HP) + local max_hp, max_decay = self.building.MAX_INTEGRITY, -1*self.building.MAX_INTEGRITY + + self.hp = math.min(math.max(self.hp+num, max_decay), max_hp) - if self.hp >= 0 or self.hp == MAX_DECAY then + if self.hp > 0 or self.hp == max_decay then --remove building from decay list - elseif self.hp < 0 then + elseif self.hp <= 0 then --add building to decay list end - - self:updateDesc() end function Integrity:canModify(player) -- possibly move all or parts of this code to criteria.toolbox and critera.ransack? @@ -44,14 +40,11 @@ end function Integrity:isState(setting) return self:getState() == setting end function Integrity:getState() - local integrity_is_full = self.hp == BUILDING_MAX_HP - local integrity_within_ransack_range = self.hp >= 0 - local integrity_within_ruin_range = self.hp < 0 - return (integrity_is_full and 'intact') or (integrity_within_ransack_range and 'ransacked') or (integrity_within_ruin_range and 'ruined') + local integrity_is_full = self.hp == self.building.MAX_INTEGRITY + local integrity_is_ransacked = self.hp > 0 + return (integrity_is_full and 'intact') or (integrity_is_ransacked and 'ransacked') or 'ruined' end ---function Integrity:getHP() return self.hp end - -function Integrity:updateDesc() end +function Integrity:getHP() return self.hp end return Integrity \ No newline at end of file From a2d837cc910ecd32d27aa2b8405de8f7df34db90 Mon Sep 17 00:00:00 2001 From: Timothy Date: Sun, 31 Dec 2017 14:13:15 -0600 Subject: [PATCH 30/45] Change zombie ransack ability to ruin, redo criteria --- code/player/zombie/ability/generic.lua | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/code/player/zombie/ability/generic.lua b/code/player/zombie/ability/generic.lua index 84959e2..71accf9 100644 --- a/code/player/zombie/ability/generic.lua +++ b/code/player/zombie/ability/generic.lua @@ -236,26 +236,24 @@ end ------------------------------------------------------------------- -local ransack = {name='ransack', ap={cost=5, modifier={ransack = -1, ruin = -2}}} +local ruin = {name='ruin', ap={cost=5, modifier={ruin = -1, ruin_adv = -2}}} -function ransack.client_criteria(player) - local p_tile = player:getTile() - assert(p_tile:isBuilding(), 'No building nearby to ransack') - assert(player:isStaged('inside'), 'Player must be inside building to ransack') - - local can_ransack_building = p_tile.integrity:canModify(player) - assert(can_ransack_building, 'Unable to ransack building in current state') -end -function ransack.server_criteria(player) + +function ruin.client_criteria(player) local p_tile = player:getTile() assert(p_tile:isBuilding(), 'No building nearby to ransack') assert(player:isStaged('inside'), 'Player must be inside building to ransack') - - local can_ransack_building = p_tile.integrity:canModify(player) - assert(can_ransack_building, 'Unable to ransack building in current state') + + assert(player.skills:check('ruin'), 'Must have "ruin" skill to use ability') -- remove this later when abilities implement required_skill + + local n_humans = self.building:countPlayers('human', 'inside') + local integrity_hp = p_tile.integrity:getHP() + assert(integrity_hp > 0 or (integrity_hp == 0 and n_humans == 0), 'Cannot ruin building ') end +ruin.server_criteria = ruin.client_criteria + function ransack.activate(player) local ransack_dice = dice:new('2d3') if player.skills:check('ransack') then ransack_dice = ransack_dice / 1 end From 08f16814e31347bf0bbe490990fafbe3afff4463 Mon Sep 17 00:00:00 2001 From: Timothy Date: Sun, 31 Dec 2017 14:17:27 -0600 Subject: [PATCH 31/45] Change ruin.activate code to updateHP(-1) --- code/player/zombie/ability/generic.lua | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/code/player/zombie/ability/generic.lua b/code/player/zombie/ability/generic.lua index 71accf9..df5b5ff 100644 --- a/code/player/zombie/ability/generic.lua +++ b/code/player/zombie/ability/generic.lua @@ -254,15 +254,11 @@ end ruin.server_criteria = ruin.client_criteria -function ransack.activate(player) - local ransack_dice = dice:new('2d3') - if player.skills:check('ransack') then ransack_dice = ransack_dice / 1 end - if player.skills:check('ruin') then ransack_dice = ransack_dice ^ 4 end - +function ruin.activate(player) local building = player:getTile() - building.integrity:updateHP(-1 * ransack_dice:roll() ) + building.integrity:updateHP(-1) local integrity_state = building.integrity:getState() - local building_was_ransacked = integrity_state == 'ransacked' --local building_was_ruined = integrity_state == 'ruined' + local building_was_ransacked = integrity_state == 'ransacked' -------------------------------------------- ----------- M E S S A G E -------------- @@ -279,7 +275,7 @@ function ransack.activate(player) --------- B R O A D C A S T ------------ -------------------------------------------- - local event = {'ransack', player, integrity_state} + local event = {'ruin', player, integrity_state} player:broadcastEvent(msg, self_msg, event) end From df40e97c7638a37690c86ec9174d7b371fb00488 Mon Sep 17 00:00:00 2001 From: Timothy Date: Sun, 31 Dec 2017 14:18:00 -0600 Subject: [PATCH 32/45] Remove whitespace from generic abilities --- code/player/zombie/ability/generic.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/code/player/zombie/ability/generic.lua b/code/player/zombie/ability/generic.lua index df5b5ff..8ca8f35 100644 --- a/code/player/zombie/ability/generic.lua +++ b/code/player/zombie/ability/generic.lua @@ -238,8 +238,6 @@ end local ruin = {name='ruin', ap={cost=5, modifier={ruin = -1, ruin_adv = -2}}} - - function ruin.client_criteria(player) local p_tile = player:getTile() assert(p_tile:isBuilding(), 'No building nearby to ransack') From 46192e834c9777fa714ab52493fcc2681d584da8 Mon Sep 17 00:00:00 2001 From: Timothy Date: Sun, 31 Dec 2017 15:07:26 -0600 Subject: [PATCH 33/45] Add isDamaged function to Door class --- code/location/tile/building/door.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/code/location/tile/building/door.lua b/code/location/tile/building/door.lua index 5ab9569..a701157 100644 --- a/code/location/tile/building/door.lua +++ b/code/location/tile/building/door.lua @@ -2,20 +2,18 @@ local class = require('code.libs.middleclass') local Barrier = require('code.location.tile.building.barrier') local Door = class('Door', Barrier) -local default_hp, max_hp = 3, 3 +local DEFAULT_HP, MAX_HP = 3, 3 local door_desc = {[0] = 'destroyed', [1] = 'smashed', [2] = 'dented', [3] = 'undamaged'} function Door:initialize() Barrier.initialize(self) - self.hp = default_hp + self.hp = DEFAULT_HP self.is_open = false - self.hp_desc = door_desc[default_hp] + self.hp_desc = door_desc[DEFAULT_HP] end - - Door.max_hp = max_hp function Door:updateDesc() self.hp_desc = door_desc[self.hp] end @@ -27,6 +25,8 @@ function Door:toggle() self.is_open = not self.is_open end function Door:isDestroyed() return self.hp == 0 end +function Door:isDamaged() return self.hp == MAX_HP + function Door:isOpen() return self.is_open end return Door \ No newline at end of file From 8cd9e6de2faa64b42d8b52836b7fb81bf0199827 Mon Sep 17 00:00:00 2001 From: Timothy Date: Sun, 31 Dec 2017 15:08:22 -0600 Subject: [PATCH 34/45] Remove deprecated Desc code from Door class --- code/location/tile/building/door.lua | 8 -------- 1 file changed, 8 deletions(-) diff --git a/code/location/tile/building/door.lua b/code/location/tile/building/door.lua index a701157..695ca07 100644 --- a/code/location/tile/building/door.lua +++ b/code/location/tile/building/door.lua @@ -4,21 +4,13 @@ local Barrier = require('code.location.tile.building.barrier') local Door = class('Door', Barrier) local DEFAULT_HP, MAX_HP = 3, 3 -local door_desc = {[0] = 'destroyed', [1] = 'smashed', [2] = 'dented', [3] = 'undamaged'} - function Door:initialize() Barrier.initialize(self) self.hp = DEFAULT_HP self.is_open = false - - self.hp_desc = door_desc[DEFAULT_HP] end -function Door:updateDesc() self.hp_desc = door_desc[self.hp] end - -function Door:getDesc() return self.hp_desc end - function Door:repair() self:updateHP(3) end function Door:toggle() self.is_open = not self.is_open end From 77aabb60d48477a60d33feb7d382152ac2820c4a Mon Sep 17 00:00:00 2001 From: Timothy Date: Sun, 31 Dec 2017 15:09:02 -0600 Subject: [PATCH 35/45] Rename equipment to machines in Building:isPresent --- code/location/tile/building/building.lua | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/code/location/tile/building/building.lua b/code/location/tile/building/building.lua index 234c4cb..993fc73 100644 --- a/code/location/tile/building/building.lua +++ b/code/location/tile/building/building.lua @@ -106,14 +106,23 @@ end -- function Building:getPos() return (NO NEED?) function Building:isPresent(setting) - if setting == 'equipment' then - for machine, i in pairs(equipment.subclasses) do + if setting == 'machines' then + + for machine, i in pairs(Machines.subclasses) do if self[machine] then return true end end return false - elseif setting == 'powered equipment' then - return self:isPresent('equipment') and self:isPowered() - else -- individual equipment + + elseif setting == 'powered machines' then + return self:isPresent('machines') and self:isPowered() + elseif setting == 'damaged machines' then + + for machine, i in pairs(Machines.subclasses) do + if self[machine] and self[machine]:isDamaged() then return true end + end + return false + + else -- individual machine local machine = setting return self[machine] end From 6278e32377a71092747f13f4527dd4e191324797 Mon Sep 17 00:00:00 2001 From: Timothy Date: Sun, 31 Dec 2017 15:10:05 -0600 Subject: [PATCH 36/45] Add isDamaged method to Machine class --- code/location/tile/building/machine/machine.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/location/tile/building/machine/machine.lua b/code/location/tile/building/machine/machine.lua index 470f0c1..9c4f926 100644 --- a/code/location/tile/building/machine/machine.lua +++ b/code/location/tile/building/machine/machine.lua @@ -22,6 +22,8 @@ end function Machine:getHP() return self.hp end +function Machine:isDamaged() return self.hp ~= MAX_HP end + function Machine:__tostring() return self.name end --[[ From 0a33c9e345c5030d596e5e844eaa8cbe0b29af72 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 1 Jan 2018 19:59:55 -0600 Subject: [PATCH 37/45] Split asserts to be specific for ruin --- code/player/zombie/ability/generic.lua | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/code/player/zombie/ability/generic.lua b/code/player/zombie/ability/generic.lua index 8ca8f35..43db884 100644 --- a/code/player/zombie/ability/generic.lua +++ b/code/player/zombie/ability/generic.lua @@ -245,9 +245,20 @@ function ruin.client_criteria(player) assert(player.skills:check('ruin'), 'Must have "ruin" skill to use ability') -- remove this later when abilities implement required_skill - local n_humans = self.building:countPlayers('human', 'inside') + + -- integrity code + assert(p_building.integrity:isState('intact'), 'Cannot repair building that has full integrity') + if p_building.integrity:isState('ruined') then + local n_zombies = p_building:countPlayers('zombie', 'inside') + assert(player.skills:check('renovate'), 'Must have "renovate" skill to repair ruins') + assert(n_zombies == 0, 'Cannot repair building with zombies present') + end + + local n_humans = p_tile:countPlayers('human', 'inside') + local integrity_hp = p_tile.integrity:getHP() - assert(integrity_hp > 0 or (integrity_hp == 0 and n_humans == 0), 'Cannot ruin building ') + assert(integrity_hp >= 0, 'Cannot ruin building that is already ruined') + assert(integrity_hp == 0 and n_humans == 0, 'Cannot ruin building with humans present') end ruin.server_criteria = ruin.client_criteria From 4e7521457eb952d10179bdecc6b4420c8d997a6c Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 1 Jan 2018 20:01:11 -0600 Subject: [PATCH 38/45] Add building integrity asserts for toolbox criteria --- code/item/items/tools.lua | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/code/item/items/tools.lua b/code/item/items/tools.lua index ae74854..2ae4cce 100644 --- a/code/item/items/tools.lua +++ b/code/item/items/tools.lua @@ -95,17 +95,24 @@ Toolbox.CATEGORY = 'engineering' Toolbox.ap = {cost = 5, modifier = {repair = -1, repair_adv = -2}} function Toolbox:client_criteria(player) + local p_tile = player:getTile() assert(player:isStaged('inside'), 'Must be inside building to repair') + assert(p_tile:isBuilding(), 'No building nearby to repair') -- need to look for door, integrity, and equipment - local p_tile = player:getTile() - local can_repair_building = p_tile.integrity:canModify(player) - assert(can_repair_building, 'Unable to repair building in current state') + + -- integrity code + local n_zombies = p_tile:countPlayers('zombie', 'inside') + local integrity_hp = p_tile.integrity:getHP() + + assert(player.skills:check('ruin'), 'Must have "ruin" skill to use ability') -- remove this later when abilities implement required_skill + + local n_humans = self.building:countPlayers('human', 'inside') + local integrity_hp = p_tile.integrity:getHP() + assert(integrity_hp > 0 or (integrity_hp == 0 and n_humans == 0), 'Cannot ruin building ') end Toolbox.server_criteria = Toolbox.client_criteria -local toolbox_dice = {'3d2-2', '3d2-1', '3d2', '3d2+1'} - function Toolbox:activate(player) local repair_dice = dice:new(toolbox_dice[self.condition]) if player.skills:check('repair') then repair_dice = repair_dice / 1 end From 24fbaccab55770eefb654fd80720f17f65218b90 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 1 Jan 2018 20:07:12 -0600 Subject: [PATCH 39/45] Fix Building:isPresent machine not being lowercase --- code/location/tile/building/building.lua | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/code/location/tile/building/building.lua b/code/location/tile/building/building.lua index 993fc73..abdc23e 100644 --- a/code/location/tile/building/building.lua +++ b/code/location/tile/building/building.lua @@ -107,21 +107,19 @@ end function Building:isPresent(setting) if setting == 'machines' then - - for machine, i in pairs(Machines.subclasses) do + for Machine in ipairs(Machines) do + machine = string.lower(tostring(Machine)) if self[machine] then return true end end - return false - + return false elseif setting == 'powered machines' then return self:isPresent('machines') and self:isPowered() elseif setting == 'damaged machines' then - - for machine, i in pairs(Machines.subclasses) do + for Machine in ipairs(Machines) do + machine = string.lower(tostring(Machine)) if self[machine] and self[machine]:isDamaged() then return true end end - return false - + return false else -- individual machine local machine = setting return self[machine] From 195d8988059ace11510a9e8dc05d0454505364d4 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 1 Jan 2018 20:08:29 -0600 Subject: [PATCH 40/45] Change building integrity asserts for toolbox --- code/item/items/tools.lua | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/code/item/items/tools.lua b/code/item/items/tools.lua index 2ae4cce..eecb2fe 100644 --- a/code/item/items/tools.lua +++ b/code/item/items/tools.lua @@ -95,20 +95,24 @@ Toolbox.CATEGORY = 'engineering' Toolbox.ap = {cost = 5, modifier = {repair = -1, repair_adv = -2}} function Toolbox:client_criteria(player) - local p_tile = player:getTile() - assert(player:isStaged('inside'), 'Must be inside building to repair') - assert(p_tile:isBuilding(), 'No building nearby to repair') + local p_building = player:getTile() + assert(p_building:isBuilding(), 'No building nearby to repair') + assert(player:isStaged('inside'), 'Must be inside building to repair') -- need to look for door, integrity, and equipment -- integrity code - local n_zombies = p_tile:countPlayers('zombie', 'inside') - local integrity_hp = p_tile.integrity:getHP() - - assert(player.skills:check('ruin'), 'Must have "ruin" skill to use ability') -- remove this later when abilities implement required_skill - - local n_humans = self.building:countPlayers('human', 'inside') - local integrity_hp = p_tile.integrity:getHP() - assert(integrity_hp > 0 or (integrity_hp == 0 and n_humans == 0), 'Cannot ruin building ') + assert(not p_building.integrity:isState('intact'), 'Cannot repair building that has full integrity') + if p_building.integrity:isState('ruined') then + local n_zombies = p_building:countPlayers('zombie', 'inside') + assert(player.skills:check('renovate'), 'Must have "renovate" skill to repair ruins') + assert(n_zombies == 0, 'Cannot repair building with zombies present') + end + + -- machine code + assert(p_building:isPresent('damaged machines'), 'No damaged machines are present to repair') + + -- door code + assert(p_building) end Toolbox.server_criteria = Toolbox.client_criteria From ecd7e0e240de7f6b0dcad6a7432a9997c4d5481a Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 1 Jan 2018 20:16:00 -0600 Subject: [PATCH 41/45] Add door:isDamaged() assert to toolbox.criteria --- code/item/items/tools.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/code/item/items/tools.lua b/code/item/items/tools.lua index eecb2fe..1c00908 100644 --- a/code/item/items/tools.lua +++ b/code/item/items/tools.lua @@ -98,7 +98,6 @@ function Toolbox:client_criteria(player) local p_building = player:getTile() assert(p_building:isBuilding(), 'No building nearby to repair') assert(player:isStaged('inside'), 'Must be inside building to repair') - -- need to look for door, integrity, and equipment -- integrity code assert(not p_building.integrity:isState('intact'), 'Cannot repair building that has full integrity') @@ -112,7 +111,7 @@ function Toolbox:client_criteria(player) assert(p_building:isPresent('damaged machines'), 'No damaged machines are present to repair') -- door code - assert(p_building) + assert(p_building.door:isDamaged(), 'No damaged door to repair') end Toolbox.server_criteria = Toolbox.client_criteria From f59595d442668366a4feaa5645121fd1b1787b51 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 1 Jan 2018 20:32:19 -0600 Subject: [PATCH 42/45] Comment out target code for toolbox Unsure how I'm going to add this later... I will need to wait and see how server/client will send data and implement it from there. --- code/item/items/tools.lua | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/code/item/items/tools.lua b/code/item/items/tools.lua index 1c00908..87b9a93 100644 --- a/code/item/items/tools.lua +++ b/code/item/items/tools.lua @@ -107,23 +107,39 @@ function Toolbox:client_criteria(player) assert(n_zombies == 0, 'Cannot repair building with zombies present') end + --[[ Other targets to check (machines, doors, etc.) -- machine code assert(p_building:isPresent('damaged machines'), 'No damaged machines are present to repair') -- door code assert(p_building.door:isDamaged(), 'No damaged door to repair') + --]] end -Toolbox.server_criteria = Toolbox.client_criteria +function Toolbox.server_criteria(player) --, target) + local p_building = player:getTile() + assert(p_building:isBuilding(), 'No building nearby to repair') + assert(player:isStaged('inside'), 'Must be inside building to repair') -function Toolbox:activate(player) - local repair_dice = dice:new(toolbox_dice[self.condition]) - if player.skills:check('repair') then repair_dice = repair_dice / 1 end - if player.skills:check('repair_adv') then repair_dice = repair_dice ^ 3 end - + assert(not p_building.integrity:isState('intact'), 'Cannot repair building that has full integrity') + if p_building.integrity:isState('ruined') then + local n_zombies = p_building:countPlayers('zombie', 'inside') + assert(player.skills:check('renovate'), 'Must have "renovate" skill to repair ruins') + assert(n_zombies == 0, 'Cannot repair building with zombies present') + end +--[[ Need a better system to identify targets + if target == 'building' then + elseif target == 'door' then + assert(p_building.door:isDamaged(), 'No damaged door to repair') + else -- target is a machine + assert(p_building:isPresent('damaged machines'), 'No damaged machines are present to repair') + end +--]] +end + +function Toolbox:activate(player, target) local building = player:getTile() - building.integrity:updateHP(repair_dice:roll() ) - local integrity_state = building.integrity:getState() + building.integrity:updateHP(1) -------------------------------------------- ----------- M E S S A G E -------------- @@ -131,7 +147,7 @@ function Toolbox:activate(player) local self_msg = 'You repair the building {is_finished}.' local msg = '{player} repairs the building {is_finished}.' - local names = {player=player, is_finished=integrity_state == 'intact' and 'completely' or ''} + local names = {player=player, is_finished=building.integrity:isState('intact') and 'completely' or ''} self_msg = self_msg:replace(names) msg = msg:replace(names) @@ -139,7 +155,7 @@ function Toolbox:activate(player) --------- B R O A D C A S T ------------ -------------------------------------------- - local event = {'toolbox', integrity_state} + local event = {'toolbox'} player:broadcastEvent(msg, self_msg, event) end From 16d64155270685e05292e1d8487da98f3a26c1d5 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 1 Jan 2018 20:33:49 -0600 Subject: [PATCH 43/45] Fix typo --- code/location/tile/building/door.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/location/tile/building/door.lua b/code/location/tile/building/door.lua index 695ca07..bdcf908 100644 --- a/code/location/tile/building/door.lua +++ b/code/location/tile/building/door.lua @@ -17,7 +17,7 @@ function Door:toggle() self.is_open = not self.is_open end function Door:isDestroyed() return self.hp == 0 end -function Door:isDamaged() return self.hp == MAX_HP +function Door:isDamaged() return self.hp == MAX_HP end function Door:isOpen() return self.is_open end From e1e9717415b1cef54b22b22e559826c219585e08 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 1 Jan 2018 20:40:28 -0600 Subject: [PATCH 44/45] Changed FAQ.md --- FAQ.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FAQ.md b/FAQ.md index b598bc1..66f1f01 100644 --- a/FAQ.md +++ b/FAQ.md @@ -41,7 +41,7 @@ Yes. If you die (as a human) or starve (as a zombie) then it's game over. Fort Regarding dice, I felt like both UD and Q suffered from using what I call 'basic' math. Weapons and items always did `x` amount of effect. That wasn't realistic and pretty boring for gameplay. So by adding dice it would allow ZT to be more dynamic! Weapons in better condition do more damage or have better accuracy. Skills either boost accuracy or grant rerolls to weapon attacks that successfully land. This is a powerful system that works well and allows for interesting possibilities. -### Q: What about PK'ing? +### Q: What about Player Killing? (PK'ing) Player killing is going to be disabled for both sides. So a human cannot kill other humans, and vice-versa for zombies. It would be too game breaking to have this feature enabled with permadeath functioning. From 530f343b3cb9faefb5fe095bc57b0b7eeeae88e9 Mon Sep 17 00:00:00 2001 From: Timothy Date: Mon, 1 Jan 2018 20:41:52 -0600 Subject: [PATCH 45/45] Bumped version number to 0.8.1 --- settings.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.lua b/settings.lua index 5107a9f..c0f9a67 100644 --- a/settings.lua +++ b/settings.lua @@ -1,5 +1,5 @@ local settings = { - _VERSION = 'ZomboTropolis v0.8.0', + _VERSION = 'ZomboTropolis v0.8.1', _AUTHOR = 'Timothy Torres', _URL = 'https://github.com/timothymtorres/ZomboTropolis-Roguelike', _DESCRIPTION = 'A zombie survival roguelike MMORPG.',