1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
package game
import (
"fmt"
"strings"
"thehouseoficarus/internal/net"
"thehouseoficarus/internal/player"
)
type HackingMinigame interface {
Init(level int) string
HandleInput(input string) (output string, done bool, won bool)
Name() string
}
type XPBonuser interface {
BonusXP() int
}
type HackingSession struct {
Minigame HackingMinigame
TerminalID string
Level int
ReqLevel int
Started bool
}
type TerminalDef struct {
ObjectID string
Level int
Minigame func() HackingMinigame
BaseXPWin int
BaseXPLose int
Name string
}
var terminalDefs = map[string]TerminalDef{
"terminal_basic": {
ObjectID: "terminal_basic",
Level: 1,
Minigame: func() HackingMinigame { return NewWumpusGame() },
BaseXPWin: 50,
BaseXPLose: 10,
Name: "Hunt the Wumpus",
},
"terminal_advanced": {
ObjectID: "terminal_advanced",
Level: 20,
Minigame: func() HackingMinigame { return NewMastermindGame() },
BaseXPWin: 150,
BaseXPLose: 30,
Name: "Code Breaker",
},
"terminal_secure": {
ObjectID: "terminal_secure",
Level: 40,
Minigame: func() HackingMinigame { return NewLiarsDiceGame() },
BaseXPWin: 300,
BaseXPLose: 50,
Name: "Signal Bluff",
},
}
func (g *Game) handleHackingInput(sess *net.Session, input string) {
p, ok := sess.Player.(*player.Player)
if !ok {
sess.State = net.StateGame
return
}
hs, ok := g.hackingStates[p.Name]
if !ok {
sess.State = net.StateGame
g.writePrompt(sess)
return
}
input = strings.TrimSpace(input)
lower := strings.ToLower(input)
if lower == "jack out" || lower == "quit" || lower == "disconnect" {
g.endHacking(sess, p, false, false)
return
}
hs.Started = true
output, done, won := hs.Minigame.HandleInput(input)
sess.WriteLine(output)
if done {
g.endHacking(sess, p, true, won)
return
}
sess.Write("\nhack> ")
}
func (g *Game) endHacking(sess *net.Session, p *player.Player, completed bool, won bool) {
hs, ok := g.hackingStates[p.Name]
if !ok {
sess.State = net.StateGame
g.writePrompt(sess)
return
}
tDef := terminalDefs[hs.TerminalID]
var xp int
if completed && won {
xp = hackingXP(tDef.BaseXPWin, hs.Level, hs.ReqLevel)
sess.WriteLine(fmt.Sprintf("\nConnection terminated. Contract complete."))
} else if completed {
xp = hackingXP(tDef.BaseXPLose, hs.Level, hs.ReqLevel)
sess.WriteLine(fmt.Sprintf("\nConnection lost."))
} else if hs.Started {
xp = hackingXP(tDef.BaseXPLose, hs.Level, hs.ReqLevel)
sess.WriteLine("\nYou jack out of the terminal.")
} else {
sess.WriteLine("\nYou jack out of the terminal.")
}
if won {
if b, ok := hs.Minigame.(XPBonuser); ok {
bonus := b.BonusXP()
if bonus > 0 {
xp += hackingXP(bonus, hs.Level, hs.ReqLevel)
}
}
}
if xp > 0 {
if newLevel := p.AddSkillXP(player.Hacking, xp); newLevel > 0 {
sess.WriteLine(g.colorize(sess, "level_up",
fmt.Sprintf("*** You are now level %d hacking! ***", newLevel)))
}
if p.OptionBool("xp_drops") {
sess.WriteLine(g.colorize(sess, "xp",
fmt.Sprintf("(+%dxp %s)", xp, player.SkillAbbr[player.Hacking])))
}
g.AccountStore.SaveCharacter(p)
}
delete(g.hackingStates, p.Name)
p.ActionState = nil
sess.State = net.StateGame
g.writePrompt(sess)
}
func hackingXP(baseXP int, playerLevel int, reqLevel int) int {
multiplier := 1.0 + 0.01*float64(playerLevel-reqLevel)
if multiplier < 1.0 {
multiplier = 1.0
}
return int(float64(baseXP) * multiplier)
}
|