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