view 06/ecl.xml @ 13:2925b0e246c6 default tip

Fix a lot of things, and add a TODO.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Fri, 17 Feb 2012 12:54:08 +0100
parents 79dfd9765a67
children
line wrap: on
line source

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../html.xsl"?>
<?xml-stylesheet type="text/css" href="../style.css"?>
<opcodes xmlns="urn:opcodes:description">
	<title>ECL Sub format</title>

	<text>
		<div xmlns="http://www.w3.org/1999/xhtml">
			<h2>Lvalues and Rvalues / direct vs memory indirect addressing</h2>
			<p>In EoSD, most 32-bits arguments passed to instructions may be actual values or variable indexes.<br/>
			Values comprised between -10025 and -10001 are variable indexes, whereas other values are actual values.
			Values passed through variable/register indexes are Lvalues, other values are not. Some instructions require some of their operands to be Lvalues.</p>

			<h2>Accessing values</h2>
			<p>[TODO: verify] How the game accesses values passed as argument is as follows:<br/>
			TYPE is the type of the argument (float, int32, ...):</p>

<pre>if ((TYPE) argument &lt; -10000)
    return *(TYPE*) &amp;variables[(int)(-10000-(TYPE) argument)];
else
    return (TYPE) argument;</pre>

			<h2>Variables</h2>
			<p>Only variables in the range [-10001, -10025] without -10014, -10020 and -10023 are used in the game.</p>

			<h3>Local variables</h3>
			<p>Local variables may be read or written by the script, they are local to a subroutine, and put on a stack when a subroutine is called. They are not used by the game engine itself.</p>
			<table>
				<tr><th>Number</th><th>Type</th></tr>
				<tr><td>-10001</td><td>int</td></tr>
				<tr><td>-10002</td><td>int</td></tr>
				<tr><td>-10003</td><td>int</td></tr>
				<tr><td>-10004</td><td>int</td></tr>
				<tr><td>-10005</td><td>float</td></tr>
				<tr><td>-10006</td><td>float</td></tr>
				<tr><td>-10007</td><td>float</td></tr>
				<tr><td>-10008</td><td>float</td></tr>
				<tr><td>-10009</td><td>int</td></tr>
				<tr><td>-10010</td><td>int</td></tr>
				<tr><td>-10011</td><td>int</td></tr>
				<tr><td>-10012</td><td>int</td></tr>
			</table>

			<h3>Special variables</h3>
			<p>Special variables are game or enemy-scoped variables and most of them cannot be overriden by the script.</p>
			<table>
				<tr><th>Number</th><th>Type</th>	<th>Name</th>		<th>RW/RO</th>	<th>Notes</th></tr>
				<tr><td>-10013</td><td>int</td>		<td>rank</td>		<td>ro</td>	<td></td></tr>
				<tr><td>-10014</td><td>int</td>		<td>difficulty</td>	<td>ro</td>	<td>Unused.</td></tr>
				<tr><td>-10015</td><td>float</td>	<td>x</td>		<td>rw</td>	<td></td></tr>
				<tr><td>-10016</td><td>float</td>	<td>y</td>		<td>rw</td>	<td></td></tr>
				<tr><td>-10017</td><td>float</td>	<td>z</td>		<td>rw</td>	<td>Actually used by Flandre. Warning!</td></tr>
				<tr><td>-10018</td><td>float</td>	<td>player_x</td>	<td>ro</td>	<td></td></tr>
				<tr><td>-10019</td><td>float</td>	<td>player_y</td>	<td>ro</td>	<td></td></tr>
				<tr><td>-10020</td><td>float</td>	<td></td>		<td>ro</td>	<td>Unused.</td></tr>
				<tr><td>-10021</td><td>float</td>	<td>player_angle</td>	<td>ro</td>	<td></td></tr>
				<tr><td>-10022</td><td>int</td>		<td>last_frame</td>	<td>rw</td>	<td></td></tr>
				<tr><td>-10023</td><td>float</td>	<td>player_distance</td><td>ro</td>	<td>Unused.</td></tr>
				<tr><td>-10024</td><td>int</td>		<td>life</td>		<td>rw</td>	<td></td></tr>
				<tr><td>-10025</td><td>int</td>		<td>player</td>		<td>ro</td>	<td>0 = ReimuA, 1 = ReimuB, 2 = MarisaA, 3 = MarisaB</td></tr>
			</table>

			<h2>Opcodes</h2>
		</div>
	</text>

	<op>
		<num>0</num>
		<name>noop</name>
		<desc>Do nothing.</desc>
	</op>

	<op>
		<num>1</num>
		<name>delete</name>
		<params>
			<param type="S" values="0">Unknown</param>
		</params>
		<desc>Delete the sprite and perhaps free the memory used.</desc>
	</op>

	<op>
		<num>2</num>
		<name>relative_jump</name>
		<params>
			<param type="S" name="new_frame" unit="frame" values="0 to 360"/>
			<param type="S" name="relative_offset" unit="bytes" values="-2032 to 632">Starting from the start of the current opcode.</param>
		</params>
		<desc>Unconditionally jump to relative_offset with new frame counter. Used as a while.</desc>
	</op>

	<op>
		<num>3</num>
		<name>relative_jump_ex</name>
		<params>
			<param type="S" name="new_frame" unit="frame" values="0 to 532"/>
			<param type="S" name="relative_offset" unit="bytes" values="-1376 to -12"/>
			<param type="S" name="counter_id" unit="var_id" var="must" values="-10011 to -10009"/>
		</params>
		<desc>If the counter is non-null, jump to relative_offset with new frame counter, and decrease counter counter_id by 1. Used as a for.</desc>
	</op>

	<op>
		<num>4</num>
		<name>set_int</name>
		<params>
			<param type="S" name="variable" unit="var_id" var="must" values="-10012 to -10001"/>
			<param type="S" name="value" var="can" values="-10005 to -10021, 0 to 300"/>
		</params>
		<desc>Assign a value to the variable. Sometimes, value can be another variable.</desc>
	</op>

	<op>
		<num>5</num>
		<name>set_float</name>
		<params>
			<param type="S" name="variable" unit="var_id" var="must" values="-10005 to -10017"/>
			<param type="f" name="value" var="can" values="-12.0f to 460.0f"/>
		</params>
		<desc>Like <ref>4</ref>, but with a float as value.</desc>
	</op>

	<op>
		<num>6</num>
		<name>set_random_int</name>
		<params>
			<param type="S" name="variable" unit="var_id" var="must" values="-10001"/>
			<param type="S" name="value" var="can" values="2, 3"/>
		</params>
		<desc>Assign an integer in the [0, value) range to the variable.</desc>
	</op>

	<op>
		<num>8</num>
		<name>set_random_float</name>
		<params>
			<param type="S" name="variable" unit="var_id" var="must"/>
			<param type="f" name="maximum" var="can" values="1.0f to 2pi to 384.0f"/>
		</params>
		<desc>Like <ref>6</ref>, but with a float as value.</desc>
	</op>

	<op>
		<num>9</num>
		<name>set_random_float2</name>
		<params>
			<param type="S" name="variable" unit="var_id" var="must"/>
			<param type="f" name="amplitude"/>
			<param type="f" name="minimum"/>
		</params>
		<desc>Assign a float in the [minimum, minimum+amplitude) range to the variable.</desc>
	</op>

	<op>
		<num>10</num>
		<name>store_x</name>
		<params>
			<param type="S" name="variable" unit="var_id" var="must" values="-10005"/>
		</params>
		<desc>Store the x value of the enemy in the specified variable. Equivalent to <ref>4</ref>(variable, -10015).</desc>
	</op>

	<op>
		<num>13</num>
		<name>add_int</name>
		<params>
			<param type="S" name="variable" unit="var_id" var="must"/>
			<param type="S" name="a" var="can"/>
			<param type="S" name="b" var="can"/>
		</params>
		<desc>variable = a + b;</desc>
	</op>

	<op>
		<num>14</num>
		<name>substract_int</name>
		<params>
			<param type="S" name="variable" unit="var_id" var="must"/>
			<param type="S" name="a" var="can"/>
			<param type="S" name="b" var="can"/>
		</params>
		<desc>variable = a - b;</desc>
	</op>

	<op>
		<num>15</num>
		<name>multiply_int</name>
		<params>
			<param type="S" name="variable" var="must" values="-10001"/>
			<param type="S" name="a" var="can" values="-10012"/>
			<param type="S" name="b" var="can" values="1 to 5"/>
		</params>
		<desc>variable = a * b;</desc>
	</op>

	<op>
		<num>16</num>
		<name>divide_int</name>
		<params>
			<param type="S" name="variable" var="must"/>
			<param type="S" name="a" var="can"/>
			<param type="S" name="b" var="can"/>
		</params>
		<desc>variable = a / b;</desc>
	</op>

	<op>
		<num>17</num>
		<name>modulo</name>
		<params>
			<param type="S" name="variable" var="must"/>
			<param type="S" name="a" var="can"/>
			<param type="S" name="b" var="can"/>
		</params>
		<desc>variable = a % b;</desc>
	</op>

	<op>
		<num>18</num>
		<name>increment</name>
		<params>
			<param type="S" name="variable" unit="var_id" var="must" values="-10012, -10004, -10002, -10001"/>
		</params>
		<desc>Increment the given integer variable of 1.</desc>
	</op>

	<op>
		<num>20</num>
		<name>add_float</name>
		<params>
			<param type="S" name="variable" unit="var_id" var="must"/>
			<param type="f" var="can" name="a"/>
			<param type="f" var="can" name="b"/>
		</params>
		<desc>variable = a + b; Warning: a and b will be dereferenced as integers (not converted) if variable is an integer!</desc>
	</op>

	<op>
		<num>21</num>
		<name>substract_float</name>
		<params>
			<param type="S" name="variable" unit="var_id" var="must"/>
			<param type="f" var="can" name="a"/>
			<param type="f" var="can" name="b"/>
		</params>
		<desc>variable = a - b; Warning: a and b will be dereferenced as integers (not converted) if variable is an integer!</desc>
	</op>

	<op>
		<num>23</num>
		<name>divide_float</name>
		<params>
			<param type="S" name="variable" unit="var_id" var="must"/>
			<param type="f" var="can" name="a"/>
			<param type="f" var="can" name="b"/>
		</params>
		<desc>variable = a / b;</desc>
	</op>

	<op>
		<num>25</num>
		<name>get_direction</name>
		<params>
			<param type="S" var="must" values="-10005"/>
			<param type="f" name="x1" unit="pixels" var="can"/>
			<param type="f" name="y1" unit="pixels" var="can"/>
			<param type="f" name="x2" unit="pixels" var="can" values="192.0f"/>
			<param type="f" name="y2" unit="pixels" var="can" values="224.0f"/>
		</params>
		<desc>Compute the direction between two points. If the first is at the left of the second put 0.0f in the variable, if it is above put pi/2, etc.</desc>
	</op>

	<op>
		<num>26</num>
		<name>float_to_unit_circle</name>
		<params>
			<param type="S" var="must" values="float variables"/>
		</params>
		<desc>Takes a float and transforms it to be in the [-pi, pi] interval.<br/>3.1415928 -> pi; 3.1415929 -> -pi.</desc>
	</op>

	<op>
		<num>27</num>
		<name>compare_ints</name>
		<params>
			<param type="S" var="can" name="a"/>
			<param type="S" var="can" name="b"/>
		</params>
		<desc>Compare a and b, store the result (-1 if a &lt; b, 0 if a == b, 1 if a > b) in the "comparison register".</desc>
	</op>

	<op>
		<num>28</num>
		<name>compare_floats</name>
		<params>
			<param type="f" var="can" name="a"/>
			<param type="f" var="can" name="b"/>
		</params>
		<desc>Like <ref>27</ref>, but with floats.</desc>
	</op>

	<op>
		<num>29</num>
		<name>relative_jump_if_lower_than</name>
		<params>
			<param type="S" name="new_frame" unit="frame"/>
			<param type="S" name="relative_offset" unit="bytes"/>
		</params>
		<desc>Like <ref>2</ref> but only when the comparison register equals to -1.</desc>
	</op>

	<op>
		<num>30</num>
		<name>relative_jump_if_lower_or_equal</name>
		<params>
			<param type="S" name="new_frame" unit="frame" values="0, 60, 65, 120"/>
			<param type="S" name="relative_offset" unit="bytes" values="40, 44, 60, 456"/>
		</params>
		<desc>Like <ref>2</ref> but only when the comparison register is different of 1.</desc>
	</op>

	<op>
		<num>31</num>
		<name>relative_jump_if_equal</name>
		<params>
			<param type="S" name="new_frame" unit="frame" values="0, 2, 60"/>
			<param type="S" name="relative_offset" unit="bytes" values="44, 176, 324">Starting from the start of the current opcode.</param>
		</params>
		<desc>Like <ref>2</ref> but only when the comparison register equals to 0.</desc>
	</op>

	<op>
		<num>32</num>
		<name>relative_jump_if_greater_than</name>
		<params>
			<param type="S" name="new_frame" unit="frame" values="120"/>
			<param type="S" name="relative_offset" unit="bytes" values="64"/>
		</params>
		<desc>Like <ref>2</ref> but only when the comparison register equals to 1.</desc>
	</op>

	<op>
		<num>33</num>
		<name>relative_jump_if_greater_or_equal</name>
		<params>
			<param type="S" name="new_frame" unit="frame"/>
			<param type="S" name="relative_offset" unit="bytes"/>
		</params>
		<desc>Like <ref>2</ref> but only when the comparison register is different of -1.</desc>
	</op>

	<op>
		<num>34</num>
		<name>relative_jump_if_not_equal</name>
		<params>
			<param type="S" name="new_frame" unit="frame"/>
			<param type="S" name="relative_offset" unit="bytes"/>
		</params>
		<desc>Like <ref>2</ref> but only when the comparison register is different of 0.</desc>
	</op>

	<op>
		<num>35</num>
		<name>call</name>
		<params>
			<param type="S" name="function" unit="sub"/>
			<param type="S" name="param1"/>
			<param type="f" name="param2" values="-0.31415927f to 0.31415927f"/>
		</params>
		<desc>Call given sub with -10001 = param1, -10005 = param2.</desc>
	</op>

	<op>
		<num>36</num>
		<name>return</name>
		<desc>When the sub is called by a <ref>35</ref> or a <ref>39</ref>, returns to the calling sub. If it was called from the main, crash.</desc>
	</op>

	<op>
		<num>39</num>
		<name>call_if_equal</name>
		<params>
			<param type="S" name="function" unit="sub"/>
			<param type="S" values="0" name="param1"/>
			<param type="f" values="0.0f" name="param2"/>
			<param type="S" name="a"/>
			<param type="S" name="b"/>
		</params>
		<desc>Call given sub with -10001 = param1, -10005 = param2 if a == b.</desc>
	</op>

	<op>
		<num>43</num>
		<name>set_pos</name>
		<params>
			<param type="f" name="x" var="can"/>
			<param type="f" name="y" var="can"/>
			<param type="f" name="z" var="can" values="0.0f">Ignored</param>
		</params>
		<desc>Move the enemy to a new position, used for interpolation.</desc>
	</op>

	<op>
		<num>45</num>
		<name>set_angle_speed</name>
		<params>
			<param type="f" name="angle" unit="radian">0.0f is left, PI/2 is down.</param>
			<param type="f" name="speed" unit="pixels/frame"/>
		</params>
		<desc>Set the angular trajectory and speed of the enemy.</desc>
	</op>

	<op>
		<num>46</num>
		<name>set_rotation_speed</name>
		<params>
			<param type="f" name="speed" unit="radian/frame"/>
		</params>
		<desc>Change the angular trajectory of the enemy. It continues to turn until this function is called again.</desc>
	</op>

	<op>
		<num>47</num>
		<name>set_speed</name>
		<params>
			<param type="f" name="speed" unit="pixels/frame"/>
		</params>
		<desc>Change the speed of the enemy.</desc>
	</op>

	<op>
		<num>48</num>
		<name>set_acceleration</name>
		<params>
			<param type="f" name="step" unit="pixels/frame"/>
		</params>
		<desc>Change the speed of the enemy step by step, at each frame.</desc>
	</op>

	<op>
		<num>49</num>
		<name>set_random_angle</name>
		<params>
			<param type="f" name="min" unit="radian" values="0.7853982f"/>
			<param type="f" name="max" unit="radian" values="2.3561945f"/>
		</params>
		<desc>Set the enemy angle in the [min, max-min) range.</desc>
	</op>

	<op>
		<num>50</num>
		<name>set_random_angle_ex</name>
		<params>
			<param type="f" values="-PI (-3.1415927f)"/>
			<param type="f" values="PI (3.1415927f)"/>
		</params>
		<desc>Like <ref>49</ref>, but enclosed in boxes. TODO: document that.</desc>
	</op>

	<op>
		<num>51</num>
		<name>set_speed_towards_player</name>
		<params>
			<param type="S" value="0">Ignored</param>
			<param type="f" name="speed" unit="pixels/frame"/>
		</params>
		<desc>Sets the speed of the enemy, and change its direction to where the player is at that frame.</desc>
	</op>

	<op>
		<num>52</num>
		<name>move_in_decel</name>
		<params>
			<param type="S" name="duration" unit="frames" values="10, 370"/>
			<param type="f" name="angle" unit="radian" values="0.0f to pi"/>
			<param type="f" name="speed" unit="pixels/frame" values="0.8f, 4.0f"/>
		</params>
		<desc>Like <ref>45</ref>, but move the enemy in `duration` frames, using an decelerating interpolation function. TODO: find that function.</desc>
	</op>

	<op>
		<num>56</num>
		<name>move_to_linear</name>
		<params>
			<param type="S" name="duration" unit="frames"/>
			<param type="f" name="x" unit="pixels"/>
			<param type="f" name="y" unit="pixels"/>
			<param type="f" name="z" unit="pixels" values="0.0f">Ignored</param>
		</params>
		<desc>Move the enemy to the new position in `duration` amount of frames, using the <code>x↦x</code> function.</desc>
	</op>

	<op>
		<num>57</num>
		<name>move_to_decel</name>
		<params>
			<param type="S" name="duration" unit="frames"/>
			<param type="f" name="x" unit="pixels"/>
			<param type="f" name="y" unit="pixels"/>
			<param type="f" name="z" unit="pixels" values="0.0f">Ignored</param>
		</params>
		<desc>Like <ref>56</ref>, but with <code>x↦2x-x²</code>.</desc>
	</op>

	<op>
		<num>59</num>
		<name>move_to_accel</name>
		<params>
			<param type="S" name="duration" unit="frames"/>
			<param type="f" name="x" unit="pixels" values="192.0f"/>
			<param type="f" name="y" unit="pixels" values="-64.0f, 150.0f"/>
			<param type="f" name="z" unit="pixels" values="0.0f"/>
		</params>
		<desc>Like <ref>56</ref>, but with <code>x↦x²</code>.</desc>
	</op>

	<op>
		<num>61</num>
		<name>stop_in_decel</name>
		<params>
			<param type="S" name="duration" unit="frames"/>
		</params>
		<desc>Keep a straight trajectory with decelerating speed to stop in duration frames.</desc>
	</op>

	<op>
		<num>63</num>
		<name>stop_in_accel</name>
		<params>
			<param type="S" name="duration" unit="frames"/>
		</params>
		<desc>Like <ref>61</ref> but with acceleration instead of deceleration.</desc>
	</op>

	<op>
		<num>65</num>
		<name>set_screen_box</name>
		<params>
			<param type="f" name="x1" unit="pixels"/>
			<param type="f" name="y1" unit="pixels"/>
			<param type="f" name="x2" unit="pixels"/>
			<param type="f" name="y2" unit="pixels"/>
		</params>
		<desc>Disallow an enemy to quit the defined rectangle. If it goes outside it is destroyed. By default this rectangle is the displayed screen.</desc>
	</op>

	<op>
		<num>66</num>
		<name>clear_screen_box</name>
		<desc>Remove the limit set in <ref>65</ref>.</desc>
	</op>

	<op>
		<num>67</num>
		<name>set_bullet_attributes_towards_player</name>
		<params>
			<param type="s" name="anim" unit="script"/>
			<param type="s" name="sprite_index_offset" unit="script"/>
			<param type="S" name="bullets_per_shot" var="can"/>
			<param type="S" name="number_of_shots"/>
			<param type="f" name="speed" unit="pixels/frame"/>
			<param type="f" name="speed2" unit="pixels/frame">speed + (speed2 - speed) * salve / nb_salve</param>
			<param type="f" name="launch_angle" unit="radian"/>
			<param type="f" name="angle" unit="radian"/>
			<param type="S" name="flags">>= 64, freezed</param>
		</params>
		<desc>Modify the attributes of the next enemy attack. Directs it to the player.</desc>
	</op>

	<op>
		<num>68</num>
		<name>set_bullet_attributes_to_the_right</name>
		<params ref="67"/>
		<desc>The same as <ref>67</ref>, except the 0.0f launch angle is to the right of the enemy, instead of towards the player.</desc>
	</op>

	<op>
		<num>69</num>
		<name>set_bullet_attributes_towards_player_equally_distributed</name>
		<params ref="67"/>
		<desc>Like <ref>67</ref>, except bullets of a shot are distributed equally all around the enemy, computing the angle by itself.</desc>
	</op>

	<op>
		<num>70</num>
		<name>set_bullet_attributes_to_the_right_equally_distributed</name>
		<params ref="67"/>
		<desc>Like <ref>68</ref>, except bullets of a shot are distributed equally all around the enemy, computing the angle by itself.</desc>
	</op>

	<op>
		<num>71</num>
		<name>set_bullet_attributes_towards_player_equally_distributed_and_rotated</name>
		<params ref="67"/>
		<desc>Like <ref>69</ref>, but with a rotation of pi/bullets_per_shot.</desc>
	</op>

	<op>
		<num>74</num>
		<name>set_bullet_attributes_towards_player_randomly_distributed</name>
		<params ref="67"/>
		<desc>Like <ref>70</ref> but with some alea (?) in the angle.</desc>
	</op>

	<op>
		<num>75</num>
		<name>set_bullet_attributes_to_the_right_with_some_random_angle</name>
		<params ref="67"/>
		<desc>Like <ref>68</ref>, but with some random angle.</desc>
	</op>

	<op>
		<num>76</num>
		<name>bullet_interval</name>
		<params>
			<param type="S" name="interval" unit="frames" values="0 to 70"/>
		</params>
		<desc>Time between two shots, 0 is infinite.</desc>
	</op>

	<op>
		<num>77</num>
		<name>bullet_interval_random</name>
		<params>
			<param type="S" name="interval" unit="frames" values="0 to 300"/>
		</params>
		<desc>Like <ref>76</ref>, but with a random delay of [0, interval) frames at the start.</desc>
	</op>

	<op>
		<num>78</num>
		<name>delay_attack</name>
		<desc>If present, delays the first attack of the amount of frames defined by <ref>77</ref>. If not, the enemy shoots instantly after setting the bullets attributes.</desc>
	</op>

	<op>
		<num>79</num>
		<name>no_delay_attack</name>
		<desc>Instantly start to attack.</desc>
	</op>

	<op>
		<num>81</num>
		<name>bullet_launch_offset</name>
		<params>
			<param type="f" name="x" unit="pixels" var="can"/>
			<param type="f" name="y" unit="pixels" var="can"/>
			<param type="f" name="z" unit="pixels" var="can" values="0.0f">Ignored</param>
		</params>
		<desc>Change the offset of the launch of bullets.</desc>
	</op>

	<op>
		<num>82</num>
		<name>set_extended_bullet_attributes</name>
		<params>
			<param type="S" values="-1, 1, 2, 40 to 240"/>
			<param type="S" values="-1, 1, 2"/>
			<param type="S" values="-1">Unused</param>
			<param type="S" values="-1">Unused</param>
			<param type="f" var="can" values="-100021.0f, variables, -1.0f, -3.6651914f to 2.443461f"/>
			<param type="f" var="can" values="variables, -999.0f, -1.0f, -0.03141593f to 4.0f"/>
			<param type="f" values="-1.0f">Unused</param>
			<param type="f" values="-1.0f">Unused</param>
		</params>
		<desc>Heavily linked to 67-75 last parameter, the flags:<dl>
