Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f076205af | ||
|
|
8bc84c1f36 | ||
|
|
418c30e334 |
No files matched your search
@@ -81,16 +81,22 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sudo apt-get update && sudo apt-get install -y nsis p7zip-full
|
sudo apt-get update && sudo apt-get install -y nsis p7zip-full
|
||||||
VERSION="$(sed -n 's/.*config\/version="\([^"]*\)".*/\1/p' project.godot)"
|
VERSION="$(sed -n 's/.*config\/version="\([^"]*\)".*/\1/p' project.godot)"
|
||||||
makensis /DVERSION="$VERSION" \
|
# NOTE: on Linux, makensis uses -D defines (the /D form is Windows-only
|
||||||
/DARTIFACT="build/step-line-windows-$VERSION.exe" \
|
# and is rejected as a script path), and it resolves relative paths
|
||||||
/DICON=packaging/windows/step-line.ico \
|
# against the script directory — pass absolute paths from the workspace.
|
||||||
|
cp assets/textures/icon.ico packaging/windows/step-line.ico
|
||||||
|
makensis \
|
||||||
|
-DVERSION="$VERSION" \
|
||||||
|
-DARTIFACT="$PWD/build/step-line-windows-$VERSION.exe" \
|
||||||
|
-DICON="$PWD/packaging/windows/step-line.ico" \
|
||||||
|
-DOUT="$PWD/build/step-line-setup-$VERSION.exe" \
|
||||||
packaging/windows/step-line.nsi
|
packaging/windows/step-line.nsi
|
||||||
|
|
||||||
- name: Verify Windows installer contents
|
- name: Verify Windows installer contents
|
||||||
run: |
|
run: |
|
||||||
VERSION="$(sed -n 's/.*config\/version="\([^"]*\)".*/\1/p' project.godot)"
|
VERSION="$(sed -n 's/.*config\/version="\([^"]*\)".*/\1/p' project.godot)"
|
||||||
ls -la build/step-line-setup-$VERSION.exe
|
ls -la build/step-line-setup-$VERSION.exe
|
||||||
7z l build/step-line-setup-$VERSION.exe | grep -E "Step Line.exe|uninstall.exe"
|
7z l build/step-line-setup-$VERSION.exe | grep -E "step-line.exe|uninstall.exe"
|
||||||
|
|
||||||
- name: Package Linux AppImage
|
- name: Package Linux AppImage
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -68,3 +68,7 @@ performance hardening only.
|
|||||||
- [ ] Profile the crowd: ensure textured materials and props hold target frame rate around a
|
- [ ] Profile the crowd: ensure textured materials and props hold target frame rate around a
|
||||||
busy entrance.
|
busy entrance.
|
||||||
- [ ] Add LOD or culling for distant NPCs/props if the crowd grows.
|
- [ ] Add LOD or culling for distant NPCs/props if the crowd grows.
|
||||||
|
|
||||||
|
## Screenshot Refresh
|
||||||
|
|
||||||
|
- [ ] Regenerate and verify the six README screenshots from the current build.
|
||||||
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 225 KiB After Width: | Height: | Size: 191 KiB |
|
Before Width: | Height: | Size: 233 KiB After Width: | Height: | Size: 197 KiB |
|
Before Width: | Height: | Size: 242 KiB After Width: | Height: | Size: 214 KiB |
|
Before Width: | Height: | Size: 219 KiB After Width: | Height: | Size: 170 KiB |
|
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 200 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 237 KiB |
@@ -27,8 +27,11 @@ cp "$HERE/step-line.desktop" "$APPDIR/step-line.desktop"
|
|||||||
cp "$HERE/AppRun" "$APPDIR/AppRun"
|
cp "$HERE/AppRun" "$APPDIR/AppRun"
|
||||||
chmod +x "$APPDIR/AppRun"
|
chmod +x "$APPDIR/AppRun"
|
||||||
cp "$HERE/step-line.png" "$APPDIR/step-line.png"
|
cp "$HERE/step-line.png" "$APPDIR/step-line.png"
|
||||||
mkdir -p "$APPDIR/usr/share/metainfo"
|
# Desktop entry + metainfo in standard locations (AppStream validation requires
|
||||||
cp "$HERE/step-line.appdata.xml" "$APPDIR/usr/share/metainfo/step-line.appdata.xml"
|
# the metainfo filename to match the component id, and the .desktop discoverable).
|
||||||
|
mkdir -p "$APPDIR/usr/share/applications" "$APPDIR/usr/share/metainfo"
|
||||||
|
cp "$HERE/step-line.desktop" "$APPDIR/usr/share/applications/step-line.desktop"
|
||||||
|
cp "$HERE/step-line.appdata.xml" "$APPDIR/usr/share/metainfo/net.stepline.game.appdata.xml"
|
||||||
|
|
||||||
TOOL="${APPIMAGE_TOOL:-/tmp/appimagetool-x86_64.AppImage}"
|
TOOL="${APPIMAGE_TOOL:-/tmp/appimagetool-x86_64.AppImage}"
|
||||||
if [[ ! -f "$TOOL" ]]; then
|
if [[ ! -f "$TOOL" ]]; then
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<component type="desktop-application">
|
<component type="desktop-application">
|
||||||
<id>net.step-line.StepLine</id>
|
<id>net.stepline.game</id>
|
||||||
<name>Step Line</name>
|
<name>Step Line</name>
|
||||||
<summary>Workplace security simulation on Hollywood Boulevard</summary>
|
<summary>Workplace security simulation on Hollywood Boulevard</summary>
|
||||||
|
<url type="homepage">https://git.allucanget.biz/zwitschi/security-game</url>
|
||||||
|
<developer id="net.stepline"><name>Step Line Team</name></developer>
|
||||||
<description>
|
<description>
|
||||||
<p>
|
<p>
|
||||||
Step Line is a workplace security simulation about observation, communication,
|
Step Line is a workplace security simulation about observation, communication,
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 15 KiB |
@@ -14,8 +14,12 @@
|
|||||||
!define ICON "packaging\windows\step-line.ico"
|
!define ICON "packaging\windows\step-line.ico"
|
||||||
!endif
|
!endif
|
||||||
|
|
||||||
; The installed executable always uses this clean name.
|
; The installed executable uses this clean name (no spaces — NSIS /oname tokens
|
||||||
!define INSTALLED_EXE "Step Line.exe"
|
; on whitespace, so a spaced name breaks the File directive).
|
||||||
|
!define INSTALLED_EXE "step-line.exe"
|
||||||
|
!ifndef OUT
|
||||||
|
!define OUT "build\step-line-setup-${VERSION}.exe"
|
||||||
|
!endif
|
||||||
!define COMPANY "Step Line Project"
|
!define COMPANY "Step Line Project"
|
||||||
!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\Step Line"
|
!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\Step Line"
|
||||||
|
|
||||||
@@ -25,7 +29,7 @@ Icon "${ICON}"
|
|||||||
UninstallIcon "${ICON}"
|
UninstallIcon "${ICON}"
|
||||||
|
|
||||||
Name "Step Line ${VERSION}"
|
Name "Step Line ${VERSION}"
|
||||||
OutFile "build\step-line-setup-${VERSION}.exe"
|
OutFile "${OUT}"
|
||||||
InstallDir "$PROGRAMFILES64\Step Line"
|
InstallDir "$PROGRAMFILES64\Step Line"
|
||||||
RequestExecutionLevel admin
|
RequestExecutionLevel admin
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
appimagetool.png
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
this_dir="$(dirname -- "$(readlink -f -- "$0")")"
|
||||||
|
|
||||||
|
# make appimagetool prefer the bundled mksquashfs
|
||||||
|
export PATH="$this_dir"/usr/bin:"$PATH"
|
||||||
|
|
||||||
|
exec "$this_dir"/usr/bin/appimagetool "$@"
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
usr/share/applications/appimagetool.desktop
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
usr/share/icons/hicolor/128x128/apps/appimagetool.png
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=appimagetool
|
||||||
|
Exec=appimagetool
|
||||||
|
Comment=Tool to generate AppImages from AppDirs
|
||||||
|
Icon=appimagetool
|
||||||
|
Categories=Development;
|
||||||
|
Terminal=true
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 9.5 KiB |
@@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<component type="desktop">
|
||||||
|
<id>appimagetool.desktop</id>
|
||||||
|
<metadata_license>MIT</metadata_license>
|
||||||
|
<project_license>MIT</project_license>
|
||||||
|
<name>appimagetool</name>
|
||||||
|
<summary>Create AppImage files</summary>
|
||||||
|
<description>
|
||||||
|
<p>
|
||||||
|
appimagetool is a tool that lets you generate AppImage files. An AppImage
|
||||||
|
is a self-running bundle that contains an application and everything
|
||||||
|
it needs to run that cannot reasonably expected to be part of each target system.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
This can include libraries that are not commonly available on target systems,
|
||||||
|
resources such as translations, icons, fonts, and other auxiliary files.
|
||||||
|
appimagetool makes it easy to take an AppDir (e.g., generated by linuxdeployqt)
|
||||||
|
and turn it into an AppImage.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
You can also embed update information so that your users can update the AppImage
|
||||||
|
using binary delta updates with the AppImageUpdate tool.
|
||||||
|
You can also sign the AppImage with GPG.
|
||||||
|
</p>
|
||||||
|
</description>
|
||||||
|
<url type="homepage">https://github.com/AppImage/AppImageKit</url>
|
||||||
|
<project_group>AppImage</project_group>
|
||||||
|
<provides>
|
||||||
|
<binary>appimagetool</binary>
|
||||||
|
</provides>
|
||||||
|
</component>
|
||||||
@@ -140,7 +140,7 @@ func _init() -> void:
|
|||||||
# --- body-camera overlay (REC + shift clock + corner brackets, top right) ---
|
# --- body-camera overlay (REC + shift clock + corner brackets, top right) ---
|
||||||
var cam_box := VBoxContainer.new()
|
var cam_box := VBoxContainer.new()
|
||||||
cam_box.set_anchors_preset(Control.PRESET_TOP_RIGHT)
|
cam_box.set_anchors_preset(Control.PRESET_TOP_RIGHT)
|
||||||
cam_box.position = Vector2(-180, 12)
|
cam_box.position = Vector2(-180, 50)
|
||||||
cam_box.alignment = BoxContainer.ALIGNMENT_END
|
cam_box.alignment = BoxContainer.ALIGNMENT_END
|
||||||
add_child(cam_box)
|
add_child(cam_box)
|
||||||
var rec_row := HBoxContainer.new()
|
var rec_row := HBoxContainer.new()
|
||||||
@@ -180,9 +180,12 @@ func _init() -> void:
|
|||||||
icon_row.add_child(wand_icon)
|
icon_row.add_child(wand_icon)
|
||||||
|
|
||||||
# --- inspect panel (popup center) ---
|
# --- inspect panel (popup center) ---
|
||||||
|
var inspect_center := CenterContainer.new()
|
||||||
|
inspect_center.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||||
|
inspect_center.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
add_child(inspect_center)
|
||||||
inspect_panel = PanelContainer.new()
|
inspect_panel = PanelContainer.new()
|
||||||
inspect_panel.visible = false
|
inspect_panel.visible = false
|
||||||
inspect_panel.set_anchors_preset(Control.PRESET_CENTER)
|
|
||||||
inspect_panel.modulate.a = 1.0
|
inspect_panel.modulate.a = 1.0
|
||||||
var ivbox := VBoxContainer.new()
|
var ivbox := VBoxContainer.new()
|
||||||
inspect_panel.add_child(ivbox)
|
inspect_panel.add_child(ivbox)
|
||||||
@@ -197,12 +200,15 @@ func _init() -> void:
|
|||||||
insp_hint.text = "A = allow entry D = deny entry"
|
insp_hint.text = "A = allow entry D = deny entry"
|
||||||
insp_hint.add_theme_font_size_override("font_size", 12)
|
insp_hint.add_theme_font_size_override("font_size", 12)
|
||||||
ivbox.add_child(insp_hint)
|
ivbox.add_child(insp_hint)
|
||||||
add_child(inspect_panel)
|
inspect_center.add_child(inspect_panel)
|
||||||
|
|
||||||
# --- wand screening panel (popup center) ---
|
# --- wand screening panel (popup center) ---
|
||||||
|
var wand_center := CenterContainer.new()
|
||||||
|
wand_center.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||||
|
wand_center.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
add_child(wand_center)
|
||||||
wand_panel = PanelContainer.new()
|
wand_panel = PanelContainer.new()
|
||||||
wand_panel.visible = false
|
wand_panel.visible = false
|
||||||
wand_panel.set_anchors_preset(Control.PRESET_CENTER)
|
|
||||||
var wvbox := VBoxContainer.new()
|
var wvbox := VBoxContainer.new()
|
||||||
wand_panel.add_child(wvbox)
|
wand_panel.add_child(wvbox)
|
||||||
wand_text = Label.new()
|
wand_text = Label.new()
|
||||||
@@ -216,7 +222,7 @@ func _init() -> void:
|
|||||||
wand_hint.text = "A = admit D = refuse entry"
|
wand_hint.text = "A = admit D = refuse entry"
|
||||||
wand_hint.add_theme_font_size_override("font_size", 12)
|
wand_hint.add_theme_font_size_override("font_size", 12)
|
||||||
wvbox.add_child(wand_hint)
|
wvbox.add_child(wand_hint)
|
||||||
add_child(wand_panel)
|
wand_center.add_child(wand_panel)
|
||||||
|
|
||||||
# --- debug overlay ---
|
# --- debug overlay ---
|
||||||
debug_label = Label.new()
|
debug_label = Label.new()
|
||||||
@@ -374,6 +380,7 @@ func show_inspection(controller: Object, artifacts: Array, result: Dictionary) -
|
|||||||
continue
|
continue
|
||||||
var card := TextureRect.new()
|
var card := TextureRect.new()
|
||||||
card.texture = tex
|
card.texture = tex
|
||||||
|
card.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||||
card.custom_minimum_size = Vector2(92, 58)
|
card.custom_minimum_size = Vector2(92, 58)
|
||||||
card.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
card.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||||
card.tooltip_text = artifact.summary()
|
card.tooltip_text = artifact.summary()
|
||||||
@@ -382,7 +389,8 @@ func show_inspection(controller: Object, artifacts: Array, result: Dictionary) -
|
|||||||
card_row.add_child(card)
|
card_row.add_child(card)
|
||||||
added_card = true
|
added_card = true
|
||||||
if added_card:
|
if added_card:
|
||||||
inspect_panel.add_child(card_row)
|
var content := inspect_panel.get_child(0) as VBoxContainer
|
||||||
|
content.add_child(card_row)
|
||||||
var lines: Array[String] = []
|
var lines: Array[String] = []
|
||||||
for artifact in artifacts:
|
for artifact in artifacts:
|
||||||
lines.append(" • " + artifact.summary())
|
lines.append(" • " + artifact.summary())
|
||||||
@@ -403,7 +411,7 @@ func _clear_card_row() -> void:
|
|||||||
return
|
return
|
||||||
var row := inspect_panel.find_child("INSPECT_CARD_ROW", true, false) as Control
|
var row := inspect_panel.find_child("INSPECT_CARD_ROW", true, false) as Control
|
||||||
if row:
|
if row:
|
||||||
inspect_panel.remove_child(row)
|
row.get_parent().remove_child(row)
|
||||||
row.queue_free()
|
row.queue_free()
|
||||||
|
|
||||||
func show_wand(controller: Object, result: Dictionary) -> void:
|
func show_wand(controller: Object, result: Dictionary) -> void:
|
||||||
|
|||||||
@@ -34,9 +34,12 @@ func _init() -> void:
|
|||||||
dim.set_anchors_preset(Control.PRESET_FULL_RECT)
|
dim.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||||
add_child(dim)
|
add_child(dim)
|
||||||
|
|
||||||
|
var center := CenterContainer.new()
|
||||||
|
center.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||||
|
center.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
add_child(center)
|
||||||
panel = PanelContainer.new()
|
panel = PanelContainer.new()
|
||||||
panel.set_anchors_preset(Control.PRESET_CENTER)
|
center.add_child(panel)
|
||||||
add_child(panel)
|
|
||||||
|
|
||||||
var vbox := VBoxContainer.new()
|
var vbox := VBoxContainer.new()
|
||||||
panel.add_child(vbox)
|
panel.add_child(vbox)
|
||||||
|
|||||||
@@ -12,9 +12,10 @@ var gm: Node = null
|
|||||||
var state := 0
|
var state := 0
|
||||||
var state_frames := 0
|
var state_frames := 0
|
||||||
var targeted := false
|
var targeted := false
|
||||||
|
var camera_staged := false
|
||||||
|
|
||||||
func _initialize() -> void:
|
func _initialize() -> void:
|
||||||
root.size = Vector2i(1600, 900)
|
root.size = Vector2i(1280, 720)
|
||||||
var packed: PackedScene = load("res://scenes/main.tscn")
|
var packed: PackedScene = load("res://scenes/main.tscn")
|
||||||
var inst: Node = packed.instantiate()
|
var inst: Node = packed.instantiate()
|
||||||
root.add_child(inst)
|
root.add_child(inst)
|
||||||
@@ -29,6 +30,10 @@ func _process(_delta: float) -> bool:
|
|||||||
push_error("GameManager not found")
|
push_error("GameManager not found")
|
||||||
quit(1)
|
quit(1)
|
||||||
return true
|
return true
|
||||||
|
if gm != null and not camera_staged:
|
||||||
|
gm.guard.global_position = Vector3(0, 1.6, 5.0)
|
||||||
|
gm.guard.head.rotation.x = deg_to_rad(-8.0)
|
||||||
|
camera_staged = true
|
||||||
if frames > MAX_FRAMES:
|
if frames > MAX_FRAMES:
|
||||||
print("timeout reached")
|
print("timeout reached")
|
||||||
quit(0)
|
quit(0)
|
||||||
|
|||||||
@@ -306,12 +306,30 @@ def app_icon():
|
|||||||
icon("icon.png", badge, size=1024)
|
icon("icon.png", badge, size=1024)
|
||||||
icon("icon.ico", badge, size=256)
|
icon("icon.ico", badge, size=256)
|
||||||
|
|
||||||
# multi-size ICO for Windows (from the 256 render)
|
# ICO for Windows. Must be BMP-entry based: PIL's ICO serializer emits
|
||||||
src = Image.open(os.path.join(ASSETS, "icon.png"))
|
# PNG-compressed entries which NSIS' icon loader rejects. ImageMagick
|
||||||
|
# writes classic BMP entries; fall back to PIL only if ImageMagick is gone
|
||||||
|
# (flag it so a human notices).
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
ico_path = os.path.join(ASSETS, "icon.ico")
|
ico_path = os.path.join(ASSETS, "icon.ico")
|
||||||
src.save(ico_path, format="ICO", sizes=[
|
src_png = os.path.join(ASSETS, "icon.png")
|
||||||
(256, 256), (128, 128), (64, 64), (48, 48), (32, 32), (16, 16)])
|
ran = False
|
||||||
print("wrote assets/textures/icon.ico (multi-size)")
|
for cmd in (
|
||||||
|
["magick", src_png, "-background", "none", "-define", "icon:auto-resize=48,32,16", ico_path],
|
||||||
|
["convert", src_png, "-background", "none", "-define", "icon:auto-resize=48,32,16", ico_path],
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
subprocess.run(cmd, check=True, capture_output=True)
|
||||||
|
ran = True
|
||||||
|
break
|
||||||
|
except (FileNotFoundError, subprocess.CalledProcessError):
|
||||||
|
continue
|
||||||
|
if ran:
|
||||||
|
print("wrote assets/textures/icon.ico (BMP 16/32/48 via ImageMagick)")
|
||||||
|
else:
|
||||||
|
print("WARNING: ImageMagick not found; writing PIL ICO (may be PNG-compressed)")
|
||||||
|
Image.open(src_png).convert("RGBA").save(ico_path, format="ICO", sizes=[(48, 48), (32, 32), (16, 16)])
|
||||||
|
|
||||||
|
|
||||||
def cards():
|
def cards():
|
||||||
|
|||||||