add intro

This commit is contained in:
2026-08-28 22:02:58 +07:00
parent 5fcbf6f2c5
commit 1a05799b2d
17 changed files with 1103 additions and 364 deletions
@@ -104,6 +104,11 @@ func (a *scenarioArchive) Pack(
return nil, err
}
}
if story.Introduction != nil {
if err := addRef(story.Introduction.Audio); err != nil {
return nil, err
}
}
for _, place := range story.Places {
if err := addRef(place.Image); err != nil {
return nil, err
@@ -137,6 +142,9 @@ func (a *scenarioArchive) Pack(
application.Image = rewriteRef(application.Image, archivePathOf)
}
}
if story.Introduction != nil {
story.Introduction.Audio = rewriteRef(story.Introduction.Audio, archivePathOf)
}
doc := ScenarioJSON{
Version: Version,
@@ -101,6 +101,48 @@ func TestPackUnpackRoundTrip(t *testing.T) {
}
}
func TestPackUnpackIntroAudioRoundTrip(t *testing.T) {
description := "desc"
image := "cover.png"
scenario := &repos.Scenario{
ID: 1,
Name: "С введением",
Description: &description,
Image: &image,
Scenario: `{"introduction":{"text":"Введение","audio":"intro.mp3"},"places":[
{"code":"club","name":"Клуб","text":"Тёмный зал","image":"club.png"}
]}`,
}
files := memoryFiles{
"cover.png": []byte("cover-bytes"),
"club.png": []byte("club-bytes"),
"intro.mp3": []byte("intro-audio-bytes"),
}
data, err := testArchive.Pack(context.Background(), scenario, testDomain, files.get)
if err != nil {
t.Fatalf("Pack: %v", err)
}
bundle, err := testArchive.Unpack(data)
if err != nil {
t.Fatalf("Unpack: %v", err)
}
if bundle.Scenario.Story.Introduction == nil {
t.Fatal("Story.Introduction = nil, want введение")
}
if bundle.Scenario.Story.Introduction.Text != "Введение" {
t.Errorf("Introduction.Text = %q, want %q", bundle.Scenario.Story.Introduction.Text, "Введение")
}
if bundle.Scenario.Story.Introduction.Audio != "images/intro.mp3" {
t.Errorf("Introduction.Audio = %q, want %q", bundle.Scenario.Story.Introduction.Audio, "images/intro.mp3")
}
if _, ok := bundle.Files["images/intro.mp3"]; !ok {
t.Errorf("в архиве нет аудиофайла %q", "images/intro.mp3")
}
}
func TestPackExternalURLsKeptAndNotFetched(t *testing.T) {
description := "desc"
scenario := &repos.Scenario{
+14 -1
View File
@@ -4,13 +4,26 @@ type IStory interface {
GetStory(scenario *Story, codes []string) *Story
}
// История - это набор точек
// История - это введение и набор точек
type Story struct {
// Введение - то, что игрок получает в начале игры
Introduction *Introduction `json:"introduction,omitempty"`
// Список точек
Places []*Place `json:"places"`
}
// Введение - текст и аудио, которые игрок получает в начале игры
type Introduction struct {
// Текст введения
Text string `json:"text"`
// Аудио введения
Audio string `json:"audio,omitempty"`
}
// Точка - что-то куда можно сходить
// Это может быть место - аптека, остановка, площадь...
// Это может быть персонаж - пострадавший, продавец, полицейский...
+8
View File
@@ -21,6 +21,14 @@ func (s *story) GetStory(
codesWithUseActions := map[string]struct{}{}
codesHidden := map[string]struct{}{}
givenApplications := map[string]struct{}{}
// Введение передаётся игроку всегда — и до первого хода (начало игры),
// и в дальнейшем (как заголовок истории).
if scenario.Introduction != nil {
story.Introduction = &Introduction{
Text: s.cleaner.ClearText(scenario.Introduction.Text),
Audio: scenario.Introduction.Audio,
}
}
for i, code := range codes {
var prevPlace *Place
if i > 0 {
@@ -28,6 +28,52 @@ func Test_story_GetStory(t *testing.T) {
},
},
},
{
name: "Введение передаётся в начале игры (без действий)",
scenario: &Story{
Introduction: &Introduction{
Text: "Текст введения.([Ы])",
Audio: "intro.mp3",
},
},
codes: []string{},
want: &Story{
Introduction: &Introduction{
Text: "Текст введения.",
Audio: "intro.mp3",
},
},
},
{
name: "Введение передаётся вместе с точками",
scenario: &Story{
Introduction: &Introduction{
Text: "Текст введения.",
Audio: "intro.mp3",
},
Places: []*Place{
{
Code: "Ы",
Name: "Название точки",
Text: "Текст точки.",
},
},
},
codes: []string{"Ы"},
want: &Story{
Introduction: &Introduction{
Text: "Текст введения.",
Audio: "intro.mp3",
},
Places: []*Place{
{
Code: "Ы",
Name: "Название точки",
Text: "Текст точки.",
},
},
},
},
{
name: "Получение точки",
scenario: &Story{