diff options
Diffstat (limited to 'internal/game/sys_assassin.go')
| -rw-r--r-- | internal/game/sys_assassin.go | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/internal/game/sys_assassin.go b/internal/game/sys_assassin.go new file mode 100644 index 0000000..1927399 --- /dev/null +++ b/internal/game/sys_assassin.go @@ -0,0 +1,174 @@ +package game + +import ( + "fmt" + "math/rand" + + "thehouseoficarus/internal/net" + "thehouseoficarus/internal/player" + "thehouseoficarus/internal/world" +) + +type assassinTaskEntry struct { + MobID string + MinLevel int + MaxLevel int + MinCount int + MaxCount int + Weight int +} + +var assassinTaskTable = []assassinTaskEntry{ + {"man", 1, 15, 10, 25, 8}, + {"cow", 1, 15, 10, 25, 8}, + {"slug", 1, 99, 15, 45, 15}, + {"drone", 15, 99, 20, 50, 12}, + {"crawler", 30, 99, 15, 40, 10}, + {"phantom", 45, 99, 10, 30, 8}, +} + +func (g *Game) assignAssassinTask(sess *net.Session, p *player.Player) { + level := p.Level(player.Assassin) + var eligible []assassinTaskEntry + totalWeight := 0 + for _, entry := range assassinTaskTable { + if level >= entry.MinLevel && level <= entry.MaxLevel { + eligible = append(eligible, entry) + totalWeight += entry.Weight + } + } + if len(eligible) == 0 { + sess.WriteLine("The Client shakes their head. \"Nothing available for your level.\"") + return + } + roll := rand.Intn(totalWeight) + var chosen assassinTaskEntry + for _, entry := range eligible { + roll -= entry.Weight + if roll < 0 { + chosen = entry + break + } + } + count := chosen.MinCount + rand.Intn(chosen.MaxCount-chosen.MinCount+1) + setPlayerFlag(p, "assassin_task_mob", chosen.MobID) + setPlayerFlag(p, "assassin_task_total", count) + setPlayerFlag(p, "assassin_task_remaining", count) + g.AccountStore.SaveCharacter(p) + + def, err := g.MobStore.LoadDef(chosen.MobID) + name := chosen.MobID + if err == nil { + name = def.Name + } + sess.WriteLine(g.colorize(sess, "assassin_task", fmt.Sprintf("\"Your target: %d %ss. Get to work.\"", count, name))) +} + +func (g *Game) onAssassinKill(sess *net.Session, p *player.Player, mob *world.MobInstance) { + taskMob := getPlayerFlagString(p, "assassin_task_mob") + if taskMob == "" || taskMob != mob.DefID { + return + } + remaining := getPlayerFlagInt(p, "assassin_task_remaining") + if remaining <= 0 { + return + } + xp := mob.MaxHP * 2 + g.awardSkillXP(sess, p, player.Assassin, xp) + if p.OptionBool("xp_drops") { + sess.WriteLine(g.colorize(sess, "xp", fmt.Sprintf(" (+%dxp asm)", xp))) + } + remaining-- + setPlayerFlag(p, "assassin_task_remaining", remaining) + if remaining <= 0 { + completed := getPlayerFlagInt(p, "assassin_tasks_completed") + 1 + streak := getPlayerFlagInt(p, "assassin_streak") + 1 + setPlayerFlag(p, "assassin_tasks_completed", completed) + setPlayerFlag(p, "assassin_streak", streak) + delete(p.Flags, "assassin_task_mob") + setPlayerFlag(p, "assassin_task_remaining", 0) + setPlayerFlag(p, "assassin_task_total", 0) + rep := 1 + bonus := streakBonus(streak) + rep += bonus + currentRep := getPlayerFlagInt(p, "assassin_reputation") + setPlayerFlag(p, "assassin_reputation", currentRep+rep) + sess.WriteLine(g.colorize(sess, "assassin_task", fmt.Sprintf("\n*** Assassin task complete! ***"))) + if bonus > 0 { + sess.WriteLine(g.colorize(sess, "assassin_task", fmt.Sprintf(" Streak bonus! %d tasks in a row. +%d bonus reputation.", streak, bonus))) + } + sess.WriteLine(g.colorize(sess, "assassin_task", fmt.Sprintf(" Reputation earned: %d (total: %d)", rep, currentRep+rep))) + } else { + total := getPlayerFlagInt(p, "assassin_task_total") + def, _ := g.MobStore.LoadDef(taskMob) + name := taskMob + if def != nil { + name = def.Name + } + sess.WriteLine(g.colorize(sess, "assassin_task", fmt.Sprintf(" Assassin task: %d of %d %ss remaining.", remaining, total, name))) + } + g.AccountStore.SaveCharacter(p) +} + +func (g *Game) skipAssassinTask(sess *net.Session, p *player.Player) { + rep := getPlayerFlagInt(p, "assassin_reputation") + if rep < 30 { + sess.WriteLine("You don't have enough Reputation to skip. (Need 30, have " + fmt.Sprint(rep) + ")") + return + } + setPlayerFlag(p, "assassin_reputation", rep-30) + delete(p.Flags, "assassin_task_mob") + setPlayerFlag(p, "assassin_task_remaining", 0) + setPlayerFlag(p, "assassin_task_total", 0) + setPlayerFlag(p, "assassin_streak", 0) + g.AccountStore.SaveCharacter(p) +} + +func (g *Game) extendAssassinTask(sess *net.Session, p *player.Player) { + rep := getPlayerFlagInt(p, "assassin_reputation") + if rep < 30 { + sess.WriteLine("You don't have enough Reputation to extend. (Need 30, have " + fmt.Sprint(rep) + ")") + return + } + taskMob := getPlayerFlagString(p, "assassin_task_mob") + if taskMob == "" { + sess.WriteLine("You don't have an active task to extend.") + return + } + setPlayerFlag(p, "assassin_reputation", rep-30) + total := getPlayerFlagInt(p, "assassin_task_total") + remaining := getPlayerFlagInt(p, "assassin_task_remaining") + extension := total / 2 + if extension < 5 { + extension = 5 + } + setPlayerFlag(p, "assassin_task_total", total+extension) + setPlayerFlag(p, "assassin_task_remaining", remaining+extension) + g.AccountStore.SaveCharacter(p) + + def, _ := g.MobStore.LoadDef(taskMob) + name := taskMob + if def != nil { + name = def.Name + } + sess.WriteLine(fmt.Sprintf("Task extended by %d. Kill %d more %ss (%d total).", extension, remaining+extension, name, total+extension)) +} + +func streakBonus(streak int) int { + if streak%1000 == 0 { + return 50 + } + if streak%250 == 0 { + return 35 + } + if streak%100 == 0 { + return 25 + } + if streak%50 == 0 { + return 15 + } + if streak%10 == 0 { + return 5 + } + return 0 +} |
