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