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
use std::{borrow::Borrow, time::Duration};
use chrono::{DateTime, Local};
use sf_api::{
command::{Command, ExpeditionSetting, TimeSkip},
gamestate::tavern::{AvailableTasks, ExpeditionStage},
session::SimpleSession,
};
use tokio::time::sleep;
#[tokio::main]
pub async fn main() {
let mut session = login_with_env().await;
loop {
let gs = session.game_state().unwrap();
let exp = &gs.tavern.expeditions;
let Some(active) = exp.active() else {
// We do not currently have an expedition running. Make sure we are
// idle
if !gs.tavern.is_idle() {
println!(
"Waiting/Collection other actions is not part of this \
example"
);
break;
}
let expeditions = match gs.tavern.available_tasks() {
AvailableTasks::Quests(_) => {
// We can only do quest, lets figure out why. Note that
// normally you could just do quests here
if !exp.is_event_ongoing() {
println!(
"Expeditions are currently not enabled, so we can \
not do anything"
);
break;
}
if gs.tavern.questing_preference
== ExpeditionSetting::PreferQuests
{
// This means we could do expeditions, but they are
// disabled in the settings
if !gs.tavern.can_change_questing_preference() {
println!(
"Expeditions are disabled in the settings and \
that setting can not be changed today"
);
break;
}
println!("Changing expedition setting");
session
.send_command(
Command::SetQuestsInsteadOfExpeditions {
value: ExpeditionSetting::PreferExpeditions,
},
)
.await
.unwrap();
continue;
}
println!("There seem to be no expeditions");
break;
}
AvailableTasks::Expeditions(expeditions) => expeditions,
};
// We would normally have to choose which expedition is the best.
// For now we just choose the first one though
let target = expeditions.first().unwrap();
// Make sure we have enough thirst for adventure to do the
// expeditions
if target.thirst_for_adventure_sec
> gs.tavern.thirst_for_adventure_sec
{
// Buying beer is an option, but not for this example
// Look at questing for that
println!("We do not have enough thirst for adventure left");
break;
}
// We should be all good to start the expedition
println!("Starting expedition");
session
.send_command(Command::ExpeditionStart { pos: 0 })
.await
.unwrap();
continue;
};
let current = active.current_stage();
let cmd = match current {
ExpeditionStage::Boss(_) => {
println!("Fighting the expedition boss");
Command::ExpeditionContinue
}
ExpeditionStage::Rewards(rewards) => {
if rewards.is_empty() {
panic!("No rewards to choose from");
}
println!("Picking reward");
// We should pick the best reward here
Command::ExpeditionPickReward { pos: 0 }
}
ExpeditionStage::Encounters(roads) => {
if roads.is_empty() {
panic!("No crossroads to choose from");
}
// We should pick the best crossroad here
println!("Choosing crossroad");
Command::ExpeditionPickEncounter { pos: 0 }
}
ExpeditionStage::Finished => {
// Between calling current_stage and now the expedition
// finished. next time we call active, it will be None
continue;
}
ExpeditionStage::Waiting(until) => {
let remaining = time_remaining(until);
if remaining.as_secs() > 60 && gs.tavern.quicksand_glasses > 0 {
println!("Skipping the {}s wait", remaining.as_secs());
Command::ExpeditionSkipWait {
typ: TimeSkip::Glass,
}
} else {
println!(
"Waiting {}s until next expedition step",
remaining.as_secs(),
);
sleep(remaining).await;
Command::Update
}
}
ExpeditionStage::Unknown => panic!("unknown expedition stage"),
};
sleep(Duration::from_secs(1)).await;
session.send_command(cmd).await.unwrap();
}
}
pub fn time_remaining<T: Borrow<DateTime<Local>>>(time: T) -> Duration {
(*time.borrow() - Local::now()).to_std().unwrap_or_default()
}
pub async fn login_with_env() -> SimpleSession {
let username = std::env::var("USERNAME").unwrap();
let password = std::env::var("PASSWORD").unwrap();
let server = std::env::var("SERVER").unwrap();
SimpleSession::login(&username, &password, &server)
.await
.unwrap()
}