153 lines
5.6 KiB
Go
153 lines
5.6 KiB
Go
package main
|
||
|
||
import "math/rand"
|
||
|
||
// WayfarerEncounterType — вид случайной встречи во время перелёта.
|
||
type WayfarerEncounterType int
|
||
|
||
const (
|
||
EncounterNone WayfarerEncounterType = iota
|
||
EncounterPirate
|
||
EncounterPoliceScan
|
||
EncounterDistress
|
||
EncounterDerelict
|
||
)
|
||
|
||
// wayfarerBaseEncounterChance — базовая вероятность хоть какой-то
|
||
// встречи за один прыжок при "нейтральном" (danger factor = 1)
|
||
// уровне опасности системы назначения.
|
||
const wayfarerBaseEncounterChance = 0.18
|
||
|
||
// RollEncounter решает, произойдёт ли что-то во время перелёта в
|
||
// систему dest, и если да — что именно.
|
||
func RollEncounter(dest WayfarerSystem, rnd *rand.Rand) WayfarerEncounterType {
|
||
chance := wayfarerBaseEncounterChance * dest.DangerFactor()
|
||
if chance > 0.9 {
|
||
chance = 0.9
|
||
}
|
||
if rnd.Float64() > chance {
|
||
return EncounterNone
|
||
}
|
||
roll := rnd.Float64()
|
||
switch {
|
||
case roll < 0.45:
|
||
return EncounterPirate
|
||
case roll < 0.65:
|
||
return EncounterPoliceScan
|
||
case roll < 0.85:
|
||
return EncounterDistress
|
||
default:
|
||
return EncounterDerelict
|
||
}
|
||
}
|
||
|
||
// GeneratePirateStats создаёт статы вражеского корабля,
|
||
// отмасштабированные под опасность системы dest — в более опасных
|
||
// (например, анархических) системах пираты в среднем крепче и злее.
|
||
func GeneratePirateStats(dest WayfarerSystem, rnd *rand.Rand) (hull, laser, shield int) {
|
||
baseHull := 15 + rnd.Intn(20)
|
||
baseLaser := 4 + rnd.Intn(6)
|
||
baseShield := rnd.Intn(20) // некоторые пираты вообще без щита — это нормально, не форсируем минимум
|
||
hull = int(float64(baseHull) * dest.DangerFactor())
|
||
laser = int(float64(baseLaser) * dest.DangerFactor())
|
||
shield = int(float64(baseShield) * dest.DangerFactor())
|
||
if hull < 5 {
|
||
hull = 5
|
||
}
|
||
if laser < 1 {
|
||
laser = 1
|
||
}
|
||
if shield < 0 {
|
||
shield = 0
|
||
}
|
||
return hull, laser, shield
|
||
}
|
||
|
||
// HasIllegalCargo проверяет, везёт ли корабль хоть что-то из
|
||
// незаконных товаров (WayfarerCommodities[i].Illegal).
|
||
func (s *WayfarerShip) HasIllegalCargo() bool {
|
||
for i, c := range WayfarerCommodities {
|
||
if c.Illegal && s.Cargo[i] > 0 {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// ConfiscateIllegalCargo изымает весь незаконный груз и возвращает
|
||
// его условную стоимость (для отображения игроку, что он потерял).
|
||
func (s *WayfarerShip) ConfiscateIllegalCargo() float64 {
|
||
lost := 0.0
|
||
for i, c := range WayfarerCommodities {
|
||
if c.Illegal && s.Cargo[i] > 0 {
|
||
lost += float64(s.Cargo[i]) * c.BasePrice
|
||
s.Cargo[i] = 0
|
||
}
|
||
}
|
||
return lost
|
||
}
|
||
|
||
// wayfarerDerelictMin/Max — диапазон случайной находки на обломках.
|
||
const (
|
||
wayfarerDerelictMin = 50.0
|
||
wayfarerDerelictMax = 250.0
|
||
)
|
||
|
||
// DerelictFind начисляет игроку случайную находку с обломков
|
||
// корабля и возвращает её размер.
|
||
func (s *WayfarerShip) DerelictFind(rnd *rand.Rand) float64 {
|
||
found := wayfarerDerelictMin + rnd.Float64()*(wayfarerDerelictMax-wayfarerDerelictMin)
|
||
s.Credits += found
|
||
return found
|
||
}
|
||
|
||
// wayfarerQuestOfferChance — с такой вероятностью прибытие в
|
||
// систему (если сейчас нет активного задания и остались
|
||
// невыполненные/непровальные квесты) заканчивается предложением
|
||
// одного из них — вместо свободного выбора квеста из списка когда
|
||
// угодно, как раньше.
|
||
const wayfarerQuestOfferChance = 0.25
|
||
|
||
// RollQuestOffer решает, предлагается ли игроку квест по прибытии в
|
||
// систему. Возвращает (ключ квеста, true), если да.
|
||
func RollQuestOffer(ship *WayfarerShip, rnd *rand.Rand) (string, bool) {
|
||
if ship.ActiveQuest != nil {
|
||
return "", false
|
||
}
|
||
var candidates []string
|
||
for _, q := range WayfarerQuestDefs {
|
||
if !ship.CompletedQuests[q.Key] && !ship.FailedQuests[q.Key] {
|
||
candidates = append(candidates, q.Key)
|
||
}
|
||
}
|
||
if len(candidates) == 0 {
|
||
return "", false
|
||
}
|
||
if rnd.Float64() > wayfarerQuestOfferChance {
|
||
return "", false
|
||
}
|
||
return candidates[rnd.Intn(len(candidates))], true
|
||
}
|
||
|
||
// wayfarerDistressTrapChance — с такой вероятностью сигнал бедствия
|
||
// на самом деле окажется засадой (тогда вызывающий код должен
|
||
// начать бой) вместо честной просьбы о помощи.
|
||
const wayfarerDistressTrapChance = 0.25
|
||
|
||
const (
|
||
wayfarerDistressRewardMin = 100.0
|
||
wayfarerDistressRewardMax = 400.0
|
||
)
|
||
|
||
// HelpDistressed разрешает решение "откликнуться на сигнал
|
||
// бедствия": либо это оказывается ловушка (wasTrap == true — бой
|
||
// должен запустить вызывающий код отдельно, начисление тут не
|
||
// происходит), либо честная награда за помощь.
|
||
func (s *WayfarerShip) HelpDistressed(rnd *rand.Rand) (reward float64, wasTrap bool) {
|
||
if rnd.Float64() < wayfarerDistressTrapChance {
|
||
return 0, true
|
||
}
|
||
reward = wayfarerDistressRewardMin + rnd.Float64()*(wayfarerDistressRewardMax-wayfarerDistressRewardMin)
|
||
s.Credits += reward
|
||
return reward, false
|
||
}
|