Compare commits
6 Commits
feature/da
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 649b73b3f8 | |||
| cd41cb3312 | |||
| ecd094e2d7 | |||
| 5b4f3052a6 | |||
| 83301a1a8e | |||
| 77bd76f6f9 |
8
.vscode/tasks.json
vendored
8
.vscode/tasks.json
vendored
@@ -11,17 +11,19 @@
|
|||||||
{
|
{
|
||||||
"label": "Build & Run TIC80",
|
"label": "Build & Run TIC80",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "make build && tic80 --fs=. impostor.lua"
|
"command": "make build && tic80 --fs=. impostor.lua",
|
||||||
|
"problemMatcher": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Export assets",
|
"label": "Export assets",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "make export_assets"
|
"command": "make export_assets",
|
||||||
|
"problemMatcher": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Make build",
|
"label": "Make build",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "make build"
|
"command": "make build"
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ steps:
|
|||||||
- name: update
|
- name: update
|
||||||
image: alpine
|
image: alpine
|
||||||
environment:
|
environment:
|
||||||
UPDATE_SERVER: https://games.vps.teletype.hu
|
UPDATE_SERVER: https://games.teletype.hu
|
||||||
UPDATE_SECRET:
|
UPDATE_SECRET:
|
||||||
from_secret: update_secret_key
|
from_secret: update_secret_key
|
||||||
commands:
|
commands:
|
||||||
|
|||||||
4
Makefile
4
Makefile
@@ -30,7 +30,7 @@ DROPAREA_HOST ?= vps.teletype.hu
|
|||||||
DROPAREA_PORT ?= 2223
|
DROPAREA_PORT ?= 2223
|
||||||
DROPAREA_TARGET_PATH ?= /home/drop
|
DROPAREA_TARGET_PATH ?= /home/drop
|
||||||
DROPAREA_USER ?= drop
|
DROPAREA_USER ?= drop
|
||||||
UPDATE_SERVER ?= https://games.vps.teletype.hu
|
UPDATE_SERVER ?= https://games.teletype.hu
|
||||||
|
|
||||||
all: build
|
all: build
|
||||||
|
|
||||||
@@ -164,6 +164,8 @@ export_assets:
|
|||||||
@$(call f_export_asset_awk,MAP,$(OUTPUT),$(ASSETS_LUA))
|
@$(call f_export_asset_awk,MAP,$(OUTPUT),$(ASSETS_LUA))
|
||||||
@$(call f_export_asset_awk,SFX,$(OUTPUT),$(ASSETS_LUA))
|
@$(call f_export_asset_awk,SFX,$(OUTPUT),$(ASSETS_LUA))
|
||||||
@$(call f_export_asset_awk,WAVES,$(OUTPUT),$(ASSETS_LUA))
|
@$(call f_export_asset_awk,WAVES,$(OUTPUT),$(ASSETS_LUA))
|
||||||
|
@$(call f_export_asset_awk,PATTERNS,$(OUTPUT),$(ASSETS_LUA))
|
||||||
|
@$(call f_export_asset_awk,TRACKS,$(OUTPUT),$(ASSETS_LUA))
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@rm -f $(PROJECT)-*.tic $(PROJECT)-*.html.zip $(PROJECT)-*-docs.zip $(PROJECT)-docs.zip $(OUTPUT) $(OUTPUT_ORIGINAL)
|
@rm -f $(PROJECT)-*.tic $(PROJECT)-*.html.zip $(PROJECT)-*-docs.zip $(PROJECT)-docs.zip $(OUTPUT) $(OUTPUT_ORIGINAL)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ function Audio.music_play_room_street_2() end
|
|||||||
function Audio.music_play_room_() end
|
function Audio.music_play_room_() end
|
||||||
--- Plays room work music.
|
--- Plays room work music.
|
||||||
--- @within Audio
|
--- @within Audio
|
||||||
function Audio.music_play_room_work() end
|
function Audio.music_play_room_work() music(0) end
|
||||||
|
|
||||||
--- Plays select sound effect.
|
--- Plays select sound effect.
|
||||||
--- @within Audio
|
--- @within Audio
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ function Config.initial_data()
|
|||||||
meter_bg = 1
|
meter_bg = 1
|
||||||
},
|
},
|
||||||
timing = {
|
timing = {
|
||||||
splash_duration = 120
|
splash_duration = 120,
|
||||||
|
minigame_win_duration = 180
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -78,7 +78,8 @@ function Minigame.get_default_ddr()
|
|||||||
current_song = nil,
|
current_song = nil,
|
||||||
pattern_index = 1,
|
pattern_index = 1,
|
||||||
use_pattern = false,
|
use_pattern = false,
|
||||||
return_window = nil
|
return_window = nil,
|
||||||
|
win_timer = 0
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -101,6 +102,7 @@ end
|
|||||||
--- * button_x (number) Button indicator X position.<br/>
|
--- * button_x (number) Button indicator X position.<br/>
|
||||||
--- * button_y (number) Button indicator Y position.<br/>
|
--- * button_y (number) Button indicator Y position.<br/>
|
||||||
--- * button_size (number) Button indicator size.<br/>
|
--- * button_size (number) Button indicator size.<br/>
|
||||||
|
--- * win_timer (number) Timer for the win message overlay.<br/>
|
||||||
function Minigame.get_default_button_mash()
|
function Minigame.get_default_button_mash()
|
||||||
return {
|
return {
|
||||||
bar_fill = 0,
|
bar_fill = 0,
|
||||||
@@ -120,7 +122,8 @@ function Minigame.get_default_button_mash()
|
|||||||
button_size = 12,
|
button_size = 12,
|
||||||
focus_center_x = nil,
|
focus_center_x = nil,
|
||||||
focus_center_y = nil,
|
focus_center_y = nil,
|
||||||
focus_initial_radius = 0
|
focus_initial_radius = 0,
|
||||||
|
win_timer = 0
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -150,6 +153,7 @@ end
|
|||||||
--- * button_size (number) Button indicator size.<br/>
|
--- * button_size (number) Button indicator size.<br/>
|
||||||
--- * press_cooldown (number) Current cooldown timer.<br/>
|
--- * press_cooldown (number) Current cooldown timer.<br/>
|
||||||
--- * press_cooldown_duration (number) Frames of press cooldown.<br/>
|
--- * press_cooldown_duration (number) Frames of press cooldown.<br/>
|
||||||
|
--- * win_timer (number) Timer for the win message overlay.<br/>
|
||||||
function Minigame.get_default_rhythm()
|
function Minigame.get_default_rhythm()
|
||||||
return {
|
return {
|
||||||
line_position = 0,
|
line_position = 0,
|
||||||
@@ -176,10 +180,28 @@ function Minigame.get_default_rhythm()
|
|||||||
press_cooldown_duration = 15,
|
press_cooldown_duration = 15,
|
||||||
focus_center_x = nil,
|
focus_center_x = nil,
|
||||||
focus_center_y = nil,
|
focus_center_y = nil,
|
||||||
focus_initial_radius = 0
|
focus_initial_radius = 0,
|
||||||
|
win_timer = 0
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Draws a unified win message overlay.
|
||||||
|
--- @within Minigame
|
||||||
|
function Minigame.draw_win_overlay()
|
||||||
|
local text = "WELL DONE!"
|
||||||
|
local tw = #text * 4
|
||||||
|
local th = 6
|
||||||
|
local padding = 4
|
||||||
|
local box_w = tw + padding * 2
|
||||||
|
local box_h = th + padding * 2
|
||||||
|
local box_x = (Config.screen.width - box_w) / 2
|
||||||
|
local box_y = (Config.screen.height - box_h) / 2
|
||||||
|
|
||||||
|
rect(box_x, box_y, box_w, box_h, Config.colors.dark_grey)
|
||||||
|
rectb(box_x, box_y, box_w, box_h, Config.colors.white)
|
||||||
|
Print.text_center(text, Config.screen.width / 2, box_y + padding, Config.colors.white)
|
||||||
|
end
|
||||||
|
|
||||||
--- Configures DDR minigame.
|
--- Configures DDR minigame.
|
||||||
--- @within Minigame
|
--- @within Minigame
|
||||||
--- @param params table Optional parameters to override defaults (see Minigame.get_default_ddr).
|
--- @param params table Optional parameters to override defaults (see Minigame.get_default_ddr).
|
||||||
|
|||||||
@@ -305,13 +305,15 @@
|
|||||||
-- 033:000000010002000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d40000000004
|
-- 033:000000010002000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d40000000004
|
||||||
-- 044:0600f6000620f6000600f6000610f600f600f6000600f600f600f600f6000600060006000600060006000600060006000600060006000600060006004600000f0f00
|
-- 044:0600f6000620f6000600f6000610f600f600f6000600f600f600f600f6000600060006000600060006000600060006000600060006000600060006004600000f0f00
|
||||||
-- 045:0000f0000020f0000000f0000010f000f000f0000000f000f000f000f0000000000000000000000000000000000000000000000000000000000000004600000f0f00
|
-- 045:0000f0000020f0000000f0000010f000f000f0000000f000f000f000f0000000000000000000000000000000000000000000000000000000000000004600000f0f00
|
||||||
-- 057:000000010002000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d40000000004
|
-- 048:090009000900090009000900090009000900090009000900090009000900090009000900090009000900090009000900090009000900090009000900400000000000
|
||||||
-- 058:41004110410041104100411041004110c100c100c100c100c100c100c100c100c100c100c100c100c100c100c100c100c100c100c100c100c100c100100000080800
|
-- 056:4100510061406140717081709100b100c100d100e100e100e100f100f100f100f100f100f100f100f100f100f100f100f100f100f100f100f100f100580000000600
|
||||||
-- 059:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000
|
-- 057:000000010002000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c40000000004
|
||||||
|
-- 058:41004110410041104100411041004110c100c100c100c100c100c100c100c100c100c100c100c100c100c100c100c100c100c100c100c100c100c100400000080800
|
||||||
|
-- 059:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000
|
||||||
-- 060:220022002200820082008200820082008200820082008200820082008200820082008200820082008200820082008200820082008200820082008200100000000000
|
-- 060:220022002200820082008200820082008200820082008200820082008200820082008200820082008200820082008200820082008200820082008200100000000000
|
||||||
-- 061:9f009f00bf00df00df00ef00ef00ef00ef00ef00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00400000000000
|
-- 061:9f009f00bf00df00df00ef00ef00ef00ef00ef00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00400000000000
|
||||||
-- 062:00000100010001000100510081008100910091009100a100a100a100a100a100b100b100b100b100c100c100c100d100d100d100e100e100e100f100484000000000
|
-- 062:00000100010001000100510081008100910091009100a100a100a100a100a100b100b100b100b100c100c100c100d100d100d100e100e100e100f100484000000000
|
||||||
-- 063:00b000100000000000000000100060009000b000c000d000d000e000e000e000f000f000f000f000f000f000f000f000f000f000f000f000f000f000405000000000
|
-- 063:00b000100000000000000000100060009000b000c000d000d000e000e000e000f000f000f000f000f000f000f000f000f000f000f000f000f000f000200000000000
|
||||||
-- </SFX>
|
-- </SFX>
|
||||||
-- <WAVES>
|
-- <WAVES>
|
||||||
-- 000:bcceefceedddddc84333121268abaa99
|
-- 000:bcceefceedddddc84333121268abaa99
|
||||||
@@ -325,3 +327,11 @@
|
|||||||
-- 008:0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f
|
-- 008:0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f
|
||||||
-- 009:fff000fff000fff000fff000fff000ff
|
-- 009:fff000fff000fff000fff000fff000ff
|
||||||
-- </WAVES>
|
-- </WAVES>
|
||||||
|
-- <PATTERNS>
|
||||||
|
-- 000:4008b50000000000000000001008c10000004008b50000001008c1000000000000000000e008b30000004008b50000001008c10000000008c10000000008c10000000000000000000000000000000000000000000000000000000000000000004008b50000000000000000001008c10000004008b50000001008c10000000008c1000000e008b30000004008b50000001008c10000000008c10000000008c10000000008c10000000008c10000000008c1000000000000000000000000000000
|
||||||
|
-- 001:4008b50000000000000000001008c10000004008b50000001008c1000000000000000000e008b30000004008b50000001008c10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007008b50000007008b50000001008c10000007008b50000001008c10000000008c10000007008b50000009008b50000001008c10000009008b50000001008c10000009008b50000009008b50000001008c10000009008b50000001008c1000000
|
||||||
|
-- 003:4008d30000000000000000000000000000000000000000004008d90000000000000000000000000000000000000000004008d30000000000000000000000000000004008d30000004008d90000000000000000000000000000000000000000004008d30000000000000000000000000000000000000000004008d90000000000000000000000000000000000000000004008d30000000000000000000000000000004008d30000004008d9000000000000000000000000000000000000000000
|
||||||
|
-- </PATTERNS>
|
||||||
|
-- <TRACKS>
|
||||||
|
-- 000:100001200001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
-- </TRACKS>
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
--- @section AudioTestWindow
|
--- @section AudioTestWindow
|
||||||
AudioTestWindow = {
|
AudioTestWindow.index_menu = 1
|
||||||
index_menu = 1,
|
AudioTestWindow.index_func = 1
|
||||||
index_func = 1,
|
AudioTestWindow.list_func = {}
|
||||||
list_func = {},
|
AudioTestWindow.menuitems = {}
|
||||||
menuitems = {},
|
AudioTestWindow.last_pressed = false
|
||||||
last_pressed = false
|
|
||||||
}
|
|
||||||
|
|
||||||
--- Generates menu items for audio test.
|
--- Generates menu items for audio test.
|
||||||
--- @within AudioTestWindow
|
--- @within AudioTestWindow
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
--- @section ConfigurationWindow
|
--- @section ConfigurationWindow
|
||||||
ConfigurationWindow = {
|
ConfigurationWindow.controls = {}
|
||||||
controls = {},
|
ConfigurationWindow.selected_control = 1
|
||||||
selected_control = 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
--- Initializes configuration window.
|
--- Initializes configuration window.
|
||||||
--- @within ConfigurationWindow
|
--- @within ConfigurationWindow
|
||||||
|
|||||||
@@ -108,18 +108,25 @@ end
|
|||||||
--- @within MinigameDDRWindow
|
--- @within MinigameDDRWindow
|
||||||
function MinigameDDRWindow.update()
|
function MinigameDDRWindow.update()
|
||||||
local mg = Context.minigame_ddr
|
local mg = Context.minigame_ddr
|
||||||
|
|
||||||
|
if mg.win_timer > 0 then
|
||||||
|
mg.win_timer = mg.win_timer - 1
|
||||||
|
if mg.win_timer == 0 then
|
||||||
|
Meter.on_minigame_complete()
|
||||||
|
Meter.show()
|
||||||
|
Window.set_current(mg.return_window)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
if mg.bar_fill >= mg.max_fill then
|
if mg.bar_fill >= mg.max_fill then
|
||||||
Meter.on_minigame_complete()
|
mg.win_timer = Config.timing.minigame_win_duration
|
||||||
Meter.show()
|
|
||||||
Window.set_current(mg.return_window)
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
mg.frame_counter = mg.frame_counter + 1
|
mg.frame_counter = mg.frame_counter + 1
|
||||||
if mg.use_pattern and mg.current_song and mg.current_song.end_frame then
|
if mg.use_pattern and mg.current_song and mg.current_song.end_frame then
|
||||||
if mg.frame_counter > mg.current_song.end_frame and #mg.arrows == 0 then
|
if mg.frame_counter > mg.current_song.end_frame and #mg.arrows == 0 then
|
||||||
Meter.on_minigame_complete()
|
mg.win_timer = Config.timing.minigame_win_duration
|
||||||
Meter.show()
|
|
||||||
Window.set_current(mg.return_window)
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -265,4 +272,7 @@ function MinigameDDRWindow.draw()
|
|||||||
else
|
else
|
||||||
Print.text_center("RANDOM MODE", Config.screen.width / 2, debug_y, Config.colors.blue)
|
Print.text_center("RANDOM MODE", Config.screen.width / 2, debug_y, Config.colors.blue)
|
||||||
end
|
end
|
||||||
|
if mg.win_timer > 0 then
|
||||||
|
Minigame.draw_win_overlay()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
@@ -25,6 +25,18 @@ end
|
|||||||
--- @within MinigameButtonMashWindow
|
--- @within MinigameButtonMashWindow
|
||||||
function MinigameButtonMashWindow.update()
|
function MinigameButtonMashWindow.update()
|
||||||
local mg = Context.minigame_button_mash
|
local mg = Context.minigame_button_mash
|
||||||
|
|
||||||
|
if mg.win_timer > 0 then
|
||||||
|
mg.win_timer = mg.win_timer - 1
|
||||||
|
if mg.win_timer == 0 then
|
||||||
|
Meter.on_minigame_complete()
|
||||||
|
Meter.show()
|
||||||
|
if mg.focus_center_x then Focus.stop() end
|
||||||
|
Window.set_current(mg.return_window)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
if Input.select() then
|
if Input.select() then
|
||||||
mg.bar_fill = mg.bar_fill + mg.fill_per_press
|
mg.bar_fill = mg.bar_fill + mg.fill_per_press
|
||||||
mg.button_pressed_timer = mg.button_press_duration
|
mg.button_pressed_timer = mg.button_press_duration
|
||||||
@@ -33,10 +45,7 @@ function MinigameButtonMashWindow.update()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
if mg.bar_fill >= mg.max_fill then
|
if mg.bar_fill >= mg.max_fill then
|
||||||
Meter.on_minigame_complete()
|
mg.win_timer = Config.timing.minigame_win_duration
|
||||||
Meter.show()
|
|
||||||
if mg.focus_center_x then Focus.stop() end
|
|
||||||
Window.set_current(mg.return_window)
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local degradation = mg.base_degradation + (mg.bar_fill * mg.degradation_multiplier)
|
local degradation = mg.base_degradation + (mg.bar_fill * mg.degradation_multiplier)
|
||||||
@@ -86,4 +95,8 @@ function MinigameButtonMashWindow.draw()
|
|||||||
Print.text_center("MASH Z!", Config.screen.width / 2, mg.bar_y + mg.bar_height + 10, Config.colors.light_grey)
|
Print.text_center("MASH Z!", Config.screen.width / 2, mg.bar_y + mg.bar_height + 10, Config.colors.light_grey)
|
||||||
local percentage = math.floor((mg.bar_fill / mg.max_fill) * 100)
|
local percentage = math.floor((mg.bar_fill / mg.max_fill) * 100)
|
||||||
Print.text_center(percentage .. "%", mg.bar_x + mg.bar_width / 2, mg.bar_y + 2, Config.colors.black)
|
Print.text_center(percentage .. "%", mg.bar_x + mg.bar_width / 2, mg.bar_y + 2, Config.colors.black)
|
||||||
|
|
||||||
|
if mg.win_timer > 0 then
|
||||||
|
Minigame.draw_win_overlay()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -27,6 +27,18 @@ end
|
|||||||
--- @within MinigameRhythmWindow
|
--- @within MinigameRhythmWindow
|
||||||
function MinigameRhythmWindow.update()
|
function MinigameRhythmWindow.update()
|
||||||
local mg = Context.minigame_rhythm
|
local mg = Context.minigame_rhythm
|
||||||
|
|
||||||
|
if mg.win_timer > 0 then
|
||||||
|
mg.win_timer = mg.win_timer - 1
|
||||||
|
if mg.win_timer == 0 then
|
||||||
|
Meter.on_minigame_complete()
|
||||||
|
Meter.show()
|
||||||
|
if mg.focus_center_x then Focus.stop() end
|
||||||
|
Window.set_current(mg.return_window)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
mg.line_position = mg.line_position + (mg.line_speed * mg.line_direction)
|
mg.line_position = mg.line_position + (mg.line_speed * mg.line_direction)
|
||||||
if mg.line_position > 1 then
|
if mg.line_position > 1 then
|
||||||
mg.line_position = 1
|
mg.line_position = 1
|
||||||
@@ -57,10 +69,7 @@ function MinigameRhythmWindow.update()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
if mg.score >= mg.max_score then
|
if mg.score >= mg.max_score then
|
||||||
Meter.on_minigame_complete()
|
mg.win_timer = Config.timing.minigame_win_duration
|
||||||
Meter.show()
|
|
||||||
if mg.focus_center_x then Focus.stop() end
|
|
||||||
Window.set_current(mg.return_window)
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if mg.button_pressed_timer > 0 then
|
if mg.button_pressed_timer > 0 then
|
||||||
@@ -107,4 +116,8 @@ function MinigameRhythmWindow.draw()
|
|||||||
circ(mg.button_x, mg.button_y, mg.button_size - 2, button_color)
|
circ(mg.button_x, mg.button_y, mg.button_size - 2, button_color)
|
||||||
end
|
end
|
||||||
Print.text_center("Z", mg.button_x - 2, mg.button_y - 3, button_color)
|
Print.text_center("Z", mg.button_x - 2, mg.button_y - 3, button_color)
|
||||||
|
|
||||||
|
if mg.win_timer > 0 then
|
||||||
|
Minigame.draw_win_overlay()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
289
infra.md
289
infra.md
@@ -1,289 +0,0 @@
|
|||||||
# Server
|
|
||||||
```mermaid
|
|
||||||
graph TD
|
|
||||||
Internet --> Nginx
|
|
||||||
|
|
||||||
Nginx --> Traefik
|
|
||||||
Traefik --> Gitea
|
|
||||||
Gitea --> GiteaDB[(Gitea data / SQLite)]
|
|
||||||
|
|
||||||
Traefik --> WoodpeckerServer
|
|
||||||
WoodpeckerServer --> WoodpeckerDB[(Woodpecker data / SQLite)]
|
|
||||||
WoodpeckerServer --> WoodpeckerAgent
|
|
||||||
WoodpeckerAgent --> DockerSocket[(Docker)]
|
|
||||||
|
|
||||||
Traefik --> WebApp
|
|
||||||
WebApp --> MySQL[(MySQL)]
|
|
||||||
WebApp --> Softwares[(Volume)]
|
|
||||||
|
|
||||||
Droparea --> Softwares
|
|
||||||
|
|
||||||
Nginx --> Discourse
|
|
||||||
Discourse --> ForumDB[(Postgres)]
|
|
||||||
Discourse --> Redis[(Redis)]
|
|
||||||
|
|
||||||
Nginx --> Wiki
|
|
||||||
Wiki --> WikiDB[(Postgres)]
|
|
||||||
```
|
|
||||||
|
|
||||||
# TIC-80 Pipeline
|
|
||||||
|
|
||||||
This document describes the Woodpecker CI pipeline used to build, export, upload, and publish a TIC-80 game project.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
The pipeline performs the following steps:
|
|
||||||
|
|
||||||
1. **Build** the TIC-80 project using a custom Docker image
|
|
||||||
2. **Export** the game to `.tic` and HTML formats
|
|
||||||
3. **Upload artifacts** to a remote server via SCP
|
|
||||||
4. **Notify an update server** to publish the new version
|
|
||||||
|
|
||||||
The pipeline is driven by environment variables so it can be reused across projects.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Global Environment
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
environment: &environment
|
|
||||||
GAME_NAME: mranderson
|
|
||||||
GAME_LANG: lua
|
|
||||||
```
|
|
||||||
|
|
||||||
- **GAME_NAME**: Project name (used for all outputs)
|
|
||||||
- **GAME_LANG**: Source language used by TIC-80 (Lua)
|
|
||||||
|
|
||||||
The anchor (`&environment`) allows reuse across steps.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Step 1: Build & Export
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- name: build
|
|
||||||
image: git.teletype.hu/internal/tic80pro:latest
|
|
||||||
environment:
|
|
||||||
<<: *environment
|
|
||||||
XDG_RUNTIME_DIR: /tmp
|
|
||||||
commands:
|
|
||||||
- make build
|
|
||||||
- make export
|
|
||||||
```
|
|
||||||
|
|
||||||
**What it does:**
|
|
||||||
|
|
||||||
- Uses a custom TIC-80 Pro Docker image hosted in Gitea
|
|
||||||
- Runs the Makefile `build` target to assemble source files
|
|
||||||
- Runs the `export` target to generate:
|
|
||||||
- `.tic` cartridge
|
|
||||||
- `.html.zip` web build
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Step 2: Artifact Upload
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- name: artifact
|
|
||||||
image: alpine
|
|
||||||
environment:
|
|
||||||
<<: *environment
|
|
||||||
DROPAREA_HOST: vps.teletype.hu
|
|
||||||
DROPAREA_PORT: 2223
|
|
||||||
DROPAREA_TARGET_PATH: /home/drop
|
|
||||||
DROPAREA_USER: drop
|
|
||||||
DROPAREA_SSH_PASSWORD:
|
|
||||||
from_secret: droparea_ssh_password
|
|
||||||
commands:
|
|
||||||
- apk add --no-cache openssh-client sshpass
|
|
||||||
- mkdir -p /root/.ssh
|
|
||||||
- sshpass -p $DROPAREA_SSH_PASSWORD scp -o StrictHostKeyChecking=no -P $DROPAREA_PORT \
|
|
||||||
$GAME_NAME.$GAME_LANG \
|
|
||||||
$GAME_NAME.tic \
|
|
||||||
$GAME_NAME.html.zip \
|
|
||||||
$DROPAREA_USER@$DROPAREA_HOST:$DROPAREA_TARGET_PATH
|
|
||||||
```
|
|
||||||
|
|
||||||
**What it does:**
|
|
||||||
|
|
||||||
- Installs SCP tooling in a minimal Alpine container
|
|
||||||
- Uploads:
|
|
||||||
- Source file
|
|
||||||
- TIC-80 cartridge
|
|
||||||
- HTML export ZIP
|
|
||||||
- Uses secrets for SSH authentication
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Step 3: Update Notification
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- name: update
|
|
||||||
image: alpine
|
|
||||||
environment:
|
|
||||||
<<: *environment
|
|
||||||
UPDATE_SERVER: https://games.vps.teletype.hu
|
|
||||||
UPDATE_SECRET:
|
|
||||||
from_secret: update_secret_key
|
|
||||||
commands:
|
|
||||||
- apk add --no-cache curl
|
|
||||||
- curl "$UPDATE_SERVER/update?secret=$UPDATE_SECRET&name=$GAME_NAME&platform=tic80"
|
|
||||||
```
|
|
||||||
|
|
||||||
**What it does:**
|
|
||||||
|
|
||||||
- Sends an HTTP request to the update server
|
|
||||||
- Notifies that a new TIC-80 build is available
|
|
||||||
- Uses a secret key to authorize the update
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Result
|
|
||||||
|
|
||||||
After a successful run:
|
|
||||||
|
|
||||||
- The game is built and exported
|
|
||||||
- Artifacts are uploaded to the server
|
|
||||||
- The public game index is updated automatically
|
|
||||||
|
|
||||||
This pipeline enables **fully automated TIC-80 releases** using open tools and infrastructure.
|
|
||||||
|
|
||||||
|
|
||||||
# TIC-80 Makefile Project Builder
|
|
||||||
|
|
||||||
This Makefile provides a simple, reproducible workflow for building **TIC-80 Lua projects** from multiple source files. It is designed for small indie or experimental projects where the source code is split into logical parts and then merged into a single `.lua` cartridge.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
The workflow is based on four core ideas:
|
|
||||||
|
|
||||||
- Source code is split into multiple Lua files inside an `inc/` directory
|
|
||||||
- A project-specific `.inc` file defines the **build order**
|
|
||||||
- All source files are concatenated into one final `.lua` file
|
|
||||||
- TIC-80 is used in CLI mode to export runnable artifacts
|
|
||||||
|
|
||||||
This approach keeps the codebase modular while remaining compatible with TIC-80’s single-file cartridge model.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Project Structure
|
|
||||||
|
|
||||||
```text
|
|
||||||
project-root/
|
|
||||||
├── inc/
|
|
||||||
│ ├── core.lua
|
|
||||||
│ ├── player.lua
|
|
||||||
│ └── world.lua
|
|
||||||
├── mranderson.inc
|
|
||||||
├── Makefile
|
|
||||||
└── README.md
|
|
||||||
```
|
|
||||||
|
|
||||||
- `inc/` contains all Lua source fragments
|
|
||||||
- `<project>.inc` defines the order in which files are merged
|
|
||||||
- `<project>.lua` is generated automatically
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## The `.inc` File
|
|
||||||
|
|
||||||
The `.inc` file is a **plain text file** listing Lua source files in build order:
|
|
||||||
|
|
||||||
```text
|
|
||||||
core.lua
|
|
||||||
player.lua
|
|
||||||
world.lua
|
|
||||||
```
|
|
||||||
|
|
||||||
The order matters. Files listed earlier are concatenated first and must define any globals used later.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### Build (default)
|
|
||||||
|
|
||||||
```sh
|
|
||||||
make build
|
|
||||||
```
|
|
||||||
|
|
||||||
- Reads `mranderson.inc`
|
|
||||||
- Concatenates files from `inc/`
|
|
||||||
- Produces `mranderson.lua`
|
|
||||||
|
|
||||||
### Export (TIC-80)
|
|
||||||
|
|
||||||
```sh
|
|
||||||
make export
|
|
||||||
```
|
|
||||||
|
|
||||||
- Loads the generated Lua file into TIC-80 (CLI mode)
|
|
||||||
- Saves a `.tic` cartridge
|
|
||||||
- Exports an HTML build
|
|
||||||
|
|
||||||
### Export Assets
|
|
||||||
|
|
||||||
```sh
|
|
||||||
make export_assets
|
|
||||||
```
|
|
||||||
|
|
||||||
- **Purpose**: Extracts asset sections (PALETTE, TILES, SPRITES, MAP, SFX, MUSIC) from the compiled `<project>.lua` file.
|
|
||||||
- **Mechanism**: Uses `sed` to directly parse the generated `<project>.lua` and saves the extracted data into `inc/meta/meta.assets.lua`. This file can then be used to embed the asset data directly into other parts of the project or for version control of visual assets.
|
|
||||||
|
|
||||||
### Import Assets
|
|
||||||
|
|
||||||
The `import_assets` target was considered during development but is currently not part of the build workflow. Asset handling for TIC-80 projects within this Makefile relies solely on direct extraction (`export_assets`) from the built Lua cartridge, rather than importing external asset definitions. This target may be implemented in the future if a need for pre-build asset injection arises.
|
|
||||||
|
|
||||||
### Watch Mode
|
|
||||||
|
|
||||||
```sh
|
|
||||||
make watch
|
|
||||||
```
|
|
||||||
|
|
||||||
- Performs an initial build
|
|
||||||
- Watches the `inc/` directory and `.inc` file
|
|
||||||
- Rebuilds automatically on any change
|
|
||||||
|
|
||||||
Requires `fswatch` to be installed.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Generated Artifacts
|
|
||||||
|
|
||||||
| File | Description |
|
|
||||||
|-----|-------------|
|
|
||||||
| `<project>.lua` | Merged Lua source (input for TIC-80) |
|
|
||||||
| `<project>.tic` | TIC-80 cartridge |
|
|
||||||
| `<project>.html` | Web export |
|
|
||||||
| `<project>.html.zip` | Packaged HTML build |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Design Goals
|
|
||||||
|
|
||||||
- Keep TIC-80 projects modular
|
|
||||||
- Avoid manual copy-paste between files
|
|
||||||
- Enable fast iteration and experimentation
|
|
||||||
- Remain fully compatible with open-source tooling
|
|
||||||
|
|
||||||
This Makefile is intentionally minimal and transparent, favoring simplicity over abstraction.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
- `make`
|
|
||||||
- `tic80` available in PATH
|
|
||||||
- `fswatch` (only for watch mode)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
MIT License — free to use, modify, and redistribute.
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user