<dt>1:</dt>
    <dd>TODO: changes the bullet's speed in a strange way</dd>

<dt>2:</dt>
    <dd>TODO: Whatever 2 does, it is in the same group as, and takes precedence over 4 and 8</dd>
<dt>4:</dt>
    <dd>TODO: Whatever 4 does, it is in the same group as, and takes precedence over 8</dd>
<dt>8:</dt>
    <dd>TODO</dd>

<dt>16: <code><ref>82</ref>(int duration,,,, float length, float angle,,)</code></dt>
    <dd>for `duration` frames, add (cos(angle) * length, sin(angle) * length) to the speed vector at each frame?</dd>
<dt>32: <code><ref>82</ref>(int duration, int count,,, float acceleration, float angular_speed,,)</code></dt>
    <dd>for `duration` frames, add acceleration to speed, and angular_speed to angle at each frame. Do that count times.</dd>
<dt>64: <code><ref>82</ref>(int nb_frames, int count,,, float angle, float speed,,)</code></dt>
    <dd>stop the bullet in nb_frames, then add angle to its angle, and sets its speed to speed. Do that count times.</dd>
<dt>128: <code><ref>82</ref>(int nb_frames, int count,,, float angle, float speed,,)</code></dt>
    <dd>stop the bullet in nb_frames, then directs the bullet towards the player, add angle to its angle, and sets its speed to speed. Do that count times.</dd>
