diff options
Diffstat (limited to 'internal/game/tech.go')
| -rw-r--r-- | internal/game/tech.go | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/internal/game/tech.go b/internal/game/tech.go new file mode 100644 index 0000000..a24c66d --- /dev/null +++ b/internal/game/tech.go @@ -0,0 +1,250 @@ +package game + +import ( + "fmt" + "strings" + + "thehouseoficarus/internal/net" + "thehouseoficarus/internal/player" + "thehouseoficarus/internal/world" +) + +type TechEffects struct { + AttackPercent int + StrengthPercent int + DefensePercent int + RangedPercent int + SciencePercent int + ProtectMelee bool + ProtectRanged bool + ProtectScience bool + DamageReduction float64 + HPRegenMulti float64 + PreserveDrain float64 + RetributionPct float64 +} + +type TechDef struct { + ID string + Name string + Level int + DrainRate float64 + Category string + Group string + Effects TechEffects +} + +var AllTechs []TechDef +var techByID map[string]*TechDef + +func init() { + AllTechs = []TechDef{ + {ID: "clarity_1", Name: "Clarity", Level: 4, DrainRate: 0.05, Category: "attack", Group: "attack_tier", Effects: TechEffects{AttackPercent: 5}}, + {ID: "clarity_2", Name: "Enhanced Clarity", Level: 16, DrainRate: 0.10, Category: "attack", Group: "attack_tier", Effects: TechEffects{AttackPercent: 10}}, + {ID: "clarity_3", Name: "Superior Clarity", Level: 44, DrainRate: 0.15, Category: "attack", Group: "attack_tier", Effects: TechEffects{AttackPercent: 15}}, + + {ID: "amplifier_1", Name: "Power Amplifier", Level: 7, DrainRate: 0.05, Category: "strength", Group: "strength_tier", Effects: TechEffects{StrengthPercent: 5}}, + {ID: "amplifier_2", Name: "Enhanced Amplifier", Level: 23, DrainRate: 0.10, Category: "strength", Group: "strength_tier", Effects: TechEffects{StrengthPercent: 10}}, + {ID: "amplifier_3", Name: "Superior Amplifier", Level: 49, DrainRate: 0.15, Category: "strength", Group: "strength_tier", Effects: TechEffects{StrengthPercent: 15}}, + + {ID: "shield_1", Name: "Energy Shield", Level: 10, DrainRate: 0.05, Category: "defense", Group: "defense_tier", Effects: TechEffects{DefensePercent: 5}}, + {ID: "shield_2", Name: "Enhanced Shield", Level: 28, DrainRate: 0.10, Category: "defense", Group: "defense_tier", Effects: TechEffects{DefensePercent: 10}}, + {ID: "shield_3", Name: "Superior Shield", Level: 52, DrainRate: 0.15, Category: "defense", Group: "defense_tier", Effects: TechEffects{DefensePercent: 15}}, + + {ID: "targeting_1", Name: "Targeting System", Level: 8, DrainRate: 0.05, Category: "ranged", Group: "ranged_tier", Effects: TechEffects{RangedPercent: 5}}, + {ID: "targeting_2", Name: "Enhanced Targeting", Level: 22, DrainRate: 0.10, Category: "ranged", Group: "ranged_tier", Effects: TechEffects{RangedPercent: 10}}, + {ID: "targeting_3", Name: "Superior Targeting", Level: 46, DrainRate: 0.15, Category: "ranged", Group: "ranged_tier", Effects: TechEffects{RangedPercent: 15}}, + + {ID: "focus_1", Name: "Neural Focus", Level: 9, DrainRate: 0.05, Category: "science", Group: "science_tier", Effects: TechEffects{SciencePercent: 5}}, + {ID: "focus_2", Name: "Enhanced Focus", Level: 27, DrainRate: 0.10, Category: "science", Group: "science_tier", Effects: TechEffects{SciencePercent: 10}}, + {ID: "focus_3", Name: "Superior Focus", Level: 55, DrainRate: 0.15, Category: "science", Group: "science_tier", Effects: TechEffects{SciencePercent: 15}}, + + {ID: "protect_melee", Name: "Kinetic Barrier", Level: 37, DrainRate: 0.20, Category: "protection", Group: "protection", Effects: TechEffects{ProtectMelee: true, DamageReduction: 0.4}}, + {ID: "protect_ranged", Name: "Projectile Screen", Level: 40, DrainRate: 0.20, Category: "protection", Group: "protection", Effects: TechEffects{ProtectRanged: true, DamageReduction: 0.4}}, + {ID: "protect_science", Name: "Neural Firewall", Level: 43, DrainRate: 0.20, Category: "protection", Group: "protection", Effects: TechEffects{ProtectScience: true, DamageReduction: 0.4}}, + + {ID: "regen", Name: "Nano Repair", Level: 22, DrainRate: 0.10, Category: "utility", Group: "regen_tier", Effects: TechEffects{HPRegenMulti: 2.0}}, + {ID: "rapid_heal", Name: "Rapid Repair", Level: 31, DrainRate: 0.15, Category: "utility", Group: "regen_tier", Effects: TechEffects{HPRegenMulti: 4.0}}, + {ID: "preserve", Name: "Power Saver", Level: 55, DrainRate: 0.05, Category: "utility", Group: "", Effects: TechEffects{PreserveDrain: 0.2}}, + {ID: "retribution", Name: "Dead Man's Switch", Level: 46, DrainRate: 0.10, Category: "utility", Group: "", Effects: TechEffects{RetributionPct: 0.25}}, + + {ID: "overclock", Name: "Overclock", Level: 60, DrainRate: 0.25, Category: "combo", Group: "attack_tier", Effects: TechEffects{AttackPercent: 15, StrengthPercent: 15}}, + {ID: "fortify", Name: "Fortify", Level: 65, DrainRate: 0.25, Category: "combo", Group: "defense_tier", Effects: TechEffects{DefensePercent: 15, HPRegenMulti: 2.0}}, + } + + techByID = make(map[string]*TechDef, len(AllTechs)) + for i := range AllTechs { + techByID[AllTechs[i].ID] = &AllTechs[i] + } +} + +func GetTechDef(id string) *TechDef { + return techByID[id] +} + +func TechByPrefixMatch(input string) []*TechDef { + input = strings.ToLower(input) + var exact []*TechDef + var prefix []*TechDef + for i := range AllTechs { + lower := strings.ToLower(AllTechs[i].Name) + lowerID := strings.ToLower(AllTechs[i].ID) + if lower == input || lowerID == input { + exact = append(exact, &AllTechs[i]) + } else if strings.HasPrefix(lower, input) || strings.HasPrefix(lowerID, input) { + prefix = append(prefix, &AllTechs[i]) + } + } + if len(exact) > 0 { + return exact + } + return prefix +} + +func techEffectString(tech TechDef) string { + var parts []string + e := tech.Effects + if e.AttackPercent > 0 { + parts = append(parts, fmt.Sprintf("+%d%% Attack", e.AttackPercent)) + } + if e.StrengthPercent > 0 { + parts = append(parts, fmt.Sprintf("+%d%% Strength", e.StrengthPercent)) + } + if e.DefensePercent > 0 { + parts = append(parts, fmt.Sprintf("+%d%% Defense", e.DefensePercent)) + } + if e.RangedPercent > 0 { + parts = append(parts, fmt.Sprintf("+%d%% Ranged", e.RangedPercent)) + } + if e.SciencePercent > 0 { + parts = append(parts, fmt.Sprintf("+%d%% Science", e.SciencePercent)) + } + if e.ProtectMelee { + parts = append(parts, fmt.Sprintf("%.0f%% melee protection", e.DamageReduction*100)) + } + if e.ProtectRanged { + parts = append(parts, fmt.Sprintf("%.0f%% ranged protection", e.DamageReduction*100)) + } + if e.ProtectScience { + parts = append(parts, fmt.Sprintf("%.0f%% science protection", e.DamageReduction*100)) + } + if e.HPRegenMulti > 0 { + parts = append(parts, fmt.Sprintf("%.0fx HP regen", e.HPRegenMulti)) + } + if e.PreserveDrain > 0 { + parts = append(parts, fmt.Sprintf("%.0f%% drain reduction", e.PreserveDrain*100)) + } + if e.RetributionPct > 0 { + parts = append(parts, fmt.Sprintf("%.0f%% retribution", e.RetributionPct*100)) + } + return strings.Join(parts, ", ") +} + +func (g *Game) totalTechBonus(p *player.Player) int { + total := 0 + for _, itemID := range p.Equipment { + def, err := g.ItemStore.Load(itemID) + if err == nil { + total += def.Stats.TechnologyBonus + } + } + return total +} + +func (g *Game) techLevelBonus(p *player.Player, stat string) int { + if len(p.ActiveTechs) == 0 { + return 0 + } + + totalPercent := 0 + for id := range p.ActiveTechs { + def := GetTechDef(id) + if def == nil { + continue + } + switch stat { + case "attack": + totalPercent += def.Effects.AttackPercent + case "strength": + totalPercent += def.Effects.StrengthPercent + case "defense": + totalPercent += def.Effects.DefensePercent + case "ranged": + totalPercent += def.Effects.RangedPercent + case "science": + totalPercent += def.Effects.SciencePercent + } + } + + if totalPercent == 0 { + return 0 + } + + var baseLevel int + switch stat { + case "attack": + baseLevel = p.Level(player.Attack) + case "strength": + baseLevel = p.Level(player.Strength) + case "defense": + baseLevel = p.Level(player.Defense) + case "ranged": + baseLevel = p.Level(player.Ranged) + case "science": + baseLevel = p.Level(player.Science) + } + + return baseLevel * totalPercent / 100 +} + +func (g *Game) tryRecharge(sess *net.Session, p *player.Player, input string) bool { + lower := strings.ToLower(strings.TrimSpace(input)) + instances := g.World.FindObjInstances(p.RoomID, lower) + for _, st := range instances { + if st.DefID == "charging_station" || st.DefID == "power_conduit" { + if p.Battery >= p.MaxBattery() { + sess.WriteLine("\nYour battery is already full.") + } else { + p.Battery = p.MaxBattery() + g.AccountStore.SaveCharacter(p) + sess.WriteLine(g.colorize(sess, "battery", + "\nYou connect to the charging station. Your battery is fully recharged.")) + } + return true + } + } + return false +} + +func (g *Game) applyTechProtection(p *player.Player, mob *world.MobInstance, dmg int) int { + if len(p.ActiveTechs) == 0 { + return dmg + } + + attackType := mob.AttackType + if attackType == "" { + attackType = "crush" + } + + var protectTechID string + switch attackType { + case "stab", "slash", "crush": + protectTechID = "protect_melee" + case "ranged": + protectTechID = "protect_ranged" + case "science": + protectTechID = "protect_science" + } + + if protectTechID != "" && p.HasActiveTech(protectTechID) { + def := GetTechDef(protectTechID) + if def != nil { + reduced := int(float64(dmg) * (1.0 - def.Effects.DamageReduction)) + if reduced < 0 { + reduced = 0 + } + return reduced + } + } + return dmg +} |
