diff --git a/assets/sounds/258269__jcallison__mouth-pop.ogg b/assets/sounds/258269__jcallison__mouth-pop.ogg new file mode 100644 index 0000000..f371a0f Binary files /dev/null and b/assets/sounds/258269__jcallison__mouth-pop.ogg differ diff --git a/assets/sounds/467951__benzix2__ui-button-click.ogg b/assets/sounds/467951__benzix2__ui-button-click.ogg new file mode 100644 index 0000000..dc51c87 Binary files /dev/null and b/assets/sounds/467951__benzix2__ui-button-click.ogg differ diff --git a/assets/sounds/80921__justinbw__buttonchime02up.ogg b/assets/sounds/80921__justinbw__buttonchime02up.ogg new file mode 100644 index 0000000..8ef08e1 Binary files /dev/null and b/assets/sounds/80921__justinbw__buttonchime02up.ogg differ diff --git a/assets/sounds/Error 2.ogg b/assets/sounds/Error 2.ogg new file mode 100644 index 0000000..eae9fff Binary files /dev/null and b/assets/sounds/Error 2.ogg differ diff --git a/assets/sounds/bamboo_hit_by_lord.ogg b/assets/sounds/bamboo_hit_by_lord.ogg new file mode 100644 index 0000000..fb4af05 Binary files /dev/null and b/assets/sounds/bamboo_hit_by_lord.ogg differ diff --git a/buy_screen.lua b/buy_screen.lua index 5b4d1ef..8d9407d 100644 --- a/buy_screen.lua +++ b/buy_screen.lua @@ -12,7 +12,7 @@ function BuyScreen:on_enter(from, level, units) self.units = units self.main = Group() - self.top = Group() + self.effects = Group() self.ui = Group() if self.level == 0 then @@ -32,63 +32,20 @@ function BuyScreen:on_enter(from, level, units) self.title = Text({{text = '[wavy_mid, fg]choose your initial party', font = pixul_font, alignment = 'center'}}, global_text_tags) else - local level_to_tier_weights = { - [1] = {100, 0, 0}, - [2] = {95, 5, 0}, - [3] = {90, 10, 0}, - [4] = {85, 15, 0}, - [5] = {80, 20, 0}, - [6] = {75, 25, 0}, - [7] = {70, 30, 0}, - [8] = {65, 35, 0}, - [9] = {60, 40, 0}, - [10] = {55, 45, 0}, - [11] = {50, 50, 0}, - [12] = {45, 50, 5}, - [13] = {40, 50, 10}, - [14] = {35, 50, 15}, - [15] = {30, 50, 20}, - [16] = {25, 50, 25}, - [17] = {20, 55, 25}, - [18] = {15, 60, 25}, - [19] = {10, 65, 25}, - [20] = {5, 70, 25}, - [21] = {0, 75, 25}, - [22] = {0, 70, 30}, - [23] = {0, 65, 35}, - [24] = {0, 60, 40}, - [25] = {0, 55, 45}, - } - self.cards = {} - self.selected_index = 1 - self.cards[1] = ShopCard{group = self.main, x = 60, y = 75, w = 80, h = 90, unit = random:table(tier_to_characters[random:weighted_pick(unpack(level_to_tier_weights[self.level]))]), parent = self} - self.cards[2] = ShopCard{group = self.main, x = 140, y = 75, w = 80, h = 90, unit = random:table(tier_to_characters[random:weighted_pick(unpack(level_to_tier_weights[self.level]))]), parent = self} - self.cards[3] = ShopCard{group = self.main, x = 220, y = 75, w = 80, h = 90, unit = random:table(tier_to_characters[random:weighted_pick(unpack(level_to_tier_weights[self.level]))]), parent = self} - self.shop_text_sy = 1 - self.shop_text = Text({{text = '[wavy_mid, fg]shop', font = pixul_font, alignment = 'center'}}, global_text_tags) - self.gold_text = Text2{group = self.main, x = 88, y = 20, lines = {{text = '[fg]- your gold: [yellow]' .. gold, font = pixul_font, alignment = 'center'}}} + self:set_cards() + self:set_party_and_sets() - self.characters = {} - local y = 40 - for i, unit in ipairs(self.units) do - table.insert(self.characters, CharacterPart{group = self.main, x = gw - 30, y = y + (i-1)*20, character = unit.character, level = unit.level, reserve = unit.reserve}) - end + self.shop_text = Text({{text = '[wavy_mid, fg]shop [fg]- gold: [yellow]' .. gold, font = pixul_font, alignment = 'center'}}, global_text_tags) self.party_text = Text({{text = '[wavy_mid, fg]party', font = pixul_font, alignment = 'center'}}, global_text_tags) - - self.sets = {} - for i, class in ipairs(get_classes(self.units)) do - local x, y = math.index_to_coordinates(i, 2) - table.insert(self.sets, ClassIcon{group = self.main, x = 319 + (x-1)*20, y = 45 + (y-1)*56, class = class, units = self.units}) - end self.sets_text = Text({{text = '[wavy_mid, fg]sets', font = pixul_font, alignment = 'center'}}, global_text_tags) - self.items_text = Text({{text = '[wavy_mid, fg]items', font = pixul_font, alignment = 'center'}}, global_text_tags) self.under_text = Text2{group = self.main, x = 140, y = gh - 60, r = -math.pi/48, lines = { {text = '[light_bg]under', font = fat_font, alignment = 'center'}, {text = '[light_bg]construction', font = fat_font, alignment = 'center'}, }} - RerollButton{group = self.main, x = 255, y = 140, parent = self} + RerollButton{group = self.main, x = 150, y = 18, parent = self} + GoButton{group = self.main, x = gw - 30, y = gh - 20, parent = self} end end @@ -96,7 +53,7 @@ end function BuyScreen:update(dt) self:update_game_object(dt*slow_amount) self.main:update(dt*slow_amount) - self.top:update(dt*slow_amount) + self.effects:update(dt*slow_amount) self.ui:update(dt*slow_amount) if self.level == 0 and self.first_screen then @@ -157,20 +114,162 @@ end function BuyScreen:draw() self.main:draw() - self.top:draw() + self.effects:draw() if self.items_text then self.items_text:draw(32, 150) end self.ui:draw() if self.level == 0 then if self.title then self.title:draw(3.25*gw/4, 32, 0, 1, self.title_sy) end else - if self.shop_text then self.shop_text:draw(32, 20, 0, 1, self.shop_text_sy) end + if self.shop_text then self.shop_text:draw(64, 20) end if self.sets_text then self.sets_text:draw(328, 20) end if self.party_text then self.party_text:draw(440, 20) end end end +function BuyScreen:buy(character, i) + local bought + if table.any(self.units, function(v) return v.character == character end) then + gold = gold - character_tiers[character] + self.shop_text:set_text{{text = '[wavy_mid, fg]shop [fg]- [fg, nudge_down]gold: [yellow, nudge_down]' .. gold, font = pixul_font, alignment = 'center'}} + for _, unit in ipairs(self.units) do + if unit.character == character then + if unit.level == 1 then + unit.reserve[1] = unit.reserve[1] + 1 + if unit.reserve[1] > 1 then + unit.reserve[1] = 0 + unit.level = 2 + unit.spawn_effect = true + end + elseif unit.level == 2 then + unit.reserve[1] = unit.reserve[1] + 1 + if unit.reserve[1] > 2 then + if unit.reserve[2] == 1 then + unit.reserve[2] = 0 + unit.reserve[1] = 0 + unit.level = 3 + unit.spawn_effect = true + else + unit.reserve[2] = unit.reserve[2] + 1 + unit.reserve[1] = 0 + end + end + end + end + end + bought = true + else + if #self.units >= 10 then + if not self.info_text then + self.info_text = InfoText{group = main.current.ui} + self.info_text:activate({ + {text = '[fg]maximum number of units [yellow](10) [fg]reached', font = pixul_font, alignment = 'center'}, + }, nil, nil, nil, nil, 16, 4, nil, 2) + self.info_text.x, self.info_text.y = gw - 140, gh - 20 + end + self.t:after(2, function() self.info_text:deactivate(); self.info_text.dead = true; self.info_text = nil end, 'info_text') + else + gold = gold - character_tiers[character] + self.shop_text:set_text{{text = '[wavy_mid, fg]shop [fg]- [fg, nudge_down]gold: [yellow, nudge_down]' .. gold, font = pixul_font, alignment = 'center'}} + table.insert(self.units, {character = character, level = 1, reserve = {0, 0}}) + bought = true + end + end + self:set_party_and_sets() + return bought +end + + +function BuyScreen:gain_gold(amount) + gold = gold + amount or 0 + self.shop_text:set_text{{text = '[wavy_mid, fg]shop [fg]- [fg, nudge_down]gold: [yellow, nudge_down]' .. gold, font = pixul_font, alignment = 'center'}} +end + + +function BuyScreen:set_cards(level, dont_spawn_effect) + if self.cards then for i = 1, 3 do if self.cards[i] then self.cards[i]:die(dont_spawn_effect) end end end + self.cards = {} + self.cards[1] = ShopCard{group = self.main, x = 60, y = 75, w = 80, h = 90, unit = random:table(tier_to_characters[random:weighted_pick(unpack(level_to_tier_weights[level or self.level]))]), parent = self, i = 1} + self.cards[2] = ShopCard{group = self.main, x = 140, y = 75, w = 80, h = 90, unit = random:table(tier_to_characters[random:weighted_pick(unpack(level_to_tier_weights[level or self.level]))]), parent = self, i = 2} + self.cards[3] = ShopCard{group = self.main, x = 220, y = 75, w = 80, h = 90, unit = random:table(tier_to_characters[random:weighted_pick(unpack(level_to_tier_weights[level or self.level]))]), parent = self, i = 3} +end + + +function BuyScreen:set_party_and_sets() + if self.characters then for _, part in ipairs(self.characters) do part:die() end end + self.characters = {} + local y = 40 + for i, unit in ipairs(self.units) do + table.insert(self.characters, CharacterPart{group = self.main, x = gw - 30, y = y + (i-1)*20, character = unit.character, level = unit.level, reserve = unit.reserve, i = i, spawn_effect = unit.spawn_effect, parent = self}) + unit.spawn_effect = false + end + + if self.sets then for _, icon in ipairs(self.sets) do icon:die(true) end end + self.sets = {} + local classes = get_classes(self.units) + for i, class in ipairs(classes) do + local x, y + if #classes <= 8 then x, y = math.index_to_coordinates(i, 2) + else x, y = math.index_to_coordinates(i, 3) end + table.insert(self.sets, ClassIcon{group = self.main, x = (#classes <= 8 and 319 or 308) + (x-1)*20, y = 45 + (y-1)*56, class = class, units = self.units, parent = self}) + end +end + + + + +GoButton = Object:extend() +GoButton:implement(GameObject) +function GoButton:init(args) + self:init_game_object(args) + self.shape = Rectangle(self.x, self.y, 24, 16) + self.interact_with_mouse = true + self.text = Text({{text = '[bg10]go!', font = pixul_font, alignment = 'center'}}, global_text_tags) +end + + +function GoButton:update(dt) + self:update_game_object(dt) + if self.selected and input.m1.pressed and not self.transitioning then + ui_switch2:play{pitch = random:float(0.95, 1.05), volume = 0.5} + self.spring:pull(0.2, 200, 10) + self.selected = true + + ui_switch1:play{pitch = random:float(0.95, 1.05), volume = 0.5} + ui_transition1:play{pitch = random:float(0.95, 1.05), volume = 0.5} + self.transitioning = true + + TransitionEffect{group = main.transitions, x = self.x, y = self.y, color = character_colors[random:table(self.parent.units).character], transition_action = function() + main:add(Arena'arena') + main:go_to('arena', 1, self.parent.units) + end} + end +end + + +function GoButton:draw() + graphics.push(self.x, self.y, 0, self.spring.x, self.spring.y) + graphics.rectangle(self.x, self.y, self.shape.w, self.shape.h, 4, 4, self.selected and fg[0] or bg[1]) + self.text:draw(self.x, self.y + 1) + graphics.pop() +end + + +function GoButton:on_mouse_enter() + ui_hover1:play{pitch = random:float(1.3, 1.5), volume = 0.5} + pop2:play{pitch = random:float(0.95, 1.05), volume = 0.5} + self.selected = true + self.text:set_text{{text = '[fgm5]go!', font = pixul_font, alignment = 'center'}} + self.spring:pull(0.2, 200, 10) +end + + +function GoButton:on_mouse_exit() + self.text:set_text{{text = '[bg10]go!', font = pixul_font, alignment = 'center'}} + self.selected = false +end + RerollButton = Object:extend() @@ -185,6 +284,15 @@ end function RerollButton:update(dt) self:update_game_object(dt) + + if self.selected and input.m1.pressed then + ui_switch2:play{pitch = random:float(0.95, 1.05), volume = 0.5} + self.parent:set_cards(random:int(1, 25), true) + self.selected = true + self.spring:pull(0.2, 200, 10) + gold = gold - 2 + self.parent.shop_text:set_text{{text = '[wavy_mid, fg]shop [fg]- [fg, nudge_down]gold: [yellow, nudge_down]' .. gold, font = pixul_font, alignment = 'center'}} + end end @@ -197,11 +305,14 @@ end function RerollButton:on_mouse_enter() + ui_hover1:play{pitch = random:float(1.3, 1.5), volume = 0.5} + pop2:play{pitch = random:float(0.95, 1.05), volume = 0.5} self.selected = true self.text:set_text{{text = '[fgm5]reroll: 2', font = pixul_font, alignment = 'center'}} self.spring:pull(0.2, 200, 10) end + function RerollButton:on_mouse_exit() self.text:set_text{{text = '[bg10]reroll: [yellow]2', font = pixul_font, alignment = 'center'}} self.selected = false @@ -219,20 +330,39 @@ function CharacterPart:init(args) self.parts = {} local x = self.x - 20 if self.reserve then - if self.reserve[2] == 1 then - table.insert(self.parts, CharacterPart{group = main.current.main, x = x, y = self.y, character = self.character, level = 2}) + if self.reserve[2] and self.reserve[2] == 1 then + table.insert(self.parts, CharacterPart{group = main.current.main, x = x, y = self.y, character = self.character, level = 2, i = self.i, parent = self}) x = x - 20 end - for i = 1, self.reserve[1] do - table.insert(self.parts, CharacterPart{group = main.current.main, x = x, y = self.y, character = self.character, level = 1, sx = 0.9, sy = 0.9}) + for i = 1, self.reserve and self.reserve[1] or 0 do + table.insert(self.parts, CharacterPart{group = main.current.main, x = x, y = self.y, character = self.character, level = 1, sx = 0.9, sy = 0.9, i = self.i, parent = self}) x = x - 20 end end + self.spring:pull(0.2, 200, 10) + if self.spawn_effect then SpawnEffect{group = main.current.effects, x = self.x, y = self.y, color = character_colors[self.character]} end + self.just_created = true + self.t:after(0.1, function() self.just_created = false end) end function CharacterPart:update(dt) self:update_game_object(dt) + + if self.selected and input.m2.pressed and not self.just_created then + _G[random:table{'coins1', 'coins2', 'coins3'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5} + if self.reserve then + self.parent:gain_gold(self:get_sale_price()) + table.remove(self.parent.units, self.i) + self:die() + self.parent:set_party_and_sets() + else + self.parent.parent:gain_gold(self:get_sale_price()) + self.parent.parent.units[self.i].reserve[self.level] = self.parent.parent.units[self.i].reserve[self.level] - 1 + self:die() + self.parent.parent:set_party_and_sets() + end + end end @@ -245,20 +375,12 @@ end function CharacterPart:on_mouse_enter() - local get_sale_price = function() - local total = 0 - total = total + self.level - if self.reserve then - if self.reserve[2] then total = total + self.reserve[2]*2 end - if self.reserve[1] then total = total + self.reserve[1] end - end - return total - end - + ui_hover1:play{pitch = random:float(1.3, 1.5), volume = 0.5} + self.selected = true self.spring:pull(0.2, 200, 10) self.info_text = InfoText{group = main.current.ui} self.info_text:activate({ - {text = '[' .. character_color_strings[self.character] .. ']' .. self.character:capitalize() .. '[fg] - [yellow]Lv.' .. self.level .. '[fg] - sells for [yellow]' .. get_sale_price(), + {text = '[' .. character_color_strings[self.character] .. ']' .. self.character:capitalize() .. '[fg] - [yellow]Lv.' .. self.level .. '[fg] - sells for [yellow]' .. self:get_sale_price(), font = pixul_font, alignment = 'center', height_multiplier = 1.25}, {text = character_descriptions[self.character](get_character_stat(self.character, self.level, 'dmg')), font = pixul_font, alignment = 'center'}, }, nil, nil, nil, nil, 16, 4, nil, 2) @@ -266,12 +388,37 @@ function CharacterPart:on_mouse_enter() end +function CharacterPart:get_sale_price() + local total = 0 + total = total + ((self.level == 1 and 1) or (self.level == 2 and 4) or (self.level == 3 and 8)) + if self.reserve then + if self.reserve[2] then total = total + self.reserve[2]*4 end + if self.reserve[1] then total = total + self.reserve[1] end + end + return total +end + + function CharacterPart:on_mouse_exit() + self.selected = false self.info_text:deactivate() + self.info_text.dead = true self.info_text = nil end +function CharacterPart:die() + self.dead = true + for _, part in ipairs(self.parts) do part:die() end + if self.info_text then + self.info_text:deactivate() + self.info_text.dead = true + self.info_text = nil + end +end + + + ShopCard = Object:extend() ShopCard:implement(GameObject) @@ -279,20 +426,35 @@ function ShopCard:init(args) self:init_game_object(args) self.shape = Rectangle(self.x, self.y, self.w, self.h) self.interact_with_mouse = true - self.character_icon = CharacterIcon{group = main.current.top, x = self.x, y = self.y - 26, character = self.unit, parent = self} + self.character_icon = CharacterIcon{group = main.current.effects, x = self.x, y = self.y - 26, character = self.unit, parent = self} self.class_icons = {} for i, class in ipairs(character_classes[self.unit]) do local x = self.x if #character_classes[self.unit] == 2 then x = self.x - 10 elseif #character_classes[self.unit] == 3 then x = self.x - 20 end - table.insert(self.class_icons, ClassIcon{group = main.current.top, x = x + (i-1)*20, y = self.y + 6, class = class, units = self.parent.units}) + table.insert(self.class_icons, ClassIcon{group = main.current.effects, x = x + (i-1)*20, y = self.y + 6, class = class, character = self.unit, units = self.parent.units, parent = self}) end self.cost = character_tiers[self.unit] + self.spring:pull(0.2, 200, 10) end function ShopCard:update(dt) self:update_game_object(dt) + + if self.selected and input.m1.pressed then + if self.parent:buy(self.unit, self.i) then + ui_switch1:play{pitch = random:float(0.95, 1.05), volume = 0.5} + _G[random:table{'coins1', 'coins2', 'coins3'}]:play{pitch = random:float(0.95, 1.05), volume = 0.5} + self:die() + self.parent.cards[self.i] = nil + else + error1:play{pitch = random:float(0.95, 1.05), volume = 0.5} + self.spring:pull(0.2, 200, 10) + self.character_icon.spring:pull(0.2, 200, 10) + for _, ci in ipairs(self.class_icons) do ci.spring:pull(0.2, 200, 10) end + end + end end @@ -319,7 +481,7 @@ end function ShopCard:draw() - graphics.push(self.x, self.y, 0, self.spring.x, self.spring.x) + graphics.push(self.x, self.y, 0, self.sx*self.spring.x, self.sy*self.spring.x) if self.selected then graphics.rectangle(self.x, self.y, self.w, self.h, 6, 6, bg[-1]) end @@ -328,6 +490,8 @@ end function ShopCard:on_mouse_enter() + ui_hover1:play{pitch = random:float(1.3, 1.5), volume = 0.5} + pop2:play{pitch = random:float(0.95, 1.05), volume = 0.5} self.selected = true self.spring:pull(0.1) self.character_icon.spring:pull(0.1, 200, 10) @@ -344,6 +508,18 @@ function ShopCard:on_mouse_exit() end +function ShopCard:die(dont_spawn_effect) + self.dead = true + self.character_icon:die(dont_spawn_effect) + for _, class_icon in ipairs(self.class_icons) do class_icon:die(dont_spawn_effect) end + if self.info_text then + self.info_text:deactivate() + self.info_text.dead = true + self.info_text = nil + end +end + + CharacterIcon = Object:extend() @@ -363,7 +539,7 @@ end function CharacterIcon:draw() - graphics.push(self.x, self.y, 0, self.spring.x, self.spring.x) + graphics.push(self.x, self.y, 0, self.sx*self.spring.x, self.sy*self.spring.x) graphics.rectangle(self.x, self.y - 7, 14, 14, 3, 3, character_colors[self.character]) graphics.print_centered(self.parent.cost, pixul_font, self.x + 0.5, self.y - 5, 0, 1, 1, 0, 0, _G[character_color_strings[self.character]][-5]) self.character_text:draw(self.x, self.y + 10) @@ -372,6 +548,7 @@ end function CharacterIcon:on_mouse_enter() + ui_hover1:play{pitch = random:float(1.3, 1.5), volume = 0.5} self.spring:pull(0.2, 200, 10) self.info_text = InfoText{group = main.current.ui} self.info_text:activate({ @@ -384,10 +561,23 @@ end function CharacterIcon:on_mouse_exit() self.info_text:deactivate() + self.info_text.dead = true self.info_text = nil end +function CharacterIcon:die(dont_spawn_effect) + self.dead = true + if not dont_spawn_effect then SpawnEffect{group = main.current.effects, x = self.x, y = self.y + 4, color = character_colors[self.character]} end + if self.info_text then + self.info_text:deactivate() + self.info_text.dead = true + self.info_text = nil + end +end + + + ClassIcon = Object:extend() ClassIcon:implement(GameObject) @@ -395,6 +585,8 @@ function ClassIcon:init(args) self:init_game_object(args) self.shape = Rectangle(self.x, self.y + 11, 20, 40) self.interact_with_mouse = true + self.t:every(0.5, function() self.flash = not self.flash end) + self.spring:pull(0.2, 200, 10) end @@ -404,8 +596,15 @@ end function ClassIcon:draw() - graphics.push(self.x, self.y, 0, self.spring.x, self.spring.x) + graphics.push(self.x, self.y, 0, self.sx*self.spring.x, self.sy*self.spring.x) local i, j, n = class_set_numbers[self.class](self.units) + local next_n + if self.parent:is(ShopCard) then + next_n = n+1 + if next_n > j then next_n = nil end + if table.any(self.units, function(v) return v.character == self.character end) then next_n = nil end + end + graphics.rectangle(self.x, self.y, 16, 24, 4, 4, (n >= i) and class_colors[self.class] or bg[3]) _G[self.class]:draw(self.x, self.y, 0, 0.3, 0.3, 0, 0, (n >= i) and _G[class_color_strings[self.class]][-5] or bg[10]) graphics.rectangle(self.x, self.y + 26, 16, 16, 3, 3, bg[3]) @@ -414,19 +613,47 @@ function ClassIcon:draw() graphics.line(self.x - 3, self.y + 27, self.x - 3, self.y + 32, (n >= 2) and class_colors[self.class] or bg[10], 3) graphics.line(self.x + 4, self.y + 20, self.x + 4, self.y + 25, (n >= 3) and class_colors[self.class] or bg[10], 3) graphics.line(self.x + 4, self.y + 27, self.x + 4, self.y + 32, (n >= 4) and class_colors[self.class] or bg[10], 3) + if next_n then + if next_n == 1 then + graphics.line(self.x - 3, self.y + 20, self.x - 3, self.y + 25, self.flash and class_colors[self.class] or bg[10], 3) + elseif next_n == 2 then + graphics.line(self.x - 3, self.y + 27, self.x - 3, self.y + 32, self.flash and class_colors[self.class] or bg[10], 3) + elseif next_n == 3 then + graphics.line(self.x + 4, self.y + 20, self.x + 4, self.y + 25, self.flash and class_colors[self.class] or bg[10], 3) + elseif next_n == 4 then + graphics.line(self.x + 4, self.y + 27, self.x + 4, self.y + 32, self.flash and class_colors[self.class] or bg[10], 3) + end + end elseif i == 3 then graphics.line(self.x - 4, self.y + 22, self.x - 4, self.y + 30, (n >= 1) and class_colors[self.class] or bg[10], 2) graphics.line(self.x, self.y + 22, self.x, self.y + 30, (n >= 2) and class_colors[self.class] or bg[10], 2) graphics.line(self.x + 4, self.y + 22, self.x + 4, self.y + 30, (n >= 3) and class_colors[self.class] or bg[10], 2) + if next_n then + if next_n == 1 then + graphics.line(self.x - 4, self.y + 22, self.x - 4, self.y + 30, self.flash and class_colors[self.class] or bg[10], 2) + elseif next_n == 2 then + graphics.line(self.x, self.y + 22, self.x, self.y + 30, self.flash and class_colors[self.class] or bg[10], 2) + elseif next_n == 3 then + graphics.line(self.x + 4, self.y + 22, self.x + 4, self.y + 30, self.flash and class_colors[self.class] or bg[10], 2) + end + end elseif i == 1 then graphics.line(self.x - 3, self.y + 22, self.x - 3, self.y + 30, (n >= 1) and class_colors[self.class] or bg[10], 3) graphics.line(self.x + 4, self.y + 22, self.x + 4, self.y + 30, (n >= 2) and class_colors[self.class] or bg[10], 3) + if next_n then + if next_n == 1 then + graphics.line(self.x - 3, self.y + 22, self.x - 3, self.y + 30, (n >= 1) and class_colors[self.class] or bg[10], 3) + elseif next_n == 2 then + graphics.line(self.x + 4, self.y + 22, self.x + 4, self.y + 30, (n >= 2) and class_colors[self.class] or bg[10], 3) + end + end end graphics.pop() end function ClassIcon:on_mouse_enter() + ui_hover1:play{pitch = random:float(1.3, 1.5), volume = 0.5} self.spring:pull(0.2, 200, 10) local i, j, owned = class_set_numbers[self.class](self.units) self.info_text = InfoText{group = main.current.ui} @@ -440,10 +667,23 @@ end function ClassIcon:on_mouse_exit() self.info_text:deactivate() + self.info_text.dead = true self.info_text = nil end +function ClassIcon:die(dont_spawn_effect) + self.dead = true + local i, j, n = class_set_numbers[self.class](self.units) + if not dont_spawn_effect then SpawnEffect{group = main.current.effects, x = self.x, y = self.y + 4, color = (n >= i) and class_colors[self.class] or bg[3]} end + if self.info_text then + self.info_text:deactivate() + self.info_text.dead = true + self.info_text = nil + end +end + + PairCard = Object:extend() diff --git a/devlog.md b/devlog.md index 7a7c77e..c0b83a7 100644 --- a/devlog.md +++ b/devlog.md @@ -360,3 +360,8 @@ have to do with visuals and not much else. I would wager that most of it has to The first problem can be fixed by just trying to draw the UI beforehand, which I never do but maybe I should start doing. The second problem is more involved and essentially it involves writing UI components that are generic enough like buttons, labels, image buttons, lists, etc, but also allow for enough specialization that I can make them really juicy, as this generally requires a lot of detail fiddling the inner works of the object. I think the Node refactor I'm planning will probably help with this, especially the idea of everything simply being a Node and classes being able to be defined inline by just defining update/draw/on_enter/etc functions. + +# Day 24-25 - 12-13/03/21 + +Finished buy screen. Now the only two things left is are redoing the first screen to take advantage of all the UI built for the buy screen, balance/progression and then fixing smaller details and finishing everything up. +I can probably finish it all before day 30 which would be great. diff --git a/main.lua b/main.lua index 0066df1..b7c11e6 100644 --- a/main.lua +++ b/main.lua @@ -17,10 +17,12 @@ function init() input:bind('enter', {'space', 'return'}) local s = {tags = {sfx}} + ui_hover1 = Sound('bamboo_hit_by_lord.ogg', s) ui_switch1 = Sound('Switch.ogg', s) ui_switch2 = Sound('Switch 3.ogg', s) ui_transition1 = Sound('Wind Bolt 8.ogg', s) ui_transition2 = Sound('Wind Bolt 12.ogg', s) + error1 = Sound('Error 2.ogg', s) coins1 = Sound('Coins 7.ogg', s) coins2 = Sound('Coins 8.ogg', s) coins3 = Sound('Coins 9.ogg', s) @@ -48,6 +50,9 @@ function init() player_hit2 = Sound('Body Fall 18.ogg', s) player_hit_wall1 = Sound('Wood Heavy 5.ogg', s) pop1 = Sound('Pop sounds 10.ogg', s) + pop2 = Sound('467951__benzix2__ui-button-click.ogg', s) + pop3 = Sound('258269__jcallison__mouth-pop.ogg', s) + confirm1 = Sound('80921__justinbw__buttonchime02up.ogg', s) heal1 = Sound('Buff 3.ogg', s) spawn1 = Sound('Buff 13.ogg', s) alert1 = Sound('Click.ogg', s) @@ -201,7 +206,7 @@ function init() get_character_stat_string = function(character, level) local group = Group():set_as_physics_world(32, 0, 0, {'player', 'enemy', 'projectile', 'enemy_projectile'}) - local mock = Player{group = group, leader = true, character = character, level = level} + local mock = Player{group = group, leader = true, character = character, level = level, follower_index = 1} mock:update(0) return '[red]HP: [red]' .. mock.max_hp .. '[fg], [red]DMG: [red]' .. mock.dmg .. '[fg], [green]ASPD: [green]' .. math.round(mock.aspd_m, 2) .. 'x[fg], [blue]AREA: [blue]' .. math.round(mock.area_dmg_m*mock.area_size_m, 2) .. 'x[fg], [yellow]DEF: [yellow]' .. math.round(mock.def, 2) .. '[fg], [green]MVSPD: [green]' .. math.round(mock.v, 2) .. '[fg]' @@ -209,7 +214,7 @@ function init() get_character_stat = function(character, level, stat) local group = Group():set_as_physics_world(32, 0, 0, {'player', 'enemy', 'projectile', 'enemy_projectile'}) - local mock = Player{group = group, leader = true, character = character, level = level} + local mock = Player{group = group, leader = true, character = character, level = level, follower_index = 1} mock:update(0) return math.round(mock[stat], 2) end @@ -340,16 +345,40 @@ function init() ['psy'] = function(units) return 1, 2, get_number_of_units_per_class(units).psy end, } - gold = 0 + level_to_tier_weights = { + [1] = {100, 0, 0}, + [2] = {95, 5, 0}, + [3] = {90, 10, 0}, + [4] = {85, 15, 0}, + [5] = {80, 20, 0}, + [6] = {75, 25, 0}, + [7] = {70, 30, 0}, + [8] = {65, 35, 0}, + [9] = {60, 40, 0}, + [10] = {55, 45, 0}, + [11] = {50, 50, 0}, + [12] = {45, 50, 5}, + [13] = {40, 50, 10}, + [14] = {35, 50, 15}, + [15] = {30, 50, 20}, + [16] = {25, 50, 25}, + [17] = {20, 55, 25}, + [18] = {15, 60, 25}, + [19] = {10, 65, 25}, + [20] = {5, 70, 25}, + [21] = {0, 75, 25}, + [22] = {0, 70, 30}, + [23] = {0, 65, 35}, + [24] = {0, 60, 40}, + [25] = {0, 55, 45}, + } + + gold = 100 main = Main() main:add(BuyScreen'buy_screen') - local rsv = function() return {random:int(0, 2), random:int(0, 1)} end main:go_to('buy_screen', 1, { - {character = 'vagrant', level = 1, reserve = rsv()}, {character = 'swordsman', level = 1, reserve = rsv()}, {character = 'wizard', level = 1, reserve = rsv()}, - {character = 'archer', level = 1, reserve = rsv()}, {character = 'scout', level = 1, reserve = rsv()}, {character = 'cleric', level = 1, reserve = rsv()}, - {character = 'elementor', level = 1, reserve = rsv()}, {character = 'cannoneer', level = 1, reserve = rsv()}, {character = 'blade', level = 1, reserve = rsv()}, - {character = 'sage', level = 1, reserve = rsv()}, {character = 'outlaw', level = 1, reserve = rsv()}, + {character = 'vagrant', level = 1, reserve = {0, 0}}, {character = 'swordsman', level = 1, reserve = {0, 0}}, }) end diff --git a/objects.lua b/objects.lua index 2a3500f..f2a57ce 100644 --- a/objects.lua +++ b/objects.lua @@ -207,6 +207,10 @@ function Unit:calculate_stats(first_run) self.base_hp = 50 + 20*y[x] self.base_dmg = 10 + 3*y[x] self.base_mvspd = 70 + 2*y[x] + elseif self:is(Saboteur) then + self.base_hp = 100*math.pow(2, self.level-1) + self.base_dmg = 10*math.pow(2, self.level-1) + self.base_mvspd = 75 end self.base_aspd_m = 1 self.base_area_dmg_m = 1 diff --git a/player.lua b/player.lua index c4bef22..78f114f 100644 --- a/player.lua +++ b/player.lua @@ -74,10 +74,10 @@ function Player:init(args) end, nil, nil, 'shoot') elseif self.character == 'cleric' then - self.color = green[0] + self.color = character_colors.cleric self:set_as_rectangle(9, 9, 'dynamic', 'player') self.visual_shape = 'rectangle' - self.classes = {'healer'} + self.classes = character_classes.cleric self.last_heal_time = love.timer.getTime() self.t:every(2, function() @@ -93,10 +93,10 @@ function Player:init(args) end) elseif self.character == 'outlaw' then - self.color = red[0] + self.color = character_colors.outlaw self:set_as_rectangle(9, 9, 'dynamic', 'player') self.visual_shape = 'rectangle' - self.classes = {'warrior', 'rogue'} + self.classes = character_classes.outlaw self.attack_sensor = Circle(self.x, self.y, 96) self.t:cooldown(3, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function() @@ -107,10 +107,10 @@ function Player:init(args) end, nil, nil, 'shoot') elseif self.character == 'blade' then - self.color = yellow[0] + self.color = character_colors.blade self:set_as_rectangle(9, 9, 'dynamic', 'player') self.visual_shape = 'rectangle' - self.classes = {'warrior', 'nuker'} + self.classes = character_classes.blade self.attack_sensor = Circle(self.x, self.y, 64) self.t:cooldown(4, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function() @@ -118,10 +118,10 @@ function Player:init(args) end, nil, nil, 'shoot') elseif self.character == 'elementor' then - self.color = blue[0] + self.color = character_colors.elementor self:set_as_rectangle(9, 9, 'dynamic', 'player') self.visual_shape = 'rectangle' - self.classes = {'mage', 'nuker'} + self.classes = character_classes.elementor self.attack_sensor = Circle(self.x, self.y, 128) self.t:cooldown(12, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function() @@ -132,10 +132,10 @@ function Player:init(args) end, nil, nil, 'attack') elseif self.character == 'saboteur' then - self.color = red[0] + self.color = character_colors.saboteur self:set_as_rectangle(9, 9, 'dynamic', 'player') self.visual_shape = 'rectangle' - self.classes = {'rogue', 'conjurer', 'nuker'} + self.classes = character_classes.saboteur self.t:every(8, function() self.t:every(0.25, function() @@ -146,10 +146,10 @@ function Player:init(args) end) elseif self.character == 'stormweaver' then - self.color = red[0] + self.color = character_colors.stormweaver self:set_as_rectangle(9, 9, 'dynamic', 'player') self.visual_shape = 'rectangle' - self.classes = {'enchanter'} + self.classes = character_classes.stormweaver self.t:every(8, function() stormweaver1:play{pitch = random:float(0.95, 1.05), volume = 0.5} @@ -164,10 +164,10 @@ function Player:init(args) end) elseif self.character == 'sage' then - self.color = blue[0] + self.color = character_colors.sage self:set_as_rectangle(9, 9, 'dynamic', 'player') self.visual_shape = 'rectangle' - self.classes = {'mage', 'nuker'} + self.classes = character_classes.sage self.attack_sensor = Circle(self.x, self.y, 96) self.t:cooldown(12, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function() @@ -178,10 +178,10 @@ function Player:init(args) end) elseif self.character == 'squire' then - self.color = yellow[0] + self.color = character_colors.squire self:set_as_rectangle(9, 9, 'dynamic', 'player') self.visual_shape = 'rectangle' - self.classes = {'warrior', 'healer', 'enchanter'} + self.classes = character_classes.squire self.t:every(8, function() self.applying_buff = true @@ -199,10 +199,10 @@ function Player:init(args) end) elseif self.character == 'cannoneer' then - self.color = green[0] + self.color = character_colors.cannoneer self:set_as_rectangle(9, 9, 'dynamic', 'player') self.visual_shape = 'rectangle' - self.classes = {'ranger', 'nuker'} + self.classes = character_classes.cannoneer self.attack_sensor = Circle(self.x, self.y, 128) self.t:cooldown(6, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function() @@ -213,10 +213,10 @@ function Player:init(args) end, nil, nil, 'shoot') elseif self.character == 'dual_gunner' then - self.color = green[0] + self.color = character_colors.dual_gunner self:set_as_rectangle(9, 9, 'dynamic', 'player') self.visual_shape = 'rectangle' - self.classes = {'ranger', 'rogue'} + self.classes = character_classes.dual_gunner self.attack_sensor = Circle(self.x, self.y, 96) self.t:cooldown(2, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function() @@ -227,10 +227,10 @@ function Player:init(args) end, nil, nil, 'shoot') elseif self.character == 'hunter' then - self.color = green[0] + self.color = character_colors.hunter self:set_as_rectangle(9, 9, 'dynamic', 'player') self.visual_shape = 'rectangle' - self.classes = {'ranger', 'conjurer'} + self.classes = character_classes.hunter self.attack_sensor = Circle(self.x, self.y, 160) self.t:cooldown(2, function() local enemies = self:get_objects_in_shape(self.attack_sensor, main.current.enemies); return enemies and #enemies > 0 end, function() @@ -241,10 +241,10 @@ function Player:init(args) end, nil, nil, 'shoot') elseif self.character == 'chronomancer' then - self.color = blue[0] + self.color = character_colors.chronomancer self:set_as_rectangle(9, 9, 'dynamic', 'player') self.visual_shape = 'rectangle' - self.classes = {'mage', 'enchanter'} + self.classes = character_classes.chronomancer self.t:every(2, function() local followers @@ -257,20 +257,20 @@ function Player:init(args) end) elseif self.character == 'spellblade' then - self.color = blue[0] + self.color = character_colors.spellblade self:set_as_rectangle(9, 9, 'dynamic', 'player') self.visual_shape = 'rectangle' - self.classes = {'mage', 'rogue'} + self.classes = character_classes.spellblade self.t:every(2, function() self:shoot(random:float(0, 2*math.pi)) end, nil, nil, 'shoot') elseif self.character == 'psykeeper' then - self.color = fg[0] + self.color = character_colors.psykeeper self:set_as_rectangle(9, 9, 'dynamic', 'player') self.visual_shape = 'rectangle' - self.classes = {'healer', 'psy'} + self.classes = character_classes.psykeeper self.psykeeper_heal = 0 self.t:every(8, function() @@ -288,10 +288,10 @@ function Player:init(args) end) elseif self.character == 'engineer' then - self.color = yellow[0] + self.color = character_colors.engineer self:set_as_rectangle(9, 9, 'dynamic', 'player') self.visual_shape = 'rectangle' - self.classes = {'conjurer'} + self.classes = character_classes.engineer self.t:every(8, function() SpawnEffect{group = main.current.effects, x = self.x, y = self.y, color = orange[0], action = function(x, y) @@ -299,6 +299,8 @@ function Player:init(args) end} end) end + + print(self.character) self:calculate_stats(true) if self.leader then @@ -1064,9 +1066,9 @@ function Saboteur:init(args) self:set_as_rectangle(8, 8, 'dynamic', 'player') self:set_restitution(0.5) - self.color = red[0] + self.color = character_colors.saboteur self.character = 'saboteur' - self.classes = {'saboteur', 'rogue', 'nuker'} + self.classes = character_classes.saboteur self:calculate_stats(true) self:set_as_steerable(self.v, 2000, 4*math.pi, 4)