forked from KristalTeam/Kristal
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
323 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,323 @@ | ||
---@class SpeechBubble : Object | ||
---@overload fun(...) : SpeechBubble | ||
local SpeechBubble, super = Class(Object) | ||
|
||
function SpeechBubble:init(text, x, y, options, speaker) | ||
super.init(self, x, y, 0, 0) | ||
options = options or {} | ||
|
||
self.layer = BATTLE_LAYERS["above_arena"] - 1 | ||
|
||
self.text = DialogueText("", 0, 0, 1, 1, { | ||
font = options["font"] or "plain", | ||
style = "none", | ||
line_offset = 0, | ||
}) | ||
self:addChild(self.text) | ||
|
||
self.text_width = 1 | ||
self.text_height = 1 | ||
|
||
self.right = options["right"] | ||
|
||
self.speaker = speaker | ||
self.actor = options["actor"] | ||
if type(self.actor) == "string" then | ||
self.actor = Registry.createActor(self.actor) | ||
end | ||
if self.speaker then | ||
self.actor = self.speaker.actor | ||
self.speaker.bubble = self | ||
end | ||
|
||
self:setCallback(options["after"]) | ||
self:setLineCallback(options["line_callback"]) | ||
|
||
self.text:registerCommand("noautoskip", function(text, node) | ||
Game.battle.use_textbox_timer = false | ||
end) | ||
|
||
self:setStyle(options["style"]) | ||
self:setText(text) | ||
end | ||
|
||
function SpeechBubble:setStyle(style) | ||
self.bubble = style or Game:getConfig("speechBubble") | ||
self.bubble_data = Assets.getBubbleData(self.bubble) | ||
self.auto = self.bubble_data["auto"] or false -- Whether the bubble automatically resizes. | ||
self.padding = self.bubble_data["text_padding"] or {left = 0, top = 0, right = 0, bottom = 0} | ||
self.text_bounds = self.bubble_data["text_bounds"] or {left = 0, top = 0, width = 0, height = 0} | ||
self.text_color = self.bubble_data["text_color"] or {0, 0, 0, 1} | ||
self.bubble_speed = self.bubble_data["speed"] or 0.5 | ||
self.bubble_anim_timer = 0 | ||
self.text:setTextColor(unpack(self.text_color)) | ||
if self.auto then | ||
self.sprites = { | ||
left = self.bubble_data["sprites"]["left" ] and Assets.getFramesOrTexture("bubbles/"..self.bubble_data["sprites"]["left" ]), | ||
right = self.bubble_data["sprites"]["right" ] and Assets.getFramesOrTexture("bubbles/"..self.bubble_data["sprites"]["right" ]), | ||
top = self.bubble_data["sprites"]["top" ] and Assets.getFramesOrTexture("bubbles/"..self.bubble_data["sprites"]["top" ]), | ||
bottom = self.bubble_data["sprites"]["bottom" ] and Assets.getFramesOrTexture("bubbles/"..self.bubble_data["sprites"]["bottom" ]), | ||
top_left = self.bubble_data["sprites"]["top_left" ] and Assets.getFramesOrTexture("bubbles/"..self.bubble_data["sprites"]["top_left" ]), | ||
top_right = self.bubble_data["sprites"]["top_right" ] and Assets.getFramesOrTexture("bubbles/"..self.bubble_data["sprites"]["top_right" ]), | ||
bottom_left = self.bubble_data["sprites"]["bottom_left" ] and Assets.getFramesOrTexture("bubbles/"..self.bubble_data["sprites"]["bottom_left" ]), | ||
bottom_right = self.bubble_data["sprites"]["bottom_right"] and Assets.getFramesOrTexture("bubbles/"..self.bubble_data["sprites"]["bottom_right"]), | ||
tail = self.bubble_data["sprites"]["tail" ] and Assets.getFramesOrTexture("bubbles/"..self.bubble_data["sprites"]["tail" ]), | ||
fill = self.bubble_data["sprites"]["fill" ] and Assets.getFramesOrTexture("bubbles/"..self.bubble_data["sprites"]["fill" ]) | ||
} | ||
else | ||
self.sprites = self.bubble_data["sprites"] and Assets.getFramesOrTexture("bubbles/"..self.bubble_data["sprites"]) | ||
end | ||
|
||
self.text.x = self.text_bounds["left"] or 0 | ||
self.text.y = self.text_bounds["top"] or 0 | ||
if not self.auto then | ||
self.text.width = self.text_bounds["width"] or SCREEN_WIDTH | ||
self.text.height = self.text_bounds["height"] or SCREEN_HEIGHT | ||
self.text.wrap = true | ||
self.text.auto_size = false | ||
else | ||
self.text.wrap = false | ||
self.text.auto_size = true | ||
end | ||
|
||
if self.bubble_data["origin"] then | ||
self:setOrigin(self.bubble_data["origin"][1], self.bubble_data["origin"][2]) | ||
elseif self.right then | ||
self:setOrigin(0, 0.5) | ||
else | ||
self:setOrigin(1, 0.5) | ||
end | ||
|
||
if self.right and self.auto then | ||
local left_width, _ = self:getSpriteSize("left") | ||
self.text.x = self:getTailWidth() + self.padding["left"] + left_width + 1 | ||
end | ||
|
||
self:updateSize() | ||
end | ||
|
||
function SpeechBubble:onRemoveFromStage(stage) | ||
super.onRemoveFromStage(self, stage) | ||
if self.speaker and self.speaker.bubble == self then | ||
self.speaker.bubble = nil | ||
end | ||
end | ||
|
||
function SpeechBubble:advance() | ||
self.text:advance() | ||
end | ||
|
||
function SpeechBubble:setText(text, callback, line_callback) | ||
if self.actor then | ||
if self.actor:getVoice() then | ||
if type(text) ~= "table" then | ||
text = {text} | ||
else | ||
text = Utils.copy(text) | ||
end | ||
for i,line in ipairs(text or {}) do | ||
text[i] = "[voice:"..self.actor:getVoice().."]"..line | ||
end | ||
end | ||
if self.actor:getFont() then | ||
if type(text) ~= "table" then | ||
text = {text} | ||
else | ||
text = Utils.copy(text) | ||
end | ||
for i,line in ipairs(text or {}) do | ||
text[i] = "[font:"..self.actor:getFont().."]"..line | ||
end | ||
end | ||
end | ||
|
||
self.text:setText(text, callback or self.advance_callback, line_callback or self.line_callback) | ||
|
||
self:updateSize() | ||
end | ||
|
||
function SpeechBubble:setAuto(auto) | ||
self.text.auto_advance = auto or false | ||
end | ||
|
||
function SpeechBubble:setAdvance(advance) | ||
self.text.can_advance = advance or false | ||
end | ||
|
||
function SpeechBubble:setSkippable(skippable) | ||
self.text.skippable = skippable or false | ||
end | ||
|
||
function SpeechBubble:setCallback(callback) | ||
self.advance_callback = callback | ||
self.text.advance_callback = callback | ||
end | ||
|
||
function SpeechBubble:setLineCallback(callback) | ||
self.line_callback = callback | ||
self.text.line_callback = callback | ||
end | ||
|
||
function SpeechBubble:setRight(right) | ||
self.right = right | ||
if not self.bubble_data["origin"] then | ||
if self.right then | ||
self:setOrigin(0, 0.5) | ||
else | ||
self:setOrigin(1, 0.5) | ||
end | ||
end | ||
self.text.x = self.text_bounds["left"] or 0 | ||
self.text.y = self.text_bounds["top"] or 0 | ||
if self.right and self.auto then | ||
local left_width, _ = self:getSpriteSize("left") | ||
self.text.x = self:getTailWidth() + self.padding["left"] + left_width + 1 | ||
end | ||
self:updateSize() | ||
end | ||
|
||
function SpeechBubble:isTyping() | ||
return self.text:isTyping() | ||
end | ||
|
||
function SpeechBubble:isDone() | ||
return self.text:isDone() | ||
end | ||
|
||
function SpeechBubble:update() | ||
super.update(self) | ||
|
||
self.bubble_anim_timer = self.bubble_anim_timer + DT | ||
|
||
self:updateSize() | ||
end | ||
|
||
function SpeechBubble:getBorder() | ||
-- Lua is a bad language | ||
local left, _ = self:getSpriteSize("left") | ||
local _, top = self:getSpriteSize("top") | ||
local right, _ = self:getSpriteSize("right") | ||
local _, bottom = self:getSpriteSize("bottom") | ||
return left, top, right, bottom | ||
end | ||
|
||
function SpeechBubble:getDebugRectangle() | ||
if not self.debug_rect then | ||
local bl, bt, br, bb = self:getBorder() | ||
|
||
local inner_left = -self.padding["left"] | ||
local inner_top = -self.padding["top"] | ||
local inner_right = self.text_width + self.padding["right"] | ||
local inner_bottom = self.text_height + self.padding["bottom"] | ||
|
||
local inner_width = self.padding["left"] + inner_right | ||
local inner_height = self.padding["top"] + inner_bottom | ||
|
||
-- TODO: FUck | ||
return {-bl + inner_left, -bt + inner_top, inner_width + bl + br + self:getTailWidth(), inner_height + bt + bb} | ||
end | ||
return super.getDebugRectangle(self) | ||
end | ||
|
||
function SpeechBubble:getSprite(name) | ||
local sprite = self.auto and self.sprites[name] or self.sprites | ||
if sprite then | ||
local frame = math.floor(self.bubble_anim_timer / self.bubble_speed) | ||
|
||
return sprite[(frame % #sprite) + 1] | ||
end | ||
end | ||
|
||
function SpeechBubble:getSpriteSize(name) | ||
local sprite = self:getSprite(name) | ||
if sprite then | ||
return sprite:getWidth(), sprite:getHeight() | ||
end | ||
return 0, 0 | ||
end | ||
|
||
function SpeechBubble:getTailWidth() | ||
local tail_width, _ = self:getSpriteSize("tail") | ||
return tail_width | ||
end | ||
|
||
function SpeechBubble:updateSize() | ||
if self.auto then | ||
local w, h = self.text:getTextWidth(), self.text:getTextHeight() | ||
|
||
self.text_width = w | ||
self.text_height = h | ||
|
||
local right_width, _ = self:getSpriteSize("right") | ||
self.width = w + self:getTailWidth() + right_width + self.padding["right"] | ||
self.height = h | ||
else | ||
self:setSize(self:getSpriteSize()) | ||
end | ||
end | ||
|
||
function SpeechBubble:draw() | ||
if not self.auto then | ||
Draw.draw(self:getSprite(), 0, 0) | ||
else | ||
local inner_left = -self.padding["left"] | ||
local inner_top = -self.padding["top"] | ||
local inner_right = self.text_width + self.padding["right"] | ||
local inner_bottom = self.text_height + self.padding["bottom"] | ||
|
||
local inner_width = self.padding["left"] + inner_right | ||
local inner_height = self.padding["top"] + inner_bottom | ||
|
||
local offset = 0 | ||
if self.right then | ||
local left_width, _ = self:getSpriteSize("left") | ||
offset = self:getTailWidth() + self.padding["left"] + left_width + 1 | ||
end | ||
|
||
|
||
local sprite_fill = self:getSprite("fill") | ||
local sprite_tail = self:getSprite("tail") | ||
|
||
local sprite_left = self:getSprite("left" ) | ||
local sprite_top = self:getSprite("top" ) | ||
local sprite_right = self:getSprite("right" ) | ||
local sprite_bottom = self:getSprite("bottom") | ||
|
||
local sprite_top_left = self:getSprite("top_left" ) | ||
local sprite_top_right = self:getSprite("top_right" ) | ||
local sprite_bottom_left = self:getSprite("bottom_left" ) | ||
local sprite_bottom_right = self:getSprite("bottom_right") | ||
|
||
|
||
if sprite_fill then Draw.draw(sprite_fill, offset + inner_left, inner_top, 0, inner_width / sprite_fill:getWidth(), inner_height / sprite_fill:getHeight()) end | ||
|
||
if sprite_left then Draw.draw(sprite_left, offset + inner_left - sprite_left:getWidth(), inner_top, 0, 1, inner_height / sprite_left:getHeight()) end | ||
if sprite_top then Draw.draw(sprite_top, offset + inner_left, inner_top - sprite_top:getHeight(), 0, inner_width / sprite_top:getWidth(), 1) end | ||
if sprite_right then Draw.draw(sprite_right, offset + inner_right, inner_top, 0, 1, inner_height / sprite_right:getHeight()) end | ||
if sprite_bottom then Draw.draw(sprite_bottom, offset + inner_left, inner_bottom, 0, inner_width / sprite_bottom:getWidth(), 1) end | ||
|
||
if sprite_top_left then Draw.draw(sprite_top_left, offset + inner_left - sprite_top_left:getWidth(), inner_top - sprite_top_left:getHeight()) end | ||
if sprite_top_right then Draw.draw(sprite_top_right, offset + inner_right, inner_top - sprite_top_right:getHeight()) end | ||
if sprite_bottom_left then Draw.draw(sprite_bottom_left, offset + inner_left - sprite_bottom_left:getWidth(), inner_bottom) end | ||
if sprite_bottom_right then Draw.draw(sprite_bottom_right, offset + inner_right, inner_bottom) end | ||
|
||
local scale = 1 | ||
if self.text.height < 35 then | ||
scale = 0.5 | ||
end | ||
|
||
if sprite_tail then | ||
if not self.right then | ||
local right, _ = self:getSpriteSize("right") | ||
Draw.draw(sprite_tail, inner_right + right, (self.text_height / 2 - 1 - (sprite_tail:getHeight() / 2)) * scale, 0, 1, scale) | ||
else | ||
local left, _ = self:getSpriteSize("left") | ||
Draw.draw(sprite_tail, offset + inner_left - left, (self.text_height / 2 - 1 - (sprite_tail:getHeight() / 2)) * scale, 0, -1, scale) | ||
end | ||
end | ||
end | ||
|
||
super.draw(self) | ||
end | ||
|
||
return SpeechBubble |