1mod function_call_writer;
2
3use self::function_call_writer::FunctionCallWriter;
4use self::function_call_writer::Ident;
5use super::Command;
6use super::ConditionalBranchCommand;
7use super::Config;
8use super::ControlVariablesValue;
9use super::ControlVariablesValueGameData;
10use super::GetLocationInfoKind;
11use super::MaybeRef;
12use anyhow::ensure;
13use std::io::Write;
14
15pub fn commands2py<W>(
16 config: &Config,
17 commands: &[(u16, Command)],
18 mut writer: W,
19) -> anyhow::Result<()>
20where
21 W: Write,
22{
23 for (indent, command) in commands.iter() {
24 command2py(config, *indent, command, &mut writer)?;
25 }
26
27 Ok(())
28}
29
30fn command2py<W>(
31 config: &Config,
32 indent: u16,
33 command: &Command,
34 mut writer: W,
35) -> anyhow::Result<()>
36where
37 W: Write,
38{
39 match command {
40 Command::Nop => {}
41 Command::ShowText {
42 face_name,
43 face_index,
44 background,
45 position_type,
46 lines,
47 } => {
48 let mut writer = FunctionCallWriter::new(&mut writer, indent, "show_text")?;
49 writer.write_param("face_name", face_name)?;
50 writer.write_param("face_index", face_index)?;
51 writer.write_param("background", background)?;
52 writer.write_param("position_type", position_type)?;
53 writer.write_param("lines", lines)?;
54 writer.finish()?;
55 }
56 Command::ShowChoices {
57 choices,
58 cancel_type,
59 default_type,
60 position_type,
61 background,
62 } => {
63 let mut writer = FunctionCallWriter::new(&mut writer, indent, "show_choices")?;
64 writer.write_param("choices", choices)?;
65 writer.write_param("cancel_type", cancel_type)?;
66 writer.write_param("default_type", default_type)?;
67 writer.write_param("position_type", position_type)?;
68 writer.write_param("background", background)?;
69 writer.finish()?;
70 }
71 Command::ShowScrollingText {
72 speed,
73 no_fast,
74 lines,
75 } => {
76 let no_fast = stringify_bool(*no_fast);
77
78 write_indent(&mut writer, indent)?;
79 writeln!(&mut writer, "show_scrolling_text(")?;
80
81 write_indent(&mut writer, indent + 1)?;
82 writeln!(&mut writer, "speed={speed},")?;
83
84 write_indent(&mut writer, indent + 1)?;
85 writeln!(&mut writer, "no_fast={no_fast},")?;
86
87 write_indent(&mut writer, indent + 1)?;
88 writeln!(&mut writer, "lines=[")?;
89
90 for line in lines {
91 let line = escape_string(line);
92
93 write_indent(&mut writer, indent + 2)?;
94 writeln!(&mut writer, "'{line}',")?;
95 }
96
97 write_indent(&mut writer, indent + 1)?;
98 writeln!(&mut writer, "],")?;
99
100 write_indent(&mut writer, indent)?;
101 writeln!(&mut writer, ")")?;
102 }
103 Command::Comment { lines } => {
104 for line in lines.iter() {
105 write_indent(&mut writer, indent)?;
106 writeln!(&mut writer, "# {line}")?;
107 }
108 }
109 Command::ConditionalBranch(command) => {
110 write_indent(&mut writer, indent)?;
111 write!(&mut writer, "if ")?;
112 match command {
113 ConditionalBranchCommand::Switch { id, check_true } => {
114 let name = config.get_switch_name(*id);
115 let check_true_str = if *check_true { "" } else { "not " };
116 writeln!(&mut writer, "{check_true_str}{name}:")?;
117 }
118 ConditionalBranchCommand::Variable {
119 lhs_id,
120 rhs_id,
121 operation,
122 } => {
123 let lhs = config.get_variable_name(*lhs_id);
124 let rhs = match rhs_id {
125 MaybeRef::Constant(value) => value.to_string(),
126 MaybeRef::Ref(id) => config.get_variable_name(*id),
127 };
128 let operation = operation.as_str();
129
130 writeln!(&mut writer, "{lhs} {operation} {rhs}:")?;
131 }
132 ConditionalBranchCommand::SelfSwitch { name, check_true } => {
133 let name = escape_string(name);
134 let check_true_str = if *check_true { "" } else { "not " };
135 writeln!(
136 &mut writer,
137 "{check_true_str}game_self_switches.get(map_id=self.map_id, event_id=self.event_id, name='{name}'):"
138 )?;
139 }
140 ConditionalBranchCommand::ActorInParty { actor_id } => {
141 let actor_name = config.get_actor_name(*actor_id);
142
143 writeln!(
144 &mut writer,
145 "game_party.members.contains(actor={actor_name}):"
146 )?;
147 }
148 ConditionalBranchCommand::Timer { value, is_gte } => {
149 let cmp = if *is_gte { ">=" } else { "<=" };
150
151 writeln!(&mut writer, "game_timer.seconds() {cmp} {value}:")?;
152 }
153 ConditionalBranchCommand::ActorSkill { actor_id, skill_id } => {
154 let actor_name = config.get_actor_name(*actor_id);
155 let skill_name = config.get_skill_name(*skill_id);
156
157 writeln!(&mut writer, "{actor_name}.has_skill(skill={skill_name}):")?;
158 }
159 ConditionalBranchCommand::ActorArmor { actor_id, armor_id } => {
160 let actor_name = config.get_actor_name(*actor_id);
161 let armor_name = config.get_armor_name(*armor_id);
162
163 writeln!(&mut writer, "{actor_name}.has_armor(armor={armor_name}):")?;
164 }
165 ConditionalBranchCommand::ActorState { actor_id, state_id } => {
166 let actor_name = config.get_actor_name(*actor_id);
167 let state_name = config.get_state_name(*state_id);
168
169 writeln!(&mut writer, "{actor_name}.has_state(state={state_name}):")?;
170 }
171 ConditionalBranchCommand::EnemyState {
172 enemy_index,
173 state_id,
174 } => {
175 let name = config.get_state_name(*state_id);
176
177 writeln!(
178 &mut writer,
179 "game_troop.members[{enemy_index}].is_state_affected(state={name}):"
180 )?;
181 }
182 ConditionalBranchCommand::Character {
183 character_id,
184 direction,
185 } => {
186 let name = if *character_id < 0 {
187 "game_player".to_string()
188 } else {
189 format!("game_character_{character_id}")
190 };
191
192 writeln!(&mut writer, "{name}.direction == {direction}:")?;
193 }
194 ConditionalBranchCommand::Gold { value, check } => {
195 let check = check.as_str();
196
197 writeln!(&mut writer, "game_party.gold {check} {value}:")?;
198 }
199 ConditionalBranchCommand::Item { item_id } => {
200 let name = config.get_item_name(*item_id);
201
202 writeln!(&mut writer, "game_party.has_item(item={name}):")?;
203 }
204 ConditionalBranchCommand::Button { key_name } => {
205 let key_name = escape_string(key_name);
206
207 writeln!(&mut writer, "game_input.is_pressed(key_name='{key_name}'):")?;
208 }
209 ConditionalBranchCommand::Script { value } => {
210 let value = escape_string(value);
211
212 writeln!(&mut writer, "execute_script('{value}'):")?;
213 }
214 }
215 }
216 Command::Loop => {
217 write_indent(&mut writer, indent)?;
218 writeln!(&mut writer, "while True:")?;
219 }
220 Command::ExitEventProcessing => {
221 write_indent(&mut writer, indent)?;
222 writeln!(&mut writer, "exit_event_processing()")?;
223 }
224 Command::CommonEvent { id } => {
225 let name = config.get_common_event_name(*id);
226 FunctionCallWriter::new(&mut writer, indent, &name)?.finish()?;
227 }
228 Command::Label { name } => {
229 let mut writer = FunctionCallWriter::new(&mut writer, indent, "set_label")?;
230 writer.set_multiline(false);
231 writer.write_param("name", name)?;
232 writer.finish()?;
233 }
234 Command::JumpToLabel { name } => {
235 let mut writer = FunctionCallWriter::new(&mut writer, indent, "jump_to_label")?;
236 writer.set_multiline(false);
237 writer.write_param("name", name)?;
238 writer.finish()?;
239 }
240 Command::ControlSwitches {
241 start_id,
242 end_id,
243 value,
244 } => {
245 for id in *start_id..(*end_id + 1) {
246 let name = config.get_switch_name(id);
247 let value = stringify_bool(*value);
248
249 write_indent(&mut writer, indent)?;
250 writeln!(&mut writer, "{name} = {value}")?;
251 }
252 }
253 Command::ControlVariables {
254 start_variable_id,
255 end_variable_id,
256 operation,
257 value,
258 } => {
259 let operation = operation.as_str();
260 let value = match value {
261 ControlVariablesValue::Constant { value } => value.to_string(),
262 ControlVariablesValue::Variable { id } => config.get_variable_name(*id),
263 ControlVariablesValue::Random { start, stop } => {
264 format!("random.randrange(start={start}, stop={stop})")
265 }
266 ControlVariablesValue::GameData(game_data) => match game_data {
267 ControlVariablesValueGameData::NumItems { item_id } => {
268 let name = config.get_item_name(*item_id);
269
270 format!("game_party.get_num_items(item={name})")
271 }
272 ControlVariablesValueGameData::ActorLevel { actor_id } => {
273 let name = config.get_actor_name(*actor_id);
274 format!("{name}.level")
275 }
276 ControlVariablesValueGameData::ActorHp { actor_id } => {
277 let name = config.get_actor_name(*actor_id);
278 format!("{name}.hp")
279 }
280 ControlVariablesValueGameData::ActorMp { actor_id } => {
281 let name = config.get_actor_name(*actor_id);
282 format!("{name}.mp")
283 }
284 ControlVariablesValueGameData::ActorParam {
285 actor_id,
286 param_index,
287 } => {
288 let name = config.get_actor_name(*actor_id);
289 format!("{name}.param({param_index})")
290 }
291 ControlVariablesValueGameData::EnemyParam {
292 enemy_index,
293 param_index,
294 } => {
295 format!("game_troop.members[{enemy_index}].param({param_index})")
296 }
297 ControlVariablesValueGameData::CharacterMapX { character_id } => {
298 format!("game.get_character(id={character_id}).map_x")
299 }
300 ControlVariablesValueGameData::CharacterMapY { character_id } => {
301 format!("game.get_character(id={character_id}).map_y")
302 }
303 ControlVariablesValueGameData::CharacterScreenX { character_id } => {
304 format!("game.get_character(id={character_id}).screen_x")
305 }
306 ControlVariablesValueGameData::CharacterScreenY { character_id } => {
307 format!("game.get_character(id={character_id}).screen_y")
308 }
309 ControlVariablesValueGameData::MapId => "game_map.map_id()".to_string(),
310 ControlVariablesValueGameData::Gold => "game_party.gold".to_string(),
311 ControlVariablesValueGameData::Steps => "game_party.steps".to_string(),
312 },
313 ControlVariablesValue::Script { value } => {
314 let value = escape_string(value);
315 format!("execute_script('{value}')")
316 }
317 };
318 for variable_id in *start_variable_id..(*end_variable_id + 1) {
319 let name = config.get_variable_name(variable_id);
320
321 write_indent(&mut writer, indent)?;
322 writeln!(&mut writer, "{name} {operation} {value}")?;
323 }
324 }
325 Command::ControlSelfSwitch { key, value } => {
326 let value = stringify_bool(*value);
327
328 write_indent(&mut writer, indent)?;
329 writeln!(&mut writer, "game_self_switches['{key}'] = {value}")?;
330 }
331 Command::ControlTimer { start_seconds } => {
332 write_indent(&mut writer, indent)?;
333 match start_seconds {
334 Some(start_seconds) => {
335 writeln!(&mut writer, "game_timer.start(seconds={start_seconds})")?
336 }
337 None => writeln!(&mut writer, "game_timer.stop()")?,
338 }
339 }
340 Command::ChangeGold { is_add, value } => {
341 let op = if *is_add { "+=" } else { "-=" };
342 let value = match value {
343 MaybeRef::Constant(value) => value.to_string(),
344 MaybeRef::Ref(id) => config.get_variable_name(*id),
345 };
346
347 write_indent(&mut writer, indent)?;
348 writeln!(&mut writer, "game_party.gold {op} {value}")?;
349 }
350 Command::ChangeItems {
351 item_id,
352 is_add,
353 value,
354 } => {
355 let item = config.get_item_name(*item_id);
356 let sign = if *is_add { "" } else { "-" };
357 let value = match value {
358 MaybeRef::Constant(value) => value.to_string(),
359 MaybeRef::Ref(id) => config.get_variable_name(*id),
360 };
361 let value = format!("{sign}{value}");
362
363 let mut writer = FunctionCallWriter::new(&mut writer, indent, "gain_item")?;
364 writer.set_multiline(false);
365 writer.write_param("item", &Ident(&item))?;
366 writer.write_param("value", &Ident(&value))?;
367 writer.finish()?;
368 }
369 Command::ChangeArmors {
370 armor_id,
371 is_add,
372 value,
373 include_equipped,
374 } => {
375 let armor = config.get_armor_name(*armor_id);
376 let sign = if *is_add { "" } else { "-" };
377 let value = match value {
378 MaybeRef::Constant(value) => value.to_string(),
379 MaybeRef::Ref(id) => config.get_variable_name(*id),
380 };
381 let value = format!("{sign}{value}");
382
383 let mut writer = FunctionCallWriter::new(&mut writer, indent, "gain_armor")?;
384 writer.set_multiline(false);
385 writer.write_param("armor", &Ident(&armor))?;
386 writer.write_param("value", &Ident(&value))?;
387 writer.write_param("include_equipped", include_equipped)?;
388 writer.finish()?;
389 }
390 Command::ChangePartyMember {
391 actor_id,
392 is_add,
393 initialize,
394 } => {
395 let actor_name = config.get_actor_name(*actor_id);
396 let fn_name = if *is_add {
397 "add_party_member"
398 } else {
399 "remove_party_member"
400 };
401
402 let mut writer = FunctionCallWriter::new(&mut writer, indent, fn_name)?;
403 writer.set_multiline(false);
404 writer.write_param("actor", &Ident(&actor_name))?;
405 if *is_add {
407 writer.write_param("initialize", initialize)?;
408 }
409 writer.finish()?;
410 }
411 Command::ChangeSaveAccess { disable } => {
412 let fn_name = if *disable {
413 "disable_saving"
414 } else {
415 "enable_saving"
416 };
417
418 let mut writer = FunctionCallWriter::new(&mut writer, indent, fn_name)?;
419 writer.finish()?;
420 }
421 Command::SetEventLocation {
422 character_id,
423 x,
424 y,
425 direction,
426 } => {
427 let mut writer = FunctionCallWriter::new(&mut writer, indent, "set_event_location")?;
428 writer.write_param("character_id", character_id)?;
429 match x {
430 MaybeRef::Constant(x) => {
431 writer.write_param("x", x)?;
432 }
433 MaybeRef::Ref(x) => {
434 let x = config.get_variable_name(*x);
435 writer.write_param("x", &Ident(&x))?;
436 }
437 }
438 match y {
439 MaybeRef::Constant(y) => {
440 writer.write_param("y", y)?;
441 }
442 MaybeRef::Ref(y) => {
443 let y = config.get_variable_name(*y);
444 writer.write_param("y", &Ident(&y))?;
445 }
446 }
447 if let Some(direction) = direction {
448 writer.write_param("direction", direction)?;
449 }
450 writer.finish()?;
451 }
452 Command::TransferPlayer {
453 map_id,
454 x,
455 y,
456 direction,
457 fade_type,
458 } => {
459 let mut writer = FunctionCallWriter::new(&mut writer, indent, "transfer_player")?;
460 match map_id {
461 MaybeRef::Constant(id) => {
462 let name = format!("game_map_{id}");
463 writer.write_param("map", &Ident(&name))?;
464 }
465 MaybeRef::Ref(id) => {
466 let name = config.get_variable_name(*id);
467 writer.write_param("map_id", &Ident(&name))?;
468 }
469 }
470
471 match x {
472 MaybeRef::Constant(value) => {
473 writer.write_param("x", value)?;
474 }
475 MaybeRef::Ref(id) => {
476 let name = config.get_variable_name(*id);
477 writer.write_param("x", &Ident(&name))?;
478 }
479 }
480
481 match y {
482 MaybeRef::Constant(value) => {
483 writer.write_param("y", value)?;
484 }
485 MaybeRef::Ref(id) => {
486 let name = config.get_variable_name(*id);
487 writer.write_param("y", &Ident(&name))?;
488 }
489 }
490
491 writer.write_param("direction", direction)?;
492 writer.write_param("fade_type", fade_type)?;
493
494 writer.finish()?;
495 }
496 Command::SetMovementRoute {
497 character_id,
498 route,
499 } => {
500 let mut writer = FunctionCallWriter::new(&mut writer, indent, "set_movement_route")?;
501 writer.write_param("character_id", character_id)?;
502 writer.write_param("route", route)?;
503 writer.finish()?;
504 }
505 Command::ChangeTransparency { set_transparent } => {
506 let set_transparent = stringify_bool(*set_transparent);
507
508 write_indent(&mut writer, indent)?;
509 writeln!(
510 &mut writer,
511 "change_transparency(set_transparent={set_transparent})"
512 )?
513 }
514 Command::ShowAnimation {
515 character_id,
516 animation_id,
517 wait,
518 } => {
519 let mut writer = FunctionCallWriter::new(&mut writer, indent, "show_animation")?;
520 writer.set_multiline(false);
521 writer.write_param("character_id", character_id)?;
522 writer.write_param("animation_id", animation_id)?;
523 writer.write_param("wait", wait)?;
524 writer.finish()?;
525 }
526 Command::ShowBalloonIcon {
527 character_id,
528 balloon_id,
529 wait,
530 } => {
531 let mut writer = FunctionCallWriter::new(&mut writer, indent, "show_balloon_icon")?;
532 writer.set_multiline(false);
533 writer.write_param("character_id", character_id)?;
534 writer.write_param("balloon_id", balloon_id)?;
535 writer.write_param("wait", wait)?;
536 writer.finish()?;
537 }
538 Command::ChangePlayerFollowers { is_show } => {
539 let fn_name = if *is_show {
540 "show_player_followers"
541 } else {
542 "hide_player_followers"
543 };
544
545 write_indent(&mut writer, indent)?;
546 writeln!(&mut writer, "{fn_name}()")?
547 }
548 Command::FadeoutScreen => {
549 FunctionCallWriter::new(&mut writer, indent, "fadeout_screen")?.finish()?;
550 }
551 Command::FadeinScreen => {
552 FunctionCallWriter::new(&mut writer, indent, "fadein_screen")?.finish()?;
553 }
554 Command::TintScreen {
555 tone,
556 duration,
557 wait,
558 } => {
559 let wait = stringify_bool(*wait);
560
561 write_indent(&mut writer, indent)?;
562 writeln!(
563 &mut writer,
564 "tint_screen(tone={tone:?}, duration={duration}, wait={wait})"
565 )?
566 }
567 Command::FlashScreen {
568 color,
569 duration,
570 wait,
571 } => {
572 let wait = stringify_bool(*wait);
573
574 write_indent(&mut writer, indent)?;
575 writeln!(
576 &mut writer,
577 "flash_screen(color={color:?}, duration={duration}, wait={wait})"
578 )?
579 }
580 Command::ShakeScreen {
581 power,
582 speed,
583 duration,
584 wait,
585 } => {
586 let mut writer = FunctionCallWriter::new(&mut writer, indent, "shake_screen")?;
587 writer.set_multiline(false);
588 writer.write_param("power", power)?;
589 writer.write_param("speed", speed)?;
590 writer.write_param("duration", duration)?;
591 writer.write_param("wait", wait)?;
592 writer.finish()?;
593 }
594 Command::Wait { duration } => {
595 let mut writer = FunctionCallWriter::new(&mut writer, indent, "wait")?;
596 writer.set_multiline(false);
597 writer.write_param("duration", duration)?;
598 writer.finish()?;
599 }
600 Command::ShowPicture {
601 picture_id,
602 picture_name,
603 origin,
604 x,
605 y,
606 scale_x,
607 scale_y,
608 opacity,
609 blend_mode,
610 } => {
611 let picture_name = escape_string(picture_name);
612 let x = match x {
613 MaybeRef::Constant(value) => value.to_string(),
614 MaybeRef::Ref(id) => config.get_variable_name(*id),
615 };
616 let y = match y {
617 MaybeRef::Constant(value) => value.to_string(),
618 MaybeRef::Ref(id) => config.get_variable_name(*id),
619 };
620
621 write_indent(&mut writer, indent)?;
622 writeln!(&mut writer, "show_picture(")?;
623
624 write_indent(&mut writer, indent + 1)?;
625 writeln!(&mut writer, "picture_id={picture_id},")?;
626
627 write_indent(&mut writer, indent + 1)?;
628 writeln!(&mut writer, "picture_name='{picture_name}',")?;
629
630 write_indent(&mut writer, indent + 1)?;
631 writeln!(&mut writer, "origin={origin},")?;
632
633 write_indent(&mut writer, indent + 1)?;
634 writeln!(&mut writer, "x={x},")?;
635
636 write_indent(&mut writer, indent + 1)?;
637 writeln!(&mut writer, "y={y},")?;
638
639 write_indent(&mut writer, indent + 1)?;
640 writeln!(&mut writer, "scale_x={scale_x},")?;
641
642 write_indent(&mut writer, indent + 1)?;
643 writeln!(&mut writer, "scale_y={scale_y},")?;
644
645 write_indent(&mut writer, indent + 1)?;
646 writeln!(&mut writer, "opacity={opacity},")?;
647
648 write_indent(&mut writer, indent + 1)?;
649 writeln!(&mut writer, "blend_mode={blend_mode},")?;
650
651 write_indent(&mut writer, indent)?;
652 writeln!(&mut writer, ")")?;
653 }
654 Command::ErasePicture { picture_id } => {
655 let mut writer = FunctionCallWriter::new(&mut writer, indent, "erase_picture")?;
656 writer.set_multiline(false);
657 writer.write_param("picture_id", picture_id)?;
658 writer.finish()?;
659 }
660 Command::PlayBgm { audio } => {
661 let mut writer = FunctionCallWriter::new(&mut writer, indent, "play_bgm")?;
662 writer.write_param("audio", audio)?;
663 writer.finish()?;
664 }
665 Command::FadeoutBgm { duration } => {
666 let mut writer = FunctionCallWriter::new(&mut writer, indent, "fadeout_bgm")?;
667 writer.set_multiline(false);
668 writer.write_param("duration", duration)?;
669 writer.finish()?;
670 }
671 Command::SaveBgm => {
672 write_indent(&mut writer, indent)?;
673 writeln!(&mut writer, "save_bgm()")?;
674 }
675 Command::ResumeBgm => {
676 write_indent(&mut writer, indent)?;
677 writeln!(&mut writer, "resume_bgm()")?;
678 }
679 Command::PlayBgs { audio } => {
680 write_indent(&mut writer, indent)?;
681 writeln!(&mut writer, "play_bgs(")?;
682
683 write_indent(&mut writer, indent + 1)?;
684 write!(&mut writer, "audio=")?;
685 write_audio_file(&mut writer, indent + 1, audio)?;
686
687 write_indent(&mut writer, indent)?;
688 writeln!(&mut writer, ")")?;
689 }
690 Command::FadeoutBgs { duration } => {
691 write_indent(&mut writer, indent)?;
692 writeln!(&mut writer, "fadeout_bgs(duration={duration})")?;
693 }
694 Command::PlaySe { audio } => {
695 let mut writer = FunctionCallWriter::new(&mut writer, indent, "play_se")?;
696 writer.write_param("audio", audio)?;
697 writer.finish()?;
698 }
699 Command::GetLocationInfo {
700 variable_id,
701 kind,
702 x,
703 y,
704 } => {
705 let variable = config.get_variable_name(*variable_id);
706 let x = match x {
707 MaybeRef::Constant(x) => x.to_string(),
708 MaybeRef::Ref(x) => config.get_variable_name(*x),
709 };
710 let y = match y {
711 MaybeRef::Constant(y) => y.to_string(),
712 MaybeRef::Ref(y) => config.get_variable_name(*y),
713 };
714
715 let value = match kind {
716 GetLocationInfoKind::TerrainTag => {
717 format!("game_map.get_terrain_tag(x={x}, y={y})")
718 }
719 GetLocationInfoKind::EventId => {
720 format!("game_map.get_event_id(x={x}, y={y})")
721 }
722 };
723
724 write_indent(&mut writer, indent)?;
725 writeln!(&mut writer, "{variable} = {value}")?;
726 }
727 Command::BattleProcessing {
728 troop_id,
729 can_escape,
730 can_lose,
731 } => {
732 let mut writer = FunctionCallWriter::new(&mut writer, indent, "battle_processing")?;
733 match troop_id {
734 Some(MaybeRef::Constant(id)) => {
735 let name = config.get_troop_name(*id);
736 writer.write_param("troop", &Ident(&name))?;
737 }
738 Some(MaybeRef::Ref(id)) => {
739 let name = config.get_variable_name(*id);
740 writer.write_param("troop_id", &Ident(&name))?;
741 }
742 None => {
743 writer.write_param("troop_id", &Ident("game.random_encounter_troop_id()"))?;
744 }
745 }
746 writer.write_param("can_escape", can_escape)?;
747 writer.write_param("can_lose", can_lose)?;
748 writer.finish()?;
749 }
750 Command::NameInputProcessing { actor_id, max_len } => {
751 let actor = config.get_actor_name(*actor_id);
752
753 let mut writer = FunctionCallWriter::new(&mut writer, indent, "name_input_processing")?;
754 writer.set_multiline(false);
755 writer.write_param("actor", &Ident(&actor))?;
756 writer.write_param("max_len", max_len)?;
757 writer.finish()?;
758 }
759 Command::ChangeHp {
760 actor_id,
761 is_add,
762 value,
763 allow_death,
764 } => {
765 let mut writer = FunctionCallWriter::new(&mut writer, indent, "gain_hp")?;
766 writer.set_multiline(false);
767 match actor_id {
768 MaybeRef::Constant(actor_id) => {
769 let name = config.get_actor_name(*actor_id);
770 writer.write_param("actor", &Ident(&name))?;
771 }
772 MaybeRef::Ref(variable_id) => {
773 let name = config.get_variable_name(*variable_id);
774 writer.write_param("actor_id", &Ident(&name))?;
775 }
776 };
777 let sign = if *is_add { "" } else { "-" };
778 let value = match value {
779 MaybeRef::Constant(value) => value.to_string(),
780 MaybeRef::Ref(id) => config.get_variable_name(*id),
781 };
782 let value = format!("{sign}{value}");
783 writer.write_param("value", &Ident(&value))?;
784 writer.write_param("allow_death", allow_death)?;
785 writer.finish()?;
786 }
787 Command::ChangeMp {
788 actor_id,
789 is_add,
790 value,
791 } => {
792 let mut writer = FunctionCallWriter::new(&mut writer, indent, "gain_mp")?;
793 writer.set_multiline(false);
794 match actor_id {
795 MaybeRef::Constant(actor_id) => {
796 let name = config.get_actor_name(*actor_id);
797 writer.write_param("actor", &Ident(&name))?;
798 }
799 MaybeRef::Ref(variable_id) => {
800 let name = config.get_variable_name(*variable_id);
801 writer.write_param("actor_id", &Ident(&name))?;
802 }
803 };
804 let sign = if *is_add { "" } else { "-" };
805 let value = match value {
806 MaybeRef::Constant(value) => value.to_string(),
807 MaybeRef::Ref(id) => config.get_variable_name(*id),
808 };
809 let value = format!("{sign}{value}");
810
811 writer.write_param("value", &Ident(&value))?;
812 writer.finish()?;
813 }
814 Command::ChangeState {
815 actor_id,
816 is_add_state,
817 state_id,
818 } => {
819 let actor_arg = match actor_id {
820 MaybeRef::Constant(0) => "actors=game_party".to_string(),
821 MaybeRef::Constant(actor_id) => {
822 let name = config.get_actor_name(*actor_id);
823 format!("actor={name}")
824 }
825 MaybeRef::Ref(variable_id) => {
826 let name = config.get_variable_name(*variable_id);
827 format!("actor_id={name}")
828 }
829 };
830
831 let fn_name = if *is_add_state {
832 "add_state"
833 } else {
834 "remove_state"
835 };
836 let state = config.get_state_name(*state_id);
837
838 write_indent(&mut writer, indent)?;
839 writeln!(&mut writer, "{fn_name}({actor_arg}, state={state})")?;
840 }
841 Command::ChangeLevel {
842 actor_id,
843 is_add,
844 value,
845 show_level_up,
846 } => {
847 let actor_arg = match actor_id {
848 MaybeRef::Constant(actor_id) => {
849 let name = config.get_actor_name(*actor_id);
850 format!("actor={name}")
851 }
852 MaybeRef::Ref(variable_id) => {
853 let name = config.get_variable_name(*variable_id);
854 format!("actor_id={name}")
855 }
856 };
857 let sign = if *is_add { "" } else { "-" };
858 let value = match value {
859 MaybeRef::Constant(value) => value.to_string(),
860 MaybeRef::Ref(id) => config.get_variable_name(*id),
861 };
862 let show_level_up = stringify_bool(*show_level_up);
863
864 write_indent(&mut writer, indent)?;
865 writeln!(
866 &mut writer,
867 "gain_level({actor_arg}, value={sign}{value}, show_level_up={show_level_up})"
868 )?;
869 }
870 Command::ChangeSkill {
871 actor_id,
872 is_learn_skill,
873 skill_id,
874 } => {
875 let actor_arg = match actor_id {
876 MaybeRef::Constant(actor_id) => {
877 let name = config.get_actor_name(*actor_id);
878 format!("actor={name}")
879 }
880 MaybeRef::Ref(variable_id) => {
881 let name = config.get_variable_name(*variable_id);
882 format!("actor_id={name}")
883 }
884 };
885 let fn_name = if *is_learn_skill {
886 "learn_skill"
887 } else {
888 "forget_skill"
889 };
890 let skill = config.get_skill_name(*skill_id);
891
892 write_indent(&mut writer, indent)?;
893 writeln!(&mut writer, "{fn_name}({actor_arg}, skill={skill})")?;
894 }
895 Command::ChangeClass {
896 actor_id,
897 class_id,
898 keep_exp,
899 } => {
900 let actor = config.get_actor_name(*actor_id);
901 let class = config.get_class_name(*class_id);
902 let keep_exp = stringify_bool(*keep_exp);
903
904 write_indent(&mut writer, indent)?;
905 writeln!(
906 &mut writer,
907 "change_class(actor={actor}, klass={class}, keep_exp={keep_exp})"
908 )?;
909 }
910 Command::ChangeActorImages {
911 actor_id,
912 character_name,
913 character_index,
914 face_name,
915 face_index,
916 battler_name,
917 } => {
918 let actor_name = config.get_actor_name(*actor_id);
919 let character_name = escape_string(character_name);
920 let face_name = escape_string(face_name);
921 let battler_name = escape_string(battler_name);
922
923 write_indent(&mut writer, indent)?;
924 writeln!(&mut writer, "change_actor_images(")?;
925
926 write_indent(&mut writer, indent + 1)?;
927 writeln!(&mut writer, "actor={actor_name},")?;
928
929 write_indent(&mut writer, indent + 1)?;
930 writeln!(&mut writer, "character_name='{character_name}',")?;
931
932 write_indent(&mut writer, indent + 1)?;
933 writeln!(&mut writer, "character_index={character_index},")?;
934
935 write_indent(&mut writer, indent + 1)?;
936 writeln!(&mut writer, "face_name='{face_name}',")?;
937
938 write_indent(&mut writer, indent + 1)?;
939 writeln!(&mut writer, "face_index={face_index},")?;
940
941 write_indent(&mut writer, indent + 1)?;
942 writeln!(&mut writer, "battler_name='{battler_name}',")?;
943
944 write_indent(&mut writer, indent)?;
945 writeln!(&mut writer, ")")?;
946 }
947 Command::ForceAction {
948 is_enemy,
949 id,
950 skill_id,
951 target_index,
952 } => {
953 let arg_0 = if *is_enemy {
954 format!("enemy_index={id}")
955 } else {
956 let actor = config.get_actor_name(*id);
957 format!("actor={actor}")
958 };
959 let skill = config.get_skill_name(*skill_id);
960
961 write_indent(&mut writer, indent)?;
962 writeln!(
963 &mut writer,
964 "force_action({arg_0}, skill={skill}, target_index={target_index})"
965 )?;
966 }
967 Command::AbortBattle => {
968 let mut writer = FunctionCallWriter::new(&mut writer, indent, "abort_battle")?;
969 writer.finish()?;
970 }
971 Command::GameOver => {
972 let mut writer = FunctionCallWriter::new(&mut writer, indent, "game_over")?;
973 writer.finish()?;
974 }
975 Command::ReturnToTitleScreen => {
976 let mut writer =
977 FunctionCallWriter::new(&mut writer, indent, "return_to_title_screen")?;
978 writer.finish()?;
979 }
980 Command::Script { lines } => {
981 write_indent(&mut writer, indent)?;
982 writeln!(&mut writer, "script(")?;
983
984 write_indent(&mut writer, indent + 1)?;
985 writeln!(writer, "lines=[")?;
986
987 for line in lines {
988 let line = escape_string(line);
989
990 write_indent(&mut writer, indent + 2)?;
991 writeln!(writer, "'{line}',")?;
992 }
993
994 write_indent(&mut writer, indent + 1)?;
995 writeln!(&mut writer, "],")?;
996
997 write_indent(&mut writer, indent)?;
998 writeln!(&mut writer, ")")?;
999 }
1000 Command::PluginCommand { params } => {
1001 write_indent(&mut writer, indent)?;
1002 write!(&mut writer, "plugin_command(")?;
1003 for (i, param) in params.iter().enumerate() {
1004 if i != 0 {
1005 write!(&mut writer, ", ")?;
1006 }
1007 let param = escape_string(param);
1008 write!(&mut writer, "'{param}'")?;
1009 }
1010 writeln!(&mut writer, ")")?;
1011 }
1012 Command::When {
1013 choice_index,
1014 choice_name,
1015 } => {
1016 write_indent(&mut writer, indent)?;
1017 writeln!(
1018 &mut writer,
1019 "if get_choice_index() == {choice_index}: # {choice_name}"
1020 )?;
1021 }
1022 Command::WhenCancel {
1023 choice_index,
1024 choice_name,
1025 } => {
1026 ensure!(choice_name.is_none());
1027
1028 write_indent(&mut writer, indent)?;
1029 writeln!(
1030 &mut writer,
1031 "if get_choice_index() == -1: # Cancel, index={choice_index}"
1032 )?;
1033 }
1034 Command::WhenEnd => {
1035 }
1037 Command::Else => {
1038 write_indent(&mut writer, indent)?;
1039 writeln!(&mut writer, "else:")?;
1040 }
1041 Command::ConditionalBranchEnd => {
1042 }
1044 Command::RepeatAbove => {
1045 }
1047 Command::IfWin => {
1048 writeln!(&mut writer, "if game_battle_result.is_win():")?;
1049 }
1050 Command::IfEscape => {
1051 writeln!(&mut writer, "if game_battle_result.is_escape():")?;
1052 }
1053 Command::IfLose => {
1054 writeln!(&mut writer, "if game_battle_result.is_lose():")?;
1055 }
1056 Command::BattleResultEnd => {
1057 }
1059 Command::Unknown { code, parameters } => {
1060 write_indent(&mut writer, indent)?;
1061 writeln!(
1062 &mut writer,
1063 "# Unknown Command Code {code:?}, parameters: {parameters:?}"
1064 )?;
1065 }
1066 }
1067 Ok(())
1068}
1069
1070fn stringify_bool(b: bool) -> &'static str {
1071 match b {
1072 true => "True",
1073 false => "False",
1074 }
1075}
1076
1077fn write_indent<W>(mut writer: W, indent: u16) -> std::io::Result<()>
1078where
1079 W: Write,
1080{
1081 for _ in 0..indent {
1082 write!(writer, "\t")?;
1083 }
1084
1085 Ok(())
1086}
1087
1088fn escape_string(input: &str) -> String {
1089 input.replace('\'', "\\'")
1090}
1091
1092fn write_audio_file<W>(
1093 mut writer: W,
1094 indent: u16,
1095 audio: &rpgmv_types::AudioFile,
1096) -> std::io::Result<()>
1097where
1098 W: Write,
1099{
1100 let audio_name = escape_string(&audio.name);
1101
1102 writeln!(&mut writer, "AudioFile(")?;
1103
1104 write_indent(&mut writer, indent + 1)?;
1105 writeln!(&mut writer, "name='{audio_name}',")?;
1106
1107 write_indent(&mut writer, indent + 1)?;
1108 writeln!(&mut writer, "pan={},", audio.pan)?;
1109
1110 write_indent(&mut writer, indent + 1)?;
1111 writeln!(&mut writer, "pitch={},", audio.pitch)?;
1112
1113 write_indent(&mut writer, indent + 1)?;
1114 writeln!(&mut writer, "volume={},", audio.volume)?;
1115
1116 write_indent(&mut writer, indent)?;
1117 writeln!(&mut writer, "),")?;
1118
1119 Ok(())
1120}