<dt>256: <code><ref>82</ref>(int nb_frames, int count,,, float angle, float speed,,)</code></dt>
    <dd>stop the bullet in nb_frames, then sets the bullet's angle and speed to angle and speed. Do that count times.</dd>

<dt>512:</dt>
    <dd>TODO: doesn't seem to change anything?</dd>

<dt>1024: <code><ref>82</ref>(int nb_bounces,,,, float speed,,,)</code></dt>
    <dd>Bullets “bounce”, reentering the screen as soon as they leave it, with a new speed set.</dd>
<dt>2048:</dt>
    <dd>Like 1024, except it only bounces when colliding with the left, upper and right edges.</dd></dl></desc>
	</op>

	<op>
		<num>83</num>
		<name>change_bullets_in_star_bonus</name>
		<desc>Isn’t called for every boss, there should be another way to do that.</desc>
	</op>

	<op>
		<num>84</num>
		<name></name>
		<params>
			<param type="S" values="-1, 7, 22, 23, 25, 27"/>
		</params>
		<desc></desc>
	</op>

	<op>
		<num>85</num>
		<name>laser</name>
		<params>
			<param type="s" name="laser_type" unit="script"/>
			<param type="s" name="sprite_index_offset" unit="script"/>
			<param type="f" name="angle" unit="radian">clockwise</param>
			<param type="S" name="speed" unit="pixels/frame">speed of the laser along its axis</param>
			<param type="f" name="start_offset" unit="pixels">offset along the laser axis, relative to the enemy. If negative, it is considered as 0.</param>
			<param type="f" name="end_offset" unit="pixels">offset along the laser axis, relative to the enemy. Can be negative. In case end_offset &lt; start_offset, the laser will be in the oposite direction.</param>
			<param type="f" name="max_length" unit="pixels">TODO: Not really a length, something really odd. The laser starts at max(start_offset, end_offset - length) and ends at end_offset.</param>
			<param type="f" name="width" unit="pixels"/>
			<param type="S" name="start_duration" unit="frames"/>
			<param type="S" name="duration" unit="frames"/>
			<param type="S" name="stop_duration" unit="frames"/>
			<param type="S" name="grazing_dealy" unit="frames">how long to wait before allowing grazing</param>
			<param type="S" name="grazing_extra_duration" unit="frames">how long to allow grazing after the laser started to disappear</param>
			<param type="S" values="0"/>
		</params>
		<desc>Spawn a laser and set its attributes.</desc>
	</op>

	<op>
		<num>86</num>
		<name>laser_towards_player</name>
		<params ref="85"/>
		<desc>Like <ref>85</ref>, with the default direction towards the player.</desc>
	</op>

	<op>
		<num>87</num>
		<name>set_upcoming_id</name>
		<params>
			<param type="S" name="laser" unit="laser_id"/>
		</params>
		<desc>Sets upcoming laser to a given id, in order to manipulate it later.</desc>
	</op>

	<op>
		<num>88</num>
		<name>alter_laser_angle</name>
		<params>
			<param type="S" name="laser" unit="laser_id"/>
			<param type="f" name="delta" unit="radian"/>
		</params>
		<desc>Adds delta to the laser's angle.</desc>
	</op>

	<op>
		<num>90</num>
		<name>translate_laser</name>
		<params>
			<param type="S" values="0 to 3" name="laser" unit="laser_id"/>
			<param type="f" values="0.0f" name="x" unit="pixels"/>
			<param type="f" values="0.0f" name="y" unit="pixels"/>
			<param type="f" values="0.0f" name="z" unit="pixels">Ignored</param>
		</params>
		<desc>Translate a laser with the current position of the launching enemy as origin, but don’t follow her after that.</desc>
	</op>

	<op>
		<num>92</num>
		<name>cancel_laser</name>
		<params>
			<param type="S" values="0 to 3" name="laser" unit="laser_id"/>
		</params>
		<desc>Cancel a laser before its normal duration.</desc>
	</op>

	<op>
		<num>93</num>
		<name>set_spellcard</name>
		<params>
			<param type="s" name="face" value="0 to 3">If greater than 3, it’s the character faces that are used.</param>
			<param type="s" name="number">As in the captured spellcards screen, minus 1.</param>
			<param type="z" name="name">In SHIFT_JIS</param>
		</params>
		<desc>
			<p>Start a spellcard and</p>
			<ul>
				<li>Display the name of the spellcard in the screen.</li>
				<li>Change the background to the eff one.</li>
				<li>Make the enemies more resistant or the attacks weaker. The damage caused by a bullet is reduced to 6 instead of 48.</li>
				<li>Clear all the bullets and transform them in star bonus.</li>
			</ul>
		</desc>
	</op>

	<op>
		<num>94</num>
		<name>end_spellcard</name>
		<desc>
			<p>Finish the current spellcard and</p>
			<ul>
				<li>Remove its name.</li>
				<li>Put back the normal background.</li>
				<li>Return the damages to the normal.</li>
				<li>Clear all the bullets and transform them in star bonus.</li>
			</ul>
		</desc>
	</op>

	<op>
		<num>95</num>
		<name>spawn_enemy</name>
		<params>
			<param type="S" name="function" unit="sub" values="1, 20 to 66"/>
			<param type="f" name="x" unit="pixels" var="can" values="-10015.0f, -10005.0f, -32.0f to 416.0f"/>
			<param type="f" name="y" unit="pixels" var="can" values="-10016.0f, -32.0f to 464.0f"/>
			<param type="f" name="z" unit="pixels" var="can" values="-10017.0f, -1.5707964f to 3.3379421f, 160.0f, 288.0f"/>
			<param type="s" name="resistance" values="-5536, 2 to 2000"/>
			<param type="s" name="drop_type" values="-2, 0, 1, 2"/>
			<param type="S" name="die_score" values="0, 10, 2000"/>
		</params>
		<desc>Spawns an enemy, see <a href="ecl.xhtml#enemy_sub">the main creation of an enemy</a>.</desc>
	</op>

	<op>
		<num>96</num>
		<name>kill_all_enemies</name>
		<desc>Instantly kill all enemies presents in the screen, dropping their bonus as if they were killed by the player. Seems to not kill if the enemy is not touchable (see <ref>117</ref>) or a boss (see <ref>101</ref>).</desc>
	</op>

	<op>
		<num>97</num>
		<name>set_enemy_anim</name>
		<params>
			<param type="S" name="anim" unit="script" var="no"/>
		</params>
		<desc>Set a sprite (taken from current anm) for the enemy.</desc>
	</op>

	<op>
		<num>98</num>
		<name>set_boss_anims</name>
		<params>
			<param type="s" name="default" unit="script" var="no"/>
			<param type="s" name="far_left" unit="script" var="no"/>
			<param type="s" name="far_right" unit="script" var="no"/>
			<param type="s" name="left" unit="script" var="no"/>
			<param type="s" name="right" unit="script" var="no"/>
			<param type="s" name="padding"/>
		</params>
		<desc>Give a set of animations for a boss deplacements.</desc>
	</op>

	<op>
		<num>99</num>
		<name>set_aux_anim</name>
		<params>
			<param type="S" name="number" values="0, 4"/>
			<param type="S" name="animation" unit="script" values="16 to 18, 66"/>
		</params>
		<desc>Add an auxiliary animation (up to 8) with always the same coordinates as the enemy.</desc>
	</op>

	<op>
		<num>100</num>
		<name>set_death_anim</name>
		<params>
			<param type="S" name="anim" unit="script" var="no" values="768, 769, 258">In fact, any 256n+[0-2] works and is the same; other values make the program crash.</param>
		</params>
		<desc>When the enemy is destroyed, the animation used.</desc>
	</op>

	<op>
		<num>101</num>
		<name>set_boss_mode</name>
		<params>
			<param type="S" name="x" values="-1, 0">0 is activate, -1 is deactivate.</param>
		</params>
		<desc>Activates the boss mode, with her life bar and lives number displayed on the top. Doesn't do anything before calling <ref>126</ref> (TODO: really?). If there are multiple boss, spawned by a <ref>95</ref>, only the last one has her life displayed, but standard enemies are blocked only until any of them is killed.</desc>
	</op>

	<op>
		<num>102</num>
		<name>create_squares</name>
		<params>
			<param type="S" values="0 to 11, 16, 22, 25"/>
			<param type="f" name="x_rotate" values="-1.0f to 1.1f"/>
			<param type="f" name="y_rotate" values="-1.0f to -0.1f"/>
			<param type="f" name="z_rotate" values="-0.3f, -0.5f"/>
			<param type="f" values="48.0f"/>
		</params>
		<desc>Create the squares turning around some boss. They stay even after the destruction of the enemy.</desc>
	</op>

	<op>
		<num>103</num>
		<name>set_enemy_hitbox</name>
		<params>
			<param type="f" name="width" unit="pixels" values="16 to 56"/>
			<param type="f" name="height" unit="pixels" values="16 to 56"/>
			<param type="f" name="depth" unit="pixels" values="32.0f">Ignored</param>
		</params>
		<desc></desc>
	</op>

	<op>
		<num>104</num>
		<name>set_collidable</name>
		<params>
			<param type="S" name="x" values="0, 1">Bitfield</param>
		</params>
		<desc>if x &amp; 1, the enemy can collide with the player, else it cannot.</desc>
	</op>

	<op>
		<num>105</num>
		<name>set_damageable</name>
		<params>
			<param type="S" name="x" values="0, 1">Bitfield</param>
		</params>
		<desc>if x &amp; 1, the enemy can take damage, else it cannot.</desc>
	</op>

	<op>
		<num>106</num>
		<name>play_sound</name>
		<params>
			<param type="S" values="5 to 9, 14, 16 to 18, 22, 24 to 27">
				0 = crash,
				1 = crash,
				/11
			</param>
		</params>
		<desc>Play a sound.</desc>
	</op>

	<op>
		<num>107</num>
		<name>set_death_flags</name>
		<params>
			<param type="S"/>
		</params>
		<desc>
			<p>Control what to do when life falls to zero, only in the [0, 7] interval:</p>
			<p>0 = normal;<br/>
			1 = die once and unset touchable/collidable;<br/>
			2 = die in loop (drop an item each time, start a new die animation), but keep being here, touchable/collidable;<br/>
			3 = die once and keep being touchable/collidable if killed by the normal attack, else die as in normal (with a bomb, a collision, a <ref>96</ref>…), even after dying once from a normal attack;<br/>
			4-7 (unused) = die in loop, with lot of sparks, but don't drop bonus.</p>
		</desc>
	</op>

	<op>
		<num>108</num>
		<name>call_when_killed</name>
		<params>
			<param type="S" name="function" unit="sub"/>
		</params>
		<desc>Specify the subroutine to call when the enemy is killed. Only if the death flag is not null.</desc>
	</op>

	<op>
		<num>109</num>
		<name>memory_write_int32</name>
		<params>
			<param type="S" name="value"/>
			<param type="S" name="offset" values="0"/>
		</params>
		<desc>
			<pre>int32_t memory *= enemy->data;
memory[offset] = value;</pre>
			<p>Eight variables (indexes 0 to 7) seems to be available, the following data is enemy state, with:<br/>
			9: x, 10: y, 11: z, 12: hitbox width, 13: hitbox height, 14: hitbox depth, ...<br/>
			TODO: see 0x00409532</p>

			<p>This is used to set a sub to call once the MSG has finished.</p>
		</desc>
	</op>

	<op>
		<num>111</num>
		<name>set_life</name>
		<params>
			<param type="S" name="life"/>
		</params>
		<desc>Equivalent to <ref>4</ref>(-10024, life).</desc>
	</op>

	<op>
		<num>112</num>
		<name>set_elapsed_time</name>
		<params>
			<param type="S" name="time" unit="frames" values="0, 99999"/>
		</params>
		<desc>Equivalent to <ref>4</ref>(-10022, time).</desc>
	</op>

	<op>
		<num>113</num>
		<name>set_boss_lower_life_limit</name>
		<params>
			<param type="S" name="limit" unit="life" values="-1, 500-3400"/>
		</params>
		<desc>When enemy's life gets lower or equal to the limit, the callback set by <ref>114</ref> is called.</desc>
	</op>

	<op>
		<num>114</num>
		<name>set_boss_life_callback</name>
		<params>
			<param type="S" name="callback" unit="sub" values="9-68"/>
		</params>
		<desc>Specify the sub to call when the enemy's life gets below a certain amount set by a <ref>113</ref>.</desc>
	</op>

	<op>
		<num>115</num>
		<name>set_timeout</name>
		<params>
			<param type="S" name="timeout" unit="frame"/>
		</params>
		<desc>Set the timeout of the current boss attack.</desc>
	</op>

	<op>
		<num>116</num>
		<name>set_timeout_callback</name>
		<params>
			<param type="S" name="function" unit="sub" values="6 to 68"/>
		</params>
		<desc>Like <ref>114</ref>, but when timeouted.</desc>
	</op>

	<op>
		<num>117</num>
		<name>set_touchable</name>
		<params>
			<param type="S" name="x" values="0, 1">Bitfield</param>
		</params>
		<desc>If 0, the player's attacks don't do anything to the enemy. RumiaA's homing attack is no more attracted by that enemy. <ref>96</ref> won’t kill it. 1 restores the usual comportment.</desc>
	</op>

	<op>
		<num>118</num>
		<name>quot_explosion_quot</name> <!-- TODO: find a better name. -->
		<params>
			<param type="S" values="3, 4, 12, 17, 18"/>
			<param type="S" values="1, 2, 6"/>
			<param type="S" values="1, 0xffffffff, 0xffffff80, 0xffff8080, 0xff80ff80, 0xff8080ff"/>
		</params>
		<desc>"Explosion" (dying boss), Meiling’s moves, and various graphical effects like that.</desc>
	</op>

	<op>
		<num>119</num>
		<name>drop_bonus</name>
		<params>
			<param type="S" name="number" values="3, 4, 5, 6, 8, 10, 12, 20"/>
		</params>
		<desc>Drop a certain number of bonus at the frame it is called, in a square around the enemy (TODO: check its dimensions). If the power is not max, drop power items, else drop point items.</desc>
	</op>

	<op>
		<num>120</num>
		<name>set_automatic_rotate</name>
		<params>
			<param type="S" name="x" values="0, 1">Bitfield</param>
		</params>
		<desc>if x &amp; 1, rotate the sprite according to the angle of the enemy.</desc>
	</op>

	<op>
		<num>121</num>
		<name>call_special_function_with_param</name>
		<params>
			<param type="S" name="function" values="0, 1, 3, 4, 7 to 9, 11 to 14, 16"/>
			<param type="S" name="param" values="0 to 3, 5, 6, 128"/>
		</params>
		<desc>
			<p>Call an hardcoded function in this list:</p>
			<table>
				<tr><th>Function</th><th>Description</th></tr>
				<tr><td>0</td><td>Freeze all the bullets in the screen if the parameter is 0, else unfreeze them. Do an explosion animation too.</td></tr>
				<tr><td>1</td><td>Launch a bullet immediately, with a launch_offset of [-param, param] for each coordinate.</td></tr>
				<tr><td>3</td><td>Change the -10002, -10003 and -10004 variables according to the character. [0, 3, 1] for ReimuA, [2, 3, 4] for ReimuB, [1, 4, 0] for MarisaA and [4, 2, 3] for MarisaB. Used to choose the dual-sign spellcards of Patchouli. The parameter is unused.</td></tr>
				<tr><td>4</td><td>If 0, unfreeze time and do an explosion animation. If 1, freeze time for the player, the bullets, the texts, but let the ECL run normally, also do an explosion animation. Else do nothing.</td></tr>
				<tr><td>7</td><td>If 0, make a lasers web, and remove any previous. Else, a crapload of bullets directed towards the player (TODO: find their origin).</td></tr>
				<tr><td>8</td><td>Do nothing?</td></tr>
				<tr><td>9</td><td>Do an explosion animation.</td></tr>
				<tr><td>11</td><td>Do an explosion animation.</td></tr>
				<tr><td>12</td><td>Do nothing?</td></tr>
				<tr><td>13</td><td>Fire `param` times the configured attack in circle, as if the enemy was at the center of the screen with:<ul>
					<li>-10006 that overrides the launch_angle set in 67-75;</li>
					<li>-10007 the rotation of the launch points with the center of the screen as origin;</li>
					<li>-10008 the distance between the center of the screen and the launch points.</li></ul>Seems to be launched only each 6 frames, even if the call is each frame.</td></tr>
				<tr><td>14</td><td>Do nothing?</td></tr>
				<tr><td>16</td><td>Used in QED: Ripples of 495 Years and probably do a temporization and modify launch_offset.</td></tr>
			</table>
		</desc>
	</op>

	<op>
		<num>122</num>
		<name>call_special_function_without_param</name>
		<params>
			<param type="S" name="function"/>
		</params>
		<desc>
			<p>Call an hardcoded function in this list:</p>
			<table>
				<tr><th>Function</th><th>Description</th></tr>
				<tr><td>-1</td><td>Stop</td></tr>
				<tr><td>2</td><td>Do nothing?</td></tr>
				<tr><td>5</td><td>Sakuya’s knives, each 12 frames.</td></tr>
				<tr><td>6</td><td>Add a wings flapping animation. Used by the Scarlet sisters.</td></tr>
				<tr><td>10</td><td>Some graphic animation.</td></tr>
				<tr><td>15</td><td>The bullets 6, 7, 8 and 9 push the 1, 2, 3, 4 and 5 bullets. Also do some graphic animation.</td></tr>
			</table>
		</desc>
	</op>

	<op>
		<num>123</num>
		<name>skip_frames</name>
		<params>
			<param type="S" name="number" unit="frames" var="can"/>
		</params>
		<desc>Skip a certain amount of frames, while keeping the current instruction pointer in place.</desc>
	</op>

	<op>
		<num>124</num>
		<name>drop_specific_bonus</name>
		<params>
			<param type="S" name="type" var="no">0 = power, 1 = point, 2 = big power, 3 = bomb, 4 = full power, 5 = 1up, 6 = star bonus, greater drop nothing.</param>
		</params>
		<desc>Drop a bonus vertically. Can be called multiple times to drop more items, but they'll be superposed.</desc>
	</op>

	<op>
		<num>125</num>
		<name></name>
		<desc></desc>
	</op>

	<op>
		<num>126</num>
		<name>set_boss_lives</name>
		<params>
			<param type="S" name="lives">Can even be negative. :D</param>
		</params>
		<desc>Sets the remaining lives of a boss. Should be called at the start of each round.</desc>
	</op>

	<op>
		<num>127</num>
		<name></name>
		<params>
			<param type="S" var="can/must" values="integer variables"/>
		</params>
		<desc></desc>
	</op>

	<op>
		<num>128</num>
		<name>interrupt_anm</name>
		<params>
			<param type="S" name="interruption" values="1"/>
		</params>
		<desc>Send this interruption to the anm.</desc>
	</op>

	<op>
		<num>129</num>
		<name></name>
		<params>
			<param type="S" values="0">Bitfield?</param>
			<param type="S" values="1">Bitfield?</param>
		</params>
		<desc></desc>
	</op>

	<op>
		<num>130</num>
		<name></name>
		<params>
			<param type="S" values="1">Bitfield?</param>
		</params>
		<desc></desc>
	</op>

	<op>
		<num>131</num>
		<name>set_difficulty_influence</name>
		<params>
			<param type="f" name="speed_low" values="-1.0f, -0.5f, -0.3f, 0.0f"/>
			<param type="f" name="speed_high" values="0.0f, 0.3f, 0.8f, 1.0f"/>
			<param type="S" name="delay_low" values="-3, -2, -1, 0"/>
			<param type="S" name="delay_high" values="0, 2, 4, 5, 6"/>
			<param type="S" name="shots_low" values="0"/>
			<param type="S" name="shots_high" values="0"/>
		</params>
		<desc>Change the influence of the difficulty on the attacks. The defaults are (-0.5f, 0.5f, 0, 0, 0, 0).</desc>
	</op>

	<op>
		<num>132</num>
		<name>set_invisible</name>
		<params>
			<param type="S" values="0, 1">Bitfield</param>
		</params>
		<desc><div xmlns="http://www.w3.org/1999/xhtml">
			If <code>x &amp; 1</code>, disable drawing of the sprite <strong>and</strong> destroy it. While it isn’t set to 0, loading a new sprite won’t make it reappear.
		</div></desc>
	</op>

	<op>
		<num>133</num>
		<name></name>
		<desc>Do not influence on the game itself. TODO: what is its utility?</desc>
	</op>

	<op>
		<num>134</num>
		<name></name>
		<desc>Do not influence on the game itself. TODO: what is its utility?</desc>
	</op>

	<op>
		<num>135</num>
		<name>enable_spellcard_bonus</name>
		<params>
			<param type="S" values="0, 1">Bitfield</param>
		</params>
		<desc>If <code>x &amp; 1</code>, FIXME. Enabled is the default.</desc>
	</op>
</opcodes>