OSDN Git Service

イニシャルコミット。
[marathon/ShapeFusion.git] / Physics / PhysicsEditor.cpp
1 /*
2  * This file is part of ShapeFusion (Copyright 2000 Tito Dal Canton)
3  *
4  * ShapeFusion is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * ShapeFusion is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with ShapeFusion; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18
19 #include "wx/wxprec.h"
20
21 #ifndef WX_PRECOMP
22 #include "wx/wx.h"
23 #endif
24
25 #include "wx/clipbrd.h"
26
27 #include <cmath>
28
29 #include "PhysicsView.h"
30 #include "PhysicsTreeItemData.h"
31 #include "../ShapeFusionMenus.h"
32
33 BEGIN_EVENT_TABLE(PhysicsView, wxView)
34         EVT_MENU(EDIT_MENU_COPY, PhysicsView::MenuEditCopy)
35         EVT_MENU(EDIT_MENU_PASTE, PhysicsView::MenuEditPaste)
36         EVT_TREE_SEL_CHANGED(-1, PhysicsView::OnTreeSelect)
37         EVT_COMMAND_RANGE(FIELD_ALIEN_COLLECTION, FIELD_ALIEN_RANGED_ATTACK_SHAPE, wxEVT_COMMAND_TEXT_UPDATED, PhysicsView::EditAlienFields)
38         EVT_TEXT(FIELD_ALIEN_RANDOM_SOUND_MASK, PhysicsView::EditAlienFields)
39         EVT_TEXT(FIELD_ALIEN_SOUND_PITCH, PhysicsView::EditAlienDoubles)
40         EVT_COMMAND_RANGE(MENU_ALIEN_ACTIVATION, MENU_ALIEN_RANDOM, wxEVT_COMMAND_CHOICE_SELECTED, PhysicsView::EditAlienMenus)
41         EVT_TEXT(FIELD_ALIEN_ATTACK_FREQUENCY, PhysicsView::EditAlienFields)
42         EVT_CHOICE(MENU_ALIEN_ATTACK_TYPE, PhysicsView::EditAlienMenus)
43         EVT_COMMAND_RANGE(FIELD_ALIEN_ATTACK_REPETITIONS, FIELD_ALIEN_ATTACK_DZ, wxEVT_COMMAND_TEXT_UPDATED, PhysicsView::EditAlienFields)
44         EVT_CHOICE(MENU_ALIEN_ATTACK_TYPE + NUM_ALIEN_ATTACK_CONTROLS, PhysicsView::EditAlienMenus)
45         EVT_COMMAND_RANGE(FIELD_ALIEN_ATTACK_REPETITIONS + NUM_ALIEN_ATTACK_CONTROLS, FIELD_ALIEN_ATTACK_DZ + NUM_ALIEN_ATTACK_CONTROLS, wxEVT_COMMAND_TEXT_UPDATED, PhysicsView::EditAlienFields)
46         EVT_TEXT(FIELD_ALIEN_SHRAPNEL_RADIUS, PhysicsView::EditAlienFields)
47         EVT_CHOICE(MENU_ALIEN_SHRAPNEL_DAMAGE_TYPE, PhysicsView::EditAlienMenus)
48         EVT_COMMAND_RANGE(FIELD_ALIEN_SHRAPNEL_BASE_DAMAGE, FIELD_ALIEN_SHRAPNEL_RANDOM_DAMAGE, wxEVT_COMMAND_TEXT_UPDATED, PhysicsView::EditAlienFields)
49         EVT_TEXT(FIELD_ALIEN_SHRAPNEL_DAMAGE_SCALE, PhysicsView::EditAlienDoubles)
50         EVT_CHECKBOX(CB_ALIEN_SHRAPNEL_ALIEN_DAMAGE, PhysicsView::EditAlienCheckboxes)
51         EVT_CHOICE(MENU_ALIEN_RANGED_IMPACT_EFFECT, PhysicsView::EditAlienMenus)
52         EVT_CHOICE(MENU_ALIEN_MELEE_IMPACT_EFFECT, PhysicsView::EditAlienMenus)
53         EVT_COMMAND_RANGE(FIELD_ALIEN_VITALITY, FIELD_ALIEN_MAX_LEDGE_JUMP, wxEVT_COMMAND_TEXT_UPDATED, PhysicsView::EditAlienFields)
54         EVT_TEXT(FIELD_ALIEN_EXT_VELOCITY_SCALE, PhysicsView::EditAlienDoubles)
55         EVT_COMMAND_RANGE(FIELD_ALIEN_HOVER_HEIGHT, FIELD_ALIEN_INTELLIGENCE, wxEVT_COMMAND_TEXT_UPDATED, PhysicsView::EditAlienFields)
56         EVT_COMMAND_RANGE(MENU_ALIEN_CARRYING_ITEM, MENU_ALIEN_CLASS, wxEVT_COMMAND_CHOICE_SELECTED, PhysicsView::EditAlienMenus)
57         EVT_COMMAND_RANGE(CB_ALIEN_FRIENDS, CB_ALIEN_WEAKNESSES + 23, wxEVT_COMMAND_CHECKBOX_CLICKED, PhysicsView::EditAlienCheckboxes)
58
59         EVT_COMMAND_RANGE(FIELD_EFFECT_COLLECTION, FIELD_EFFECT_SEQUENCE, wxEVT_COMMAND_TEXT_UPDATED, PhysicsView::EditEffectFields)
60         EVT_TEXT(FIELD_EFFECT_PITCH, PhysicsView::EditEffectDoubles)
61         EVT_CHOICE(MENU_EFFECT_DELAY_SOUND, PhysicsView::EditEffectMenus)
62         EVT_COMMAND_RANGE(CB_EFFECT_END_WHEN_ANIMATION_LOOPS, CB_EFFECT_MEDIA_EFFECT, wxEVT_COMMAND_CHECKBOX_CLICKED, PhysicsView::EditEffectCheckboxes)
63
64         EVT_COMMAND_RANGE(CB_SHOT_FLAGS, CB_SHOT_ALIEN_DAMAGE, wxEVT_COMMAND_CHECKBOX_CLICKED, PhysicsView::EditShotCheckboxes)
65         EVT_COMMAND_RANGE(FIELD_SHOT_COLLECTION, FIELD_SHOT_MAXIMUM_CONTRAILS, wxEVT_COMMAND_TEXT_UPDATED, PhysicsView::EditShotFields)
66         EVT_COMMAND_RANGE(FIELD_SHOT_DAMAGE_SCALE, FIELD_SHOT_SOUND_PITCH, wxEVT_COMMAND_TEXT_UPDATED, PhysicsView::EditShotDoubles)
67         EVT_COMMAND_RANGE(MENU_SHOT_DAMAGE_TYPE, MENU_SHOT_MEDIA_IMPACT, wxEVT_COMMAND_CHOICE_SELECTED, PhysicsView::EditShotMenus)
68
69         EVT_COMMAND_RANGE(FIELD_MAX_FORWARD_VELOCITY, FIELD_HALF_CAMERA_SEPARATION, wxEVT_COMMAND_TEXT_UPDATED, PhysicsView::EditPhysicsConstants)
70
71         EVT_COMMAND_RANGE(CB_WEAPON_FLAGS, CB_WEAPON_FLAGS + 9, wxEVT_COMMAND_CHECKBOX_CLICKED, PhysicsView::EditWeaponCheckboxes)
72         EVT_COMMAND_RANGE(FIELD_WEAPON_COLLECTION, FIELD_WEAPON_FLASH_DECAY, wxEVT_COMMAND_TEXT_UPDATED, PhysicsView::EditWeaponFields)
73         EVT_COMMAND_RANGE(FIELD_WEAPON_FLASH_INTENSITY, FIELD_WEAPON_IDLE_WIDTH, wxEVT_COMMAND_TEXT_UPDATED, PhysicsView::EditWeaponDoubles)
74         EVT_COMMAND_RANGE(MENU_WEAPON_ITEM_TYPE, MENU_WEAPON_CLASS, wxEVT_COMMAND_CHOICE_SELECTED, PhysicsView::EditWeaponMenus)
75         EVT_COMMAND_RANGE(FIELD_TRIGGER_ROUNDS, FIELD_TRIGGER_BURST_COUNT, wxEVT_COMMAND_TEXT_UPDATED, PhysicsView::EditTriggerFields)
76         EVT_COMMAND_RANGE(FIELD_TRIGGER_ROUNDS + NUM_TRIGGER_IDS, FIELD_TRIGGER_BURST_COUNT + NUM_TRIGGER_IDS, wxEVT_COMMAND_TEXT_UPDATED, PhysicsView::EditTriggerFields)
77         EVT_COMMAND_RANGE(MENU_TRIGGER_PROJECTILE, MENU_TRIGGER_SHELL_CASING_TYPE, wxEVT_COMMAND_CHOICE_SELECTED, PhysicsView::EditTriggerMenus)
78         EVT_COMMAND_RANGE(MENU_TRIGGER_PROJECTILE + NUM_TRIGGER_IDS, MENU_TRIGGER_SHELL_CASING_TYPE + NUM_TRIGGER_IDS, wxEVT_COMMAND_CHOICE_SELECTED, PhysicsView::EditTriggerMenus)
79 END_EVENT_TABLE()
80
81 IMPLEMENT_DYNAMIC_CLASS(PhysicsView, wxView)
82
83
84 static inline wxString Format(double f) { 
85         return wxString::Format(wxT("%0.4f"), f);
86 }
87
88 static inline wxString Format(unsigned short u) {
89         return wxString::Format(wxT("%hu"), u);
90 }
91
92 static inline wxString Format(short i) {
93         return wxString::Format(wxT("%hi"), i);
94 }
95
96 void PhysicsView::OnSelectPhysicsConstants(int index)
97 {
98         PhysicsConstants* constants = static_cast<PhysicsDocument*>(GetDocument())->GetPhysicsConstants(index);
99
100         max_forward_velocity_field->ChangeValue(Format(constants->GetMaximumForwardVelocity()));
101         max_backward_velocity_field->ChangeValue(Format(constants->GetMaximumBackwardVelocity()));
102         max_perpendicular_velocity_field->ChangeValue(Format(constants->GetMaximumPerpendicularVelocity()));
103
104         acceleration_field->ChangeValue(Format(constants->GetAcceleration()));
105         deceleration_field->ChangeValue(Format(constants->GetDeceleration()));
106         airborne_deceleration_field->ChangeValue(Format(constants->GetAirborneDeceleration()));
107         gravitational_acceleration_field->ChangeValue(Format(constants->GetGravitationalAcceleration()));
108         climbing_acceleration_field->ChangeValue(Format(constants->GetClimbingAcceleration()));
109         terminal_velocity_field->ChangeValue(Format(constants->GetTerminalVelocity()));
110         external_deceleration_field->ChangeValue(Format(constants->GetExternalDeceleration()));
111
112         step_delta_field->ChangeValue(Format(constants->GetStepDelta()));
113         step_amplitude_field->ChangeValue(Format(constants->GetStepAmplitude()));
114
115         radius_field->ChangeValue(Format(constants->GetRadius()));
116         height_field->ChangeValue(Format(constants->GetHeight()));
117
118         angular_acceleration_field->ChangeValue(Format(constants->GetAngularAcceleration()));
119         angular_deceleration_field->ChangeValue(Format(constants->GetAngularDeceleration()));
120         maximum_angular_velocity_field->ChangeValue(Format(constants->GetMaximumAngularVelocity()));
121         angular_recentering_velocity_field->ChangeValue(Format(constants->GetAngularRecenteringVelocity()));
122         head_angular_velocity_field->ChangeValue(Format(constants->GetFastAngularVelocity()));
123         head_angular_maximum_field->ChangeValue(Format(constants->GetFastAngularMaximum()));
124         maximum_elevation_field->ChangeValue(Format(constants->GetMaximumElevation()));
125         external_angular_deceleration_field->ChangeValue(Format(constants->GetExternalAngularDeceleration()));
126
127         dead_height_field->ChangeValue(Format(constants->GetDeadHeight()));
128         camera_height_field->ChangeValue(Format(constants->GetCameraHeight()));
129         splash_height_field->ChangeValue(Format(constants->GetSplashHeight()));
130         half_camera_separation_field->ChangeValue(Format(constants->GetHalfCameraSeparation()));
131         
132         mainbox->Show(physics_sizer, true);
133 }
134
135 void PhysicsView::OnSelectAlienAppearance(int index)
136 {
137         MonsterDefinition* monster = static_cast<PhysicsDocument*>(GetDocument())->GetMonsterDefinition(index);
138
139         alien_collection_field->ChangeValue(Format(monster->GetCollection()));
140         alien_color_table_field->ChangeValue(Format(monster->GetColorTable()));
141         
142         alien_hit_field->ChangeValue(Format(monster->GetHitShapes()));
143         alien_hard_dying_field->ChangeValue(Format(monster->GetHardDyingShape()));
144         alien_soft_dying_field->ChangeValue(Format(monster->GetSoftDyingShape()));
145         alien_hard_dead_field->ChangeValue(Format(monster->GetHardDeadShapes()));
146         alien_soft_dead_field->ChangeValue(Format(monster->GetSoftDeadShapes()));
147         alien_stationary_field->ChangeValue(Format(monster->GetStationaryShape()));
148         alien_moving_field->ChangeValue(Format(monster->GetMovingShape()));
149         alien_teleport_in_field->ChangeValue(Format(monster->GetTeleportInShape()));
150         alien_teleport_out_field->ChangeValue(Format(monster->GetTeleportOutShape()));
151         alien_melee_attack_shape_field->ChangeValue(Format(monster->GetMeleeAttack()->GetShape()));
152         alien_ranged_attack_shape_field->ChangeValue(Format(monster->GetRangedAttack()->GetShape()));
153
154         alien_activation_choice->SetSelection(monster->GetActivationSound() + 1);
155         alien_friendly_activation_choice->SetSelection(monster->GetFriendlyActivationSound() + 1);
156         alien_clear_choice->SetSelection(monster->GetClearSound() + 1);
157         alien_kill_choice->SetSelection(monster->GetKillSound() + 1);
158         alien_apology_choice->SetSelection(monster->GetApologySound() + 1);
159         alien_friendly_fire_choice->SetSelection(monster->GetFriendlyFireSound() + 1);
160         alien_flaming_choice->SetSelection(monster->GetFlamingSound() + 1);
161         alien_random_choice->SetSelection(monster->GetRandomSound() + 1);
162
163         alien_random_sound_mask_field->ChangeValue(Format(monster->GetRandomSoundMask()));
164         alien_sound_pitch_field->ChangeValue(Format(monster->GetSoundPitch()));
165         
166         mainbox->Show(aliens_appearance_sizer, true);
167 }
168
169 void PhysicsView::OnSelectAlienCombat(int index)
170 {
171         MonsterDefinition* monster = static_cast<PhysicsDocument*>(GetDocument())->GetMonsterDefinition(index);
172
173         alien_attack_frequency_field->ChangeValue(Format(monster->GetAttackFrequency()));
174         
175         for (int i = 0; i < 2; ++i) {
176                 AttackDefinition* attack = (i == 0) ? monster->GetMeleeAttack() : monster->GetRangedAttack();
177                 alien_attack_type_choices[i]->SetSelection(attack->GetType() + 1);
178                 alien_attack_repetitions_fields[i]->ChangeValue(Format(attack->GetRepetitions()));
179                 // Anvil displays the raw angle units here...
180                 alien_attack_error_fields[i]->ChangeValue(Format(static_cast<short>(std::floor(attack->GetError() * 512.0 / 360.0 + 0.5))));
181                 alien_attack_range_fields[i]->ChangeValue(Format(attack->GetRange()));
182                 alien_attack_sequence_fields[i]->ChangeValue(Format(attack->GetShape()));
183                 alien_attack_dx_fields[i]->ChangeValue(Format(attack->GetDx()));
184                 alien_attack_dy_fields[i]->ChangeValue(Format(attack->GetDy()));
185                 alien_attack_dz_fields[i]->ChangeValue(Format(attack->GetDz()));
186         }
187
188         alien_shrapnel_radius_field->ChangeValue(Format(monster->GetShrapnelRadius()));
189
190         DamageDefinition* shrapnel = monster->GetShrapnelDamage();
191         alien_shrapnel_damage_type_choice->SetSelection(shrapnel->GetType() + 1);
192         alien_shrapnel_base_damage_field->ChangeValue(Format(shrapnel->GetBase()));
193         alien_shrapnel_random_damage_field->ChangeValue(Format(shrapnel->GetRandom()));
194         alien_shrapnel_damage_scale_field->ChangeValue(Format(shrapnel->GetScale()));
195         alien_shrapnel_alien_damage_checkbox->SetValue(shrapnel->GetAlien());
196
197         alien_ranged_impact_effect_choice->SetSelection(monster->GetImpactEffect() + 1);
198         alien_melee_impact_effect_choice->SetSelection(monster->GetMeleeImpactEffect() + 1);
199
200         mainbox->Show(aliens_combat_sizer, true);
201 }
202
203 void PhysicsView::OnSelectAlienConstants(int index)
204 {
205         MonsterDefinition* monster = static_cast<PhysicsDocument*>(GetDocument())->GetMonsterDefinition(index);
206
207         alien_vitality_field->ChangeValue(Format(monster->GetVitality()));
208
209         alien_radius_field->ChangeValue(Format(monster->GetRadius()));
210         alien_height_field->ChangeValue(Format(monster->GetHeight()));
211
212         alien_speed_field->ChangeValue(Format(monster->GetSpeed()));
213
214         alien_terminal_velocity_field->ChangeValue(Format(monster->GetTerminalVelocity()));
215         alien_gravity_field->ChangeValue(Format(monster->GetGravity()));
216
217         alien_min_ledge_jump_field->ChangeValue(Format(monster->GetMinimumLedgeDelta()));
218         alien_max_ledge_jump_field->ChangeValue(Format(monster->GetMaximumLedgeDelta()));
219         alien_ext_velocity_scale_field->ChangeValue(Format(monster->GetExternalVelocityScale()));
220         alien_hover_height_field->ChangeValue(Format(monster->GetPreferredHoverHeight()));
221         
222         alien_door_retry_mask_field->ChangeValue(Format(monster->GetDoorRetryMask()));
223
224         alien_visual_range_field->ChangeValue(Format(monster->GetVisualRange()));
225         alien_dark_visual_range_field->ChangeValue(Format(monster->GetDarkVisualRange()));
226         alien_intelligence_field->ChangeValue(Format(monster->GetIntelligence()));
227
228         alien_carrying_item_choice->SetSelection(monster->GetCarryingItemType() + 1);
229         alien_contrail_effect_choice->SetSelection(monster->GetContrailEffect() + 1);
230
231         mainbox->Show(aliens_constants_sizer, true);
232 }
233
234 void PhysicsView::OnSelectAlienBehavior(int index)
235 {
236         MonsterDefinition* monster = static_cast<PhysicsDocument*>(GetDocument())->GetMonsterDefinition(index);
237
238         int monster_class_index = 0;
239         long monster_class = monster->GetClass();
240         while (monster_class >>= 1) {
241                 monster_class_index++;
242         }
243         alien_class_choice->SetSelection(monster_class_index);
244
245         for (int i = 0; i < 16; ++i) {
246                 alien_friends_checkboxes[i]->SetValue(monster->GetFriend(i));
247                 alien_enemies_checkboxes[i]->SetValue(monster->GetEnemy(i));
248         }
249
250         for (int i = 0; i < 27; ++i) {
251                 alien_flags_checkboxes[i]->SetValue(monster->GetFlag(i + 1));
252         }
253
254         mainbox->Show(aliens_behavior_sizer, true);
255 }
256
257 void PhysicsView::OnSelectAlienImmunities(int index)
258 {
259         MonsterDefinition* monster = static_cast<PhysicsDocument*>(GetDocument())->GetMonsterDefinition(index);
260
261         for (int i = 0; i < 24; ++i) {
262                 alien_immunities_checkboxes[i]->SetValue(monster->GetImmunity(i));
263                 alien_weaknesses_checkboxes[i]->SetValue(monster->GetWeakness(i));
264         }
265
266         mainbox->Show(aliens_immunities_sizer, true);
267 }
268
269 void PhysicsView::OnSelectEffect(int index)
270 {
271         EffectDefinition* effect = static_cast<PhysicsDocument*>(GetDocument())->GetEffectDefinition(index);
272         
273         eff_collection_field->ChangeValue(Format(effect->GetCollection()));
274         eff_color_table_field->ChangeValue(Format(effect->GetColorTable()));
275         eff_sequence_field->ChangeValue(Format(effect->GetShape()));
276         
277         eff_delay_field->ChangeValue(Format(effect->GetDelay()));
278         eff_pitch_field->ChangeValue(Format(effect->GetSoundPitch()));
279
280         eff_delay_sound_choice->SetSelection(effect->GetDelaySound() + 1);
281         
282         eff_end_when_animation_loops_checkbox->SetValue(effect->GetEndWhenAnimationLoops());
283         eff_end_when_transfer_animation_loops_checkbox->SetValue(effect->GetEndWhenTransferAnimationLoops());
284         eff_sound_only_checkbox->SetValue(effect->GetSoundOnly());
285         eff_media_effect_checkbox->SetValue(effect->GetMediaEffect());
286         
287         mainbox->Show(effects_sizer, true);
288 }
289
290 void PhysicsView::OnSelectShot(int index)
291 {
292         ProjectileDefinition* projectile = static_cast<PhysicsDocument*>(GetDocument())->GetProjectileDefinition(index);
293         
294         shots_collection_field->ChangeValue(Format(projectile->GetCollection()));
295         shots_color_table_field->ChangeValue(Format(projectile->GetColorTable()));
296         shots_sequence_field->ChangeValue(Format(projectile->GetShape()));
297
298         DamageDefinition* damage = projectile->GetDamage();
299
300         shots_damage_type_choice->SetSelection(damage->GetType() + 1);
301         shots_damage_base_field->ChangeValue(Format(damage->GetBase()));
302         shots_damage_random_field->ChangeValue(Format(damage->GetRandom()));
303         shots_damage_scale_field->ChangeValue(Format(damage->GetScale()));
304         shots_alien_damage_checkbox->SetValue(damage->GetAlien());
305
306         shots_flyby_sound_choice->SetSelection(projectile->GetFlybySound() + 1);
307         shots_rebound_sound_choice->SetSelection(projectile->GetReboundSound() + 1);
308         shots_sound_pitch_field->ChangeValue(Format(projectile->GetSoundPitch()));
309         
310         shots_radius_field->ChangeValue(Format(projectile->GetRadius()));
311         shots_area_of_effect_field->ChangeValue(Format(projectile->GetAreaOfEffect()));
312         shots_speed_field->ChangeValue(Format(projectile->GetSpeed()));
313         shots_range_field->ChangeValue(Format(projectile->GetMaximumRange()));
314
315         shots_detonation_effect_choice->SetSelection(projectile->GetDetonationEffect() + 1);
316         shots_media_detonation_effect_choice->SetSelection(projectile->GetMediaDetonationEffect() + 1);
317         shots_contrail_choice->SetSelection(projectile->GetContrailEffect() + 1);
318         shots_contrail_ticks_field->ChangeValue(Format(projectile->GetTicksBetweenContrails()));
319         shots_maximum_contrails_field->ChangeValue(Format(projectile->GetMaximumContrails()));
320
321         for (int i = 0; i < 22; ++i) {
322                 shots_flags_checkboxes[i]->SetValue(projectile->GetFlag(i));
323         }
324
325         shots_media_impact_choice->SetSelection(projectile->GetMediaProjectilePromotion() + 1);
326
327         mainbox->Show(shots_sizer, true);
328 }
329
330 void PhysicsView::OnSelectWeaponDefinition(int index)
331 {
332         WeaponDefinition* weapon = static_cast<PhysicsDocument*>(GetDocument())->GetWeaponDefinition(index);
333
334         weapon_item_type_choice->SetSelection(weapon->GetItemType() + 1);
335
336         weapon_collection_field->ChangeValue(Format(weapon->GetCollection()));
337         weapon_color_table_field->ChangeValue(Format(weapon->GetColorTable()));
338         weapon_idle_field->ChangeValue(Format(weapon->GetIdleShape()));
339         weapon_firing_field->ChangeValue(Format(weapon->GetFiringShape()));
340         weapon_reloading_field->ChangeValue(Format(weapon->GetReloadingShape()));
341         weapon_charging_field->ChangeValue(Format(weapon->GetChargingShape()));
342         weapon_charged_field->ChangeValue(Format(weapon->GetChargedShape()));
343         weapon_flash_intensity_field->ChangeValue(Format(weapon->GetFiringLightIntensity()));
344
345         weapon_ready_field->ChangeValue(Format(weapon->GetReadyTicks()));
346         weapon_await_reload_field->ChangeValue(Format(weapon->GetAwaitReloadTicks()));
347         weapon_loading_field->ChangeValue(Format(weapon->GetLoadingTicks()));
348         weapon_finish_loading_field->ChangeValue(Format(weapon->GetFinishLoadingTicks()));
349         weapon_flash_decay_field->ChangeValue(Format(weapon->GetFiringIntensityDecayTicks()));
350
351         weapon_class_choice->SetSelection(weapon->GetWeaponClass() + 1);
352         
353         weapon_idle_height_field->ChangeValue(Format(weapon->GetIdleHeight()));
354         weapon_bob_amplitude_field->ChangeValue(Format(weapon->GetBobAmplitude()));
355         weapon_kick_height_field->ChangeValue(Format(weapon->GetKickHeight()));
356         weapon_reload_height_field->ChangeValue(Format(weapon->GetReloadHeight()));
357         weapon_idle_width_field->ChangeValue(Format(weapon->GetIdleWidth()));
358
359         for (int i = 0; i < 10; ++i) {
360                 weapon_flags_checkboxes[i]->SetValue(weapon->GetFlag(i >= 5 ? i + 1 : i));
361         }
362
363         mainbox->Show(weapons_definitions_sizer, true);
364 }
365
366 void PhysicsView::OnSelectWeaponTriggers(int index)
367 {
368         WeaponDefinition* weapon = static_cast<PhysicsDocument*>(GetDocument())->GetWeaponDefinition(index);
369
370         for (int i = 0; i < 2; ++i) {
371                 TriggerDefinition* trigger = (i == 0) ? weapon->GetPrimaryTrigger() : weapon->GetSecondaryTrigger();
372
373                 trigger_projectile_choices[i]->SetSelection(trigger->GetProjectileType() + 1);
374                 trigger_rounds_fields[i]->ChangeValue(Format(trigger->GetRoundsPerMagazine()));
375                 trigger_ammo_type_choices[i]->SetSelection(trigger->GetAmmunitionType() + 1);
376
377                 trigger_firing_choices[i]->SetSelection(trigger->GetFiringSound() + 1);
378                 trigger_click_choices[i]->SetSelection(trigger->GetClickSound() + 1);
379                 trigger_charging_choices[i]->SetSelection(trigger->GetChargingSound() + 1);
380                 trigger_shell_casing_choices[i]->SetSelection(trigger->GetShellCasingSound() + 1);
381                 trigger_reloading_choices[i]->SetSelection(trigger->GetReloadingSound() + 1);
382                 trigger_charged_choices[i]->SetSelection(trigger->GetChargedSound() + 1);
383
384                 trigger_ticks_fields[i]->ChangeValue(Format(trigger->GetTicksPerRound()));
385                 trigger_recovery_fields[i]->ChangeValue(Format(trigger->GetRecoveryTicks()));
386                 trigger_charging_fields[i]->ChangeValue(Format(trigger->GetChargingTicks()));
387                 trigger_recoil_fields[i]->ChangeValue(Format(trigger->GetRecoilMagnitude()));
388                 trigger_theta_fields[i]->ChangeValue(Format(trigger->GetThetaError()));
389                 trigger_dx_fields[i]->ChangeValue(Format(trigger->GetDx()));
390                 trigger_dz_fields[i]->ChangeValue(Format(trigger->GetDz()));
391                 trigger_burst_count_fields[i]->ChangeValue(Format(trigger->GetBurstCount()));
392
393                 trigger_shell_casing_type_choices[i]->SetSelection(trigger->GetShellCasingType() + 1);
394
395         }
396
397         mainbox->Show(weapons_triggers_sizer, true);
398 }
399
400 void PhysicsView::OnTreeSelect(wxTreeEvent& e)
401 {
402         PhysicsTreeItemData* data = dynamic_cast<PhysicsTreeItemData*>(tree->GetItemData(e.GetItem()));
403         if (data) {
404                 mainbox->Show(aliens_appearance_sizer, false);
405                 mainbox->Show(aliens_behavior_sizer, false);
406                 mainbox->Show(aliens_combat_sizer, false);
407                 mainbox->Show(aliens_constants_sizer, false);
408                 mainbox->Show(aliens_immunities_sizer, false);
409                 mainbox->Show(dummy_sizer, false);
410                 mainbox->Show(effects_sizer, false);
411                 mainbox->Show(shots_sizer, false);
412                 mainbox->Show(physics_sizer, false);
413                 mainbox->Show(weapons_definitions_sizer, false);
414                 mainbox->Show(weapons_triggers_sizer, false);
415
416                 int new_section = data->Section();
417                 switch (new_section) {
418                 case TREESECTION_PHYSICS:
419                         OnSelectPhysicsConstants(data->ID());
420                         break;
421                 case TREESECTION_EFFECTS:
422                         OnSelectEffect(data->ID());
423                         break;
424                 case TREESECTION_PROJECTILES:
425                         OnSelectShot(data->ID());
426                         break;
427                 case TREESECTION_MONSTERS_APPEARANCE:
428                         OnSelectAlienAppearance(data->ID());
429                         break;
430                 case TREESECTION_MONSTERS_COMBAT:
431                         OnSelectAlienCombat(data->ID());
432                         break;
433                 case TREESECTION_MONSTERS_CONSTANTS:
434                         OnSelectAlienConstants(data->ID());
435                         break;
436                 case TREESECTION_MONSTERS_BEHAVIOR:
437                         OnSelectAlienBehavior(data->ID());
438                         break;
439                 case TREESECTION_MONSTERS_IMMUNITIES:
440                         OnSelectAlienImmunities(data->ID());
441                         break;
442                 case TREESECTION_WEAPONS_SETTINGS:
443                         OnSelectWeaponDefinition(data->ID());
444                         break;
445                 case TREESECTION_WEAPONS_TRIGGERS:
446                         OnSelectWeaponTriggers(data->ID());
447                         break;
448                 default:
449                         mainbox->Show(dummy_sizer, true);
450                         break;
451                 }
452
453                 switch (new_section) {
454                 case TREESECTION_MONSTERS:
455                 case TREESECTION_EFFECTS:
456                 case TREESECTION_PROJECTILES:
457                 case TREESECTION_PHYSICS:
458                 case TREESECTION_WEAPONS:
459                         menubar->Enable(EDIT_MENU_COPY, true);
460                         menubar->Enable(EDIT_MENU_PASTE, true);
461                         break;
462                 default:
463                         menubar->Enable(EDIT_MENU_COPY, false);
464                         menubar->Enable(EDIT_MENU_PASTE, false);
465                         break;
466                 }
467
468                 mainbox->Layout();
469         }
470 }
471
472 short PhysicsView::GetSelection() {
473         return static_cast<PhysicsTreeItemData*>(tree->GetItemData(tree->GetSelection()))->ID();
474 }
475
476 template<class T>
477 inline unsigned char* Serialize(T* element, size_t& size)
478 {
479         size = T::kSize;
480         unsigned char* data = new unsigned char[size];
481         BigEndianBuffer buffer(data, size);
482         element->SaveObject(buffer);
483         return data;
484 }
485
486 void PhysicsView::MenuEditCopy(wxCommandEvent&) {
487         if (wxTheClipboard->Open()) {
488
489                 PhysicsTreeItemData* data = static_cast<PhysicsTreeItemData*>(tree->GetItemData(tree->GetSelection()));
490                 PhysicsDocument* document = static_cast<PhysicsDocument*>(GetDocument());
491
492                 if (data) {
493                         size_t size = 0;
494                         unsigned char* buf = 0;
495                         wxDataFormat format;
496
497                         switch (data->Section()) {
498                         case TREESECTION_MONSTERS:
499                                 buf = Serialize(document->GetMonsterDefinition(data->ID()), size);
500                                 format.SetId(wxT("application/vnd.shapefusion.monster"));
501                                 break;
502                         case TREESECTION_EFFECTS:
503                                 buf = Serialize(document->GetEffectDefinition(data->ID()), size);
504                                 format.SetId(wxT("application/vnd.shapefusion.effect"));
505                                 break;
506                         case TREESECTION_PROJECTILES:
507                                 buf = Serialize(document->GetProjectileDefinition(data->ID()), size);
508                                 format.SetId(wxT("application/vnd.shapefusion.projectile"));
509                                 break;
510                         case TREESECTION_PHYSICS:
511                                 buf = Serialize(document->GetPhysicsConstants(data->ID()), size);
512                                 format.SetId(wxT("application/vnd.shapefusion.physics"));
513                                 break;
514                         case TREESECTION_WEAPONS:
515                                 buf = Serialize(document->GetWeaponDefinition(data->ID()), size);
516                                 format.SetId(wxT("application/vnd.shapefusion.weapon"));
517                                 break;
518                         }
519
520                         wxCustomDataObject* dataObject = new wxCustomDataObject(format);
521                         dataObject->TakeData(size, buf);
522                         wxTheClipboard->SetData(dataObject);
523                                 
524                         wxTheClipboard->Close();
525                 }
526         }
527 }
528
529 void PhysicsView::MenuEditPaste(wxCommandEvent&) {
530         if (wxTheClipboard->Open()) {
531                 PhysicsTreeItemData* data = static_cast<PhysicsTreeItemData*>(tree->GetItemData(tree->GetSelection()));
532                 PhysicsDocument* document = static_cast<PhysicsDocument*>(GetDocument());
533                 
534                 if (data) {
535                         wxDataFormat format;
536
537                         switch (data->Section()) {
538                         case TREESECTION_MONSTERS:
539                                 format.SetId(wxT("application/vnd.shapefusion.monster"));
540                                 break;
541                         case TREESECTION_EFFECTS:
542                                 format.SetId(wxT("application/vnd.shapefusion.effect"));
543                                 break;
544                         case TREESECTION_PROJECTILES:
545                                 format.SetId(wxT("application/vnd.shapefusion.projectile"));
546                                 break;
547                         case TREESECTION_PHYSICS:
548                                 format.SetId(wxT("application/vnd.shapefusion.physics"));
549                                 break;
550                         case TREESECTION_WEAPONS:
551                                 format.SetId(wxT("application/vnd.shapefusion.weapon"));
552                                 break;
553
554                         }
555
556                         wxCustomDataObject dataObject(format);
557                         if (wxTheClipboard->GetData(dataObject)) {
558                                 BigEndianBuffer buffer(reinterpret_cast<unsigned char *>(dataObject.GetData()), dataObject.GetSize());
559                                 
560                                 switch (data->Section()) {
561                                 case TREESECTION_MONSTERS:
562                                         document->GetMonsterDefinition(data->ID())->LoadObject(buffer);
563                                         break;
564                                 case TREESECTION_EFFECTS:
565                                         document->GetEffectDefinition(data->ID())->LoadObject(buffer);
566                                         OnSelectEffect(data->ID());
567                                         break;
568                                 case TREESECTION_PROJECTILES:
569                                         document->GetProjectileDefinition(data->ID())->LoadObject(buffer);
570                                         OnSelectShot(data->ID());
571                                         break;
572                                 case TREESECTION_PHYSICS:
573                                         document->GetPhysicsConstants(data->ID())->LoadObject(buffer);
574                                         OnSelectPhysicsConstants(data->ID());
575                                         break;
576                                 case TREESECTION_WEAPONS:
577                                         document->GetWeaponDefinition(data->ID())->LoadObject(buffer);
578                                         break;
579                                 }
580
581                                 document->Modify(true);
582                         }
583                 }
584
585                 wxTheClipboard->Close();
586         }
587 }
588
589 void PhysicsView::EditAlienCheckboxes(wxCommandEvent& e)
590 {
591         MonsterDefinition* monster = static_cast<PhysicsDocument*>(GetDocument())->GetMonsterDefinition(GetSelection());
592
593         int id = e.GetId();
594
595         if (id == CB_ALIEN_SHRAPNEL_ALIEN_DAMAGE) {
596                 monster->GetShrapnelDamage()->SetAlien(e.IsChecked());
597         } else if (id >= CB_ALIEN_FRIENDS && id < CB_ALIEN_ENEMIES) {
598                 monster->SetFriend(id - CB_ALIEN_FRIENDS, e.IsChecked());
599         } else if (id >= CB_ALIEN_ENEMIES && id < CB_ALIEN_FLAGS) {
600                 monster->SetEnemy(id - CB_ALIEN_ENEMIES, e.IsChecked());
601         } else if (id >= CB_ALIEN_FLAGS && id < CB_ALIEN_IMMUNITIES) {
602                 monster->SetFlag(id - CB_ALIEN_FLAGS + 1, e.IsChecked());
603         } else if (id >= CB_ALIEN_IMMUNITIES && id < CB_ALIEN_WEAKNESSES) {
604                 monster->SetImmunity(id - CB_ALIEN_IMMUNITIES, e.IsChecked());
605         } else if (id >= CB_ALIEN_WEAKNESSES && id <= CB_ALIEN_WEAKNESSES + 24) {
606                 monster->SetWeakness(id - CB_ALIEN_WEAKNESSES, e.IsChecked());
607         }
608
609         static_cast<PhysicsDocument*>(GetDocument())->Modify(true);
610 }
611
612 void PhysicsView::EditAlienDoubles(wxCommandEvent& e)
613 {
614         MonsterDefinition* monster = static_cast<PhysicsDocument*>(GetDocument())->GetMonsterDefinition(GetSelection());
615
616         double d = 0.0;
617         if (e.GetString().ToDouble(&d)) {
618                 switch (e.GetId()) {
619                 case FIELD_ALIEN_SOUND_PITCH:
620                         monster->SetSoundPitch(d);
621                         break;
622                 case FIELD_ALIEN_SHRAPNEL_DAMAGE_SCALE:
623                         monster->GetShrapnelDamage()->SetScale(d);
624                         break;
625                 case FIELD_ALIEN_EXT_VELOCITY_SCALE:
626                         monster->SetExternalVelocityScale(d);
627                         break;
628                 }
629         }
630
631         static_cast<PhysicsDocument*>(GetDocument())->Modify(true);
632 }
633
634 void PhysicsView::EditAlienFields(wxCommandEvent& e)
635 {
636         MonsterDefinition* monster = static_cast<PhysicsDocument*>(GetDocument())->GetMonsterDefinition(GetSelection());
637
638         long v = 0;
639         if (e.GetString().ToLong(&v)) {
640                 int id = e.GetId();
641                 AttackDefinition* attack = monster->GetMeleeAttack();
642
643                 if (id >= MENU_ALIEN_ATTACK_TYPE + NUM_ALIEN_ATTACK_CONTROLS && id <= FIELD_ALIEN_ATTACK_DZ + NUM_ALIEN_ATTACK_CONTROLS)
644                 {
645                         id -= NUM_ALIEN_ATTACK_CONTROLS;
646                         attack = monster->GetRangedAttack();
647                 }
648                 
649                 switch (id) {
650                         case FIELD_ALIEN_COLLECTION:
651                                 if (v == -1) {
652                                         monster->SetCollection(31);
653                                         monster->SetColorTable(7);
654                                         alien_collection_field->ChangeValue(wxT("31"));
655                                         alien_color_table_field->ChangeValue(wxT("7"));
656                                 } else {
657                                         monster->SetCollection(v);
658                                 }
659                                 break;
660                         case FIELD_ALIEN_COLOR_TABLE:
661                                 if (v == -1) {
662                                         monster->SetCollection(31);
663                                         monster->SetColorTable(7);
664                                         alien_collection_field->ChangeValue(wxT("31"));
665                                         alien_color_table_field->ChangeValue(wxT("7"));
666                                 } else {
667                                         monster->SetColorTable(v);
668                                 }
669                                 break;
670                         case FIELD_ALIEN_HIT:
671                                 monster->SetHitShapes(v);
672                                 break;
673                         case FIELD_ALIEN_HARD_DYING:
674                                 monster->SetHardDyingShape(v);
675                                 break;
676                         case FIELD_ALIEN_SOFT_DYING:
677                                 monster->SetSoftDyingShape(v);
678                                 break;
679                         case FIELD_ALIEN_HARD_DEAD:
680                                 monster->SetHardDeadShapes(v);
681                                 break;
682                         case FIELD_ALIEN_SOFT_DEAD:
683                                 monster->SetSoftDeadShapes(v);
684                                 break;
685                         case FIELD_ALIEN_STATIONARY:
686                                 monster->SetStationaryShape(v);
687                                 break;
688                         case FIELD_ALIEN_MOVING:
689                                 monster->SetMovingShape(v);
690                                 break;
691                         case FIELD_ALIEN_TELEPORT_IN:
692                                 monster->SetTeleportInShape(v);
693                                 break;
694                         case FIELD_ALIEN_TELEPORT_OUT:
695                                 monster->SetTeleportOutShape(v);
696                                 break;
697                         case FIELD_ALIEN_MELEE_ATTACK_SHAPE:
698                                 monster->GetMeleeAttack()->SetShape(v);
699                                 break;
700                         case FIELD_ALIEN_RANGED_ATTACK_SHAPE:
701                                 monster->GetRangedAttack()->SetShape(v);
702                                 break;
703                         case FIELD_ALIEN_RANDOM_SOUND_MASK:
704                                 monster->SetRandomSoundMask(v);
705                                 break;
706                         case FIELD_ALIEN_ATTACK_FREQUENCY:
707                                 monster->SetAttackFrequency(v);
708                                 break;
709                         case FIELD_ALIEN_ATTACK_REPETITIONS:
710                                 attack->SetRepetitions(v);
711                                 break;
712                         case FIELD_ALIEN_ATTACK_ERROR:
713                                 attack->SetError(v / 512.0 * 360.0);
714                                 break;
715                         case FIELD_ALIEN_ATTACK_RANGE:
716                                 attack->SetRange(v);
717                                 break;
718                         case FIELD_ALIEN_ATTACK_SEQUENCE:
719                                 attack->SetShape(v);
720                                 break;
721                         case FIELD_ALIEN_ATTACK_DX:
722                                 attack->SetDx(v);
723                                 break;
724                         case FIELD_ALIEN_ATTACK_DY:
725                                 attack->SetDy(v);
726                                 break;
727                         case FIELD_ALIEN_ATTACK_DZ:
728                                 attack->SetDz(v);
729                                 break;
730                         case FIELD_ALIEN_SHRAPNEL_RADIUS:
731                                 monster->SetShrapnelRadius(v);
732                                 break;
733                         case FIELD_ALIEN_SHRAPNEL_BASE_DAMAGE:
734                                 monster->GetShrapnelDamage()->SetBase(v);
735                                 break;
736                         case FIELD_ALIEN_SHRAPNEL_RANDOM_DAMAGE:
737                                 monster->GetShrapnelDamage()->SetRandom(v);
738                                 break;
739                         case FIELD_ALIEN_VITALITY:
740                                 monster->SetVitality(v);
741                                 break;
742                         case FIELD_ALIEN_RADIUS:
743                                 monster->SetRadius(v);
744                                 break;
745                         case FIELD_ALIEN_HEIGHT:
746                                 monster->SetHeight(v);
747                                 break;
748                         case FIELD_ALIEN_SPEED:
749                                 monster->SetSpeed(v);
750                                 break;
751                         case FIELD_ALIEN_TERMINAL_VELOCITY:
752                                 monster->SetTerminalVelocity(v);
753                                 break;
754                         case FIELD_ALIEN_GRAVITY:
755                                 monster->SetGravity(v);
756                                 break;                          
757                         case FIELD_ALIEN_MIN_LEDGE_JUMP:
758                                 monster->SetMinimumLedgeDelta(v);
759                                 break;
760                         case FIELD_ALIEN_MAX_LEDGE_JUMP:
761                                 monster->SetMaximumLedgeDelta(v);
762                                 break;
763                         case FIELD_ALIEN_HOVER_HEIGHT:
764                                 monster->SetPreferredHoverHeight(v);
765                                 break;
766                         case FIELD_ALIEN_DOOR_RETRY_MASK:
767                                 monster->SetDoorRetryMask(v);
768                                 break;
769                         case FIELD_ALIEN_VISUAL_RANGE:
770                                 monster->SetVisualRange(v);
771                                 break;
772                         case FIELD_ALIEN_DARK_VISUAL_RANGE:
773                                 monster->SetDarkVisualRange(v);
774                                 break;
775                         case FIELD_ALIEN_INTELLIGENCE:
776                                 monster->SetIntelligence(v);
777                                 break;          
778                 }
779         }
780
781         static_cast<PhysicsDocument*>(GetDocument())->Modify(true);
782 }
783
784 void PhysicsView::EditAlienMenus(wxCommandEvent& e)
785 {
786         MonsterDefinition* monster = static_cast<PhysicsDocument*>(GetDocument())->GetMonsterDefinition(GetSelection());
787         
788         switch (e.GetId()) {
789         case MENU_ALIEN_ACTIVATION:
790                 monster->SetActivationSound(e.GetSelection() - 1);
791                 break;
792         case MENU_ALIEN_FRIENDLY_ACTIVATION:
793                 monster->SetFriendlyActivationSound(e.GetSelection() - 1);
794                 break;
795         case MENU_ALIEN_CLEAR:
796                 monster->SetClearSound(e.GetSelection() - 1);
797                 break;
798         case MENU_ALIEN_KILL:
799                 monster->SetKillSound(e.GetSelection() - 1);
800                 break;
801         case MENU_ALIEN_APOLOGY:
802                 monster->SetApologySound(e.GetSelection() - 1);
803                 break;
804         case MENU_ALIEN_FRIENDLY_FIRE:
805                 monster->SetFriendlyFireSound(e.GetSelection() - 1);
806                 break;
807         case MENU_ALIEN_FLAMING:
808                 monster->SetFlamingSound(e.GetSelection() - 1);
809                 break;
810         case MENU_ALIEN_RANDOM:
811                 monster->SetRandomSound(e.GetSelection() - 1);
812                 break;
813         case MENU_ALIEN_ATTACK_TYPE:
814                 monster->GetMeleeAttack()->SetType(e.GetSelection() - 1);
815                 break;
816         case MENU_ALIEN_ATTACK_TYPE + NUM_ALIEN_ATTACK_CONTROLS:
817                 monster->GetRangedAttack()->SetType(e.GetSelection() - 1);
818                 break;
819         case MENU_ALIEN_SHRAPNEL_DAMAGE_TYPE:
820                 monster->GetShrapnelDamage()->SetType(e.GetSelection() - 1);
821                 break;
822         case MENU_ALIEN_RANGED_IMPACT_EFFECT:
823                 monster->SetImpactEffect(e.GetSelection() - 1);
824                 break;
825         case MENU_ALIEN_MELEE_IMPACT_EFFECT:
826                 monster->SetMeleeImpactEffect(e.GetSelection() - 1);
827                 break;
828         case MENU_ALIEN_CARRYING_ITEM:
829                 monster->SetCarryingItemType(e.GetSelection() - 1);
830                 break;
831         case MENU_ALIEN_CONTRAIL_EFFECT:
832                 monster->SetContrailEffect(e.GetSelection() - 1);
833                 break;
834         case MENU_ALIEN_CLASS:
835                 monster->SetClass(1 << e.GetSelection());
836                 break;
837         }
838
839         static_cast<PhysicsDocument*>(GetDocument())->Modify(true);
840 }
841
842 void PhysicsView::EditEffectCheckboxes(wxCommandEvent& e)
843 {
844         EffectDefinition* effect = static_cast<PhysicsDocument*>(GetDocument())->GetEffectDefinition(GetSelection());
845         
846         switch (e.GetId()) {
847         case CB_EFFECT_END_WHEN_ANIMATION_LOOPS:
848                 effect->SetEndWhenAnimationLoops(e.IsChecked());
849                 break;
850         case CB_EFFECT_END_WHEN_TRANSFER_ANIMATION_LOOPS:
851                 effect->SetEndWhenTransferAnimationLoops(e.IsChecked());
852                 break;
853         case CB_EFFECT_SOUND_ONLY:
854                 effect->SetSoundOnly(e.IsChecked());
855                 break;
856         case CB_EFFECT_MEDIA_EFFECT:
857                 effect->SetMediaEffect(e.IsChecked());
858                 break;
859         }
860
861         static_cast<PhysicsDocument*>(GetDocument())->Modify(true);     
862 }
863
864 void PhysicsView::EditEffectDoubles(wxCommandEvent& e)
865 {
866         EffectDefinition* effect = static_cast<PhysicsDocument*>(GetDocument())->GetEffectDefinition(GetSelection());
867
868         double d = 0.0;
869         if (e.GetString().ToDouble(&d)) {
870                 switch (e.GetId()) {
871                 case FIELD_EFFECT_PITCH:
872                         effect->SetSoundPitch(d);
873                         break;
874                 }
875         }
876
877         static_cast<PhysicsDocument*>(GetDocument())->Modify(true);     
878 }
879
880 void PhysicsView::EditEffectFields(wxCommandEvent& e)
881 {
882         EffectDefinition* effect = static_cast<PhysicsDocument*>(GetDocument())->GetEffectDefinition(GetSelection());
883
884         long v = 0;
885         if (e.GetString().ToLong(&v)) {
886                 switch (e.GetId()) {
887                 case FIELD_EFFECT_COLLECTION:
888                         if (v == -1) {
889                                 effect->SetCollection(31);
890                                 effect->SetColorTable(7);
891                                 eff_collection_field->ChangeValue(wxT("31"));
892                                 eff_color_table_field->ChangeValue(wxT("7"));
893                         } else {
894                                 effect->SetCollection(v);
895                         }
896                         break;
897                 case FIELD_EFFECT_COLOR_TABLE:
898                         if (v == -1) {
899                                 effect->SetCollection(31);
900                                 effect->SetColorTable(7);
901                                 eff_collection_field->ChangeValue(wxT("31"));
902                                 eff_color_table_field->ChangeValue(wxT("7"));
903                         } else {
904                                 effect->SetColorTable(v);
905                         }
906                         break;
907                 case FIELD_EFFECT_SEQUENCE:
908                         effect->SetShape(v);
909                         break;
910                 }
911         }
912
913         static_cast<PhysicsDocument*>(GetDocument())->Modify(true);
914 }
915
916 void PhysicsView::EditEffectMenus(wxCommandEvent& e)
917 {
918         EffectDefinition* effect = static_cast<PhysicsDocument*>(GetDocument())->GetEffectDefinition(GetSelection());
919
920         switch (e.GetId()) {
921         case MENU_EFFECT_DELAY_SOUND:
922                 effect->SetDelaySound(e.GetSelection() - 1);
923                 break;
924         }
925
926         static_cast<PhysicsDocument*>(GetDocument())->Modify(true);
927 }
928
929 void PhysicsView::EditShotCheckboxes(wxCommandEvent& e)
930 {
931         ProjectileDefinition* projectile = static_cast<PhysicsDocument*>(GetDocument())->GetProjectileDefinition(GetSelection());
932         
933         if (e.GetId() == CB_SHOT_ALIEN_DAMAGE) {
934                 projectile->GetDamage()->SetAlien(e.IsChecked());
935         } else if (e.GetId() >= CB_SHOT_FLAGS && e.GetId() < CB_SHOT_FLAGS + 22) {
936                 projectile->SetFlag(e.GetId() - CB_SHOT_FLAGS, e.IsChecked());
937         }
938         
939         static_cast<PhysicsDocument*>(GetDocument())->Modify(true);
940 }
941
942 void PhysicsView::EditShotFields(wxCommandEvent& e)
943 {
944         ProjectileDefinition* projectile = static_cast<PhysicsDocument*>(GetDocument())->GetProjectileDefinition(GetSelection());
945
946         long v = 0;
947         if (e.GetString().ToLong(&v)) {
948                 switch (e.GetId()) {
949                 case FIELD_SHOT_COLLECTION:
950                         if (v == -1) {
951                                 projectile->SetCollection(31);
952                                 projectile->SetColorTable(7);
953                                 shots_collection_field->ChangeValue(wxT("31"));
954                                 shots_color_table_field->ChangeValue(wxT("7"));
955                         } else {
956                                 projectile->SetCollection(v);
957                         }
958                         break;
959                 case FIELD_SHOT_COLOR_TABLE:
960                         if (v == -1) {
961                                 projectile->SetCollection(31);
962                                 projectile->SetColorTable(7);
963                                 shots_collection_field->ChangeValue(wxT("31"));
964                                 shots_color_table_field->ChangeValue(wxT("7"));
965                         } else {
966                                 projectile->SetColorTable(v);
967                         }
968                         break;
969                 case FIELD_SHOT_SEQUENCE:
970                         projectile->SetShape(v);
971                         break;
972                 case FIELD_SHOT_DAMAGE_BASE:
973                         projectile->GetDamage()->SetBase(v);
974                         break;
975                 case FIELD_SHOT_DAMAGE_RANDOM:
976                         projectile->GetDamage()->SetRandom(v);
977                         break;
978                 case FIELD_SHOT_RADIUS:
979                         projectile->SetRadius(v);
980                         break;
981                 case FIELD_SHOT_AREA_OF_EFFECT:
982                         projectile->SetAreaOfEffect(v);
983                         break;
984                 case FIELD_SHOT_SPEED:
985                         projectile->SetSpeed(v);
986                         break;
987                 case FIELD_SHOT_RANGE:
988                         projectile->SetMaximumRange(v);
989                         break;
990                 case FIELD_SHOT_CONTRAIL_TICKS:
991                         projectile->SetTicksBetweenContrails(v);
992                         break;
993                 case FIELD_SHOT_MAXIMUM_CONTRAILS:
994                         projectile->SetMaximumContrails(v);
995                         break;
996                 }
997         }
998         static_cast<PhysicsDocument*>(GetDocument())->Modify(true);
999 }
1000
1001 void PhysicsView::EditShotDoubles(wxCommandEvent& e)
1002 {
1003         ProjectileDefinition* projectile = static_cast<PhysicsDocument*>(GetDocument())->GetProjectileDefinition(GetSelection());
1004         
1005         double d = 0.0;
1006
1007         if (e.GetString().ToDouble(&d)) {
1008                 switch (e.GetId()) {
1009                 case FIELD_SHOT_DAMAGE_SCALE:
1010                         projectile->GetDamage()->SetScale(d);
1011                         break;
1012                 case FIELD_SHOT_SOUND_PITCH:
1013                         projectile->SetSoundPitch(d);
1014                         break;
1015                 }
1016         }
1017
1018         static_cast<PhysicsDocument*>(GetDocument())->Modify(true);
1019 }
1020
1021 void PhysicsView::EditShotMenus(wxCommandEvent& e)
1022 {
1023         ProjectileDefinition* projectile = static_cast<PhysicsDocument*>(GetDocument())->GetProjectileDefinition(GetSelection());
1024
1025         switch (e.GetId()) {
1026         case MENU_SHOT_DAMAGE_TYPE:
1027                 projectile->GetDamage()->SetType(e.GetSelection() - 1);
1028                 break;
1029         case MENU_SHOT_FLYBY_SOUND:
1030                 projectile->SetFlybySound(e.GetSelection() - 1);
1031                 break;
1032         case MENU_SHOT_REBOUND_SOUND:
1033                 projectile->SetReboundSound(e.GetSelection() - 1);
1034                 break;
1035         case MENU_SHOT_DETONATION_EFFECT:
1036                 projectile->SetDetonationEffect(e.GetSelection() - 1);
1037                 break;
1038         case MENU_SHOT_MEDIA_DETONATION_EFFECT:
1039                 projectile->SetMediaDetonationEffect(e.GetSelection() - 1);
1040                 break;
1041         case MENU_SHOT_CONTRAIL:
1042                 projectile->SetContrailEffect(e.GetSelection() - 1);
1043                 break;
1044         case MENU_SHOT_MEDIA_IMPACT:
1045                 projectile->SetMediaProjectilePromotion(e.GetSelection() - 1);
1046                 break;
1047         }
1048
1049         static_cast<PhysicsDocument*>(GetDocument())->Modify(true);     
1050 }
1051
1052 void PhysicsView::EditPhysicsConstants(wxCommandEvent& e)
1053 {
1054         PhysicsConstants* constants = static_cast<PhysicsDocument*>(GetDocument())->GetPhysicsConstants(GetSelection());
1055
1056         double d = 0.0;
1057         if (e.GetString().ToDouble(&d)) {
1058                 switch (e.GetId()) {
1059                 case FIELD_MAX_FORWARD_VELOCITY:
1060                         constants->SetMaximumForwardVelocity(d);
1061                         break;
1062                 case FIELD_MAX_BACKWARD_VELOCITY:
1063                         constants->SetMaximumBackwardVelocity(d);
1064                         break;
1065                 case FIELD_MAX_PERPENDICULAR_VELOCITY:
1066                         constants->SetMaximumPerpendicularVelocity(d);
1067                         break;
1068
1069                 case FIELD_ACCELERATION:
1070                         constants->SetAcceleration(d);
1071                         break;
1072                 case FIELD_DECELERATION:
1073                         constants->SetDeceleration(d);
1074                         break;
1075                 case FIELD_AIRBORNE_DECELERATION:
1076                         constants->SetAirborneDeceleration(d);
1077                         break;
1078                 case FIELD_GRAVITATIONAL_ACCELERATION:
1079                         constants->SetGravitationalAcceleration(d);
1080                         break;
1081                 case FIELD_CLIMBING_ACCELERATION:
1082                         constants->SetClimbingAcceleration(d);
1083                         break;
1084                 case FIELD_TERMINAL_VELOCITY:
1085                         constants->SetTerminalVelocity(d);
1086                         break;
1087                 case FIELD_EXTERNAL_DECELERATION:
1088                         constants->SetExternalDeceleration(d);
1089                         break;
1090
1091                 case FIELD_STEP_DELTA:
1092                         constants->SetStepDelta(d);
1093                         break;
1094                 case FIELD_STEP_AMPLITUDE:
1095                         constants->SetStepAmplitude(d);
1096                         break;
1097
1098                 case FIELD_RADIUS:
1099                         constants->SetRadius(d);
1100                         break;
1101                 case FIELD_HEIGHT:
1102                         constants->SetHeight(d);
1103                         break;
1104
1105                 case FIELD_ANGULAR_ACCELERATION:
1106                         constants->SetAngularAcceleration(d);
1107                         break;
1108                 case FIELD_ANGULAR_DECELERATION:
1109                         constants->SetAngularDeceleration(d);
1110                         break;
1111                 case FIELD_MAXIMUM_ANGULAR_VELOCITY:
1112                         constants->SetMaximumAngularVelocity(d);
1113                         break;
1114                 case FIELD_ANGULAR_RECENTERING_VELOCITY:
1115                         constants->SetAngularRecenteringVelocity(d);
1116                         break;
1117                 case FIELD_HEAD_ANGULAR_VELOCITY:
1118                         constants->SetFastAngularVelocity(d);
1119                         break;
1120                 case FIELD_HEAD_ANGULAR_MAXIMUM:
1121                         constants->SetFastAngularMaximum(d);
1122                         break;
1123                 case FIELD_MAXIMUM_ELEVATION:
1124                         constants->SetMaximumElevation(d);
1125                         break;
1126                 case FIELD_EXTERNAL_ANGULAR_DECELERATION:
1127                         constants->SetExternalAngularDeceleration(d);
1128                         break;
1129
1130                 case FIELD_DEAD_HEIGHT:
1131                         constants->SetDeadHeight(d);
1132                         break;
1133                 case FIELD_CAMERA_HEIGHT:
1134                         constants->SetCameraHeight(d);
1135                         break;
1136                 case FIELD_SPLASH_HEIGHT:
1137                         constants->SetSplashHeight(d);
1138                         break;
1139                 case FIELD_HALF_CAMERA_SEPARATION:
1140                         constants->SetHalfCameraSeparation(d);
1141                         break;
1142                 }
1143         }
1144         
1145         static_cast<PhysicsDocument*>(GetDocument())->Modify(true);     
1146 }
1147
1148 void PhysicsView::EditWeaponCheckboxes(wxCommandEvent& e)
1149 {
1150         WeaponDefinition* weapon = static_cast<PhysicsDocument*>(GetDocument())->GetWeaponDefinition(GetSelection());
1151
1152         int flag = e.GetId() - CB_WEAPON_FLAGS;
1153         
1154         weapon->SetFlag(flag >= 5 ? flag + 1: flag, e.IsChecked());
1155
1156         static_cast<PhysicsDocument*>(GetDocument())->Modify(true);     
1157 }
1158
1159 void PhysicsView::EditWeaponFields(wxCommandEvent& e)
1160 {
1161         WeaponDefinition* weapon = static_cast<PhysicsDocument*>(GetDocument())->GetWeaponDefinition(GetSelection());
1162
1163         long v = 0;
1164         if (e.GetString().ToLong(&v)) {
1165                 switch (e.GetId()) {
1166                 case FIELD_WEAPON_COLLECTION:
1167                         if (v == -1) {
1168                                 weapon->SetCollection(31);
1169                                 weapon->SetColorTable(7);
1170                                 weapon_collection_field->ChangeValue(wxT("31"));
1171                                 weapon_color_table_field->ChangeValue(wxT("7"));
1172                         } else {
1173                                 weapon->SetCollection(v);
1174                         }
1175                         break;
1176                 case FIELD_WEAPON_COLOR_TABLE:
1177                         if (v == -1) {
1178                                 weapon->SetCollection(31);
1179                                 weapon->SetColorTable(7);
1180                                 weapon_collection_field->ChangeValue(wxT("31"));
1181                                 weapon_color_table_field->ChangeValue(wxT("7"));
1182                         } else {
1183                                 weapon->SetColorTable(v);
1184                         }
1185                         break;
1186                 case FIELD_WEAPON_IDLE:
1187                         weapon->SetIdleShape(v);
1188                         break;
1189                 case FIELD_WEAPON_FIRING:
1190                         weapon->SetFiringShape(v);
1191                         break;
1192                 case FIELD_WEAPON_RELOADING:
1193                         weapon->SetReloadingShape(v);
1194                         break;
1195                 case FIELD_WEAPON_CHARGING:
1196                         weapon->SetChargingShape(v);
1197                         break;
1198                 case FIELD_WEAPON_CHARGED:
1199                         weapon->SetChargedShape(v);
1200                         break;
1201                 case FIELD_WEAPON_READY:
1202                         weapon->SetReadyTicks(v);
1203                         break;
1204                 case FIELD_WEAPON_AWAIT_RELOAD:
1205                         weapon->SetAwaitReloadTicks(v);
1206                         break;
1207                 case FIELD_WEAPON_LOADING:
1208                         weapon->SetLoadingTicks(v);
1209                         break;
1210                 case FIELD_WEAPON_FINISH_LOADING:
1211                         weapon->SetFinishLoadingTicks(v);
1212                         break;
1213                 case FIELD_WEAPON_FLASH_DECAY:
1214                         weapon->SetFiringIntensityDecayTicks(v);
1215                         break;
1216                 }
1217         }
1218
1219         static_cast<PhysicsDocument*>(GetDocument())->Modify(true);     
1220
1221 }
1222
1223 void PhysicsView::EditWeaponDoubles(wxCommandEvent& e)
1224 {
1225         WeaponDefinition* weapon = static_cast<PhysicsDocument*>(GetDocument())->GetWeaponDefinition(GetSelection());
1226
1227         double d = 0.0;
1228         if (e.GetString().ToDouble(&d)) {
1229                 switch (e.GetId()) {
1230                 case FIELD_WEAPON_FLASH_INTENSITY:
1231                         weapon->SetFiringLightIntensity(d);
1232                         break;
1233                 case FIELD_WEAPON_IDLE_HEIGHT:
1234                         weapon->SetIdleHeight(d);
1235                         break;
1236                 case FIELD_WEAPON_BOB_AMPLITUDE:
1237                         weapon->SetBobAmplitude(d);
1238                         break;
1239                 case FIELD_WEAPON_KICK_HEIGHT:
1240                         weapon->SetKickHeight(d);
1241                         break;
1242                 case FIELD_WEAPON_RELOAD_HEIGHT:
1243                         weapon->SetReloadHeight(d);
1244                         break;
1245                 case FIELD_WEAPON_IDLE_WIDTH:
1246                         weapon->SetIdleWidth(d);
1247                         break;
1248                 }
1249         }
1250
1251         static_cast<PhysicsDocument*>(GetDocument())->Modify(true);     
1252 }
1253
1254 void PhysicsView::EditWeaponMenus(wxCommandEvent& e)
1255 {
1256         WeaponDefinition* weapon = static_cast<PhysicsDocument*>(GetDocument())->GetWeaponDefinition(GetSelection());
1257
1258         switch (e.GetId()) {
1259         case MENU_WEAPON_ITEM_TYPE:
1260                 weapon->SetItemType(e.GetSelection() - 1);
1261                 break;
1262         case MENU_WEAPON_CLASS:
1263                 weapon->SetWeaponClass(e.GetSelection() - 1);
1264                 break;
1265         }
1266
1267         static_cast<PhysicsDocument*>(GetDocument())->Modify(true);     
1268 }
1269
1270 void PhysicsView::EditTriggerFields(wxCommandEvent& e)
1271 {
1272         WeaponDefinition* weapon = static_cast<PhysicsDocument*>(GetDocument())->GetWeaponDefinition(GetSelection());
1273
1274         long v = 0;
1275         if (e.GetString().ToLong(&v)) {
1276                 int id = e.GetId();
1277                 TriggerDefinition* trigger = weapon->GetPrimaryTrigger();
1278
1279                 if (id >= FIELD_TRIGGER_ROUNDS + NUM_TRIGGER_IDS) {
1280                         id -= NUM_TRIGGER_IDS;
1281                         trigger = weapon->GetSecondaryTrigger();
1282                 }
1283
1284                 switch (id) {
1285                 case FIELD_TRIGGER_ROUNDS:
1286                         trigger->SetRoundsPerMagazine(v);
1287                         break;
1288                 case FIELD_TRIGGER_TICKS:
1289                         trigger->SetTicksPerRound(v);
1290                         break;
1291                 case FIELD_TRIGGER_RECOVERY:
1292                         trigger->SetRecoveryTicks(v);
1293                         break;
1294                 case FIELD_TRIGGER_CHARGING:
1295                         trigger->SetChargingTicks(v);
1296                         break;
1297                 case FIELD_TRIGGER_RECOIL:
1298                         trigger->SetRecoilMagnitude(v);
1299                         break;
1300                 case FIELD_TRIGGER_THETA:
1301                         trigger->SetThetaError(v);
1302                         break;
1303                 case FIELD_TRIGGER_DX:
1304                         trigger->SetDx(v);
1305                         break;
1306                 case FIELD_TRIGGER_DZ:
1307                         trigger->SetDz(v);
1308                         break;
1309                 case FIELD_TRIGGER_BURST_COUNT:
1310                         trigger->SetBurstCount(v);
1311                         break;
1312                 }
1313         }
1314
1315         static_cast<PhysicsDocument*>(GetDocument())->Modify(true);
1316 }
1317
1318 void PhysicsView::EditTriggerMenus(wxCommandEvent& e)
1319 {
1320         WeaponDefinition* weapon = static_cast<PhysicsDocument*>(GetDocument())->GetWeaponDefinition(GetSelection());
1321
1322         int id = e.GetId();
1323         TriggerDefinition* trigger = weapon->GetPrimaryTrigger();
1324         
1325         if (id >= FIELD_TRIGGER_ROUNDS + NUM_TRIGGER_IDS) {
1326                 id -= NUM_TRIGGER_IDS;
1327                 trigger = weapon->GetSecondaryTrigger();
1328         }
1329
1330         switch (id) {
1331         case MENU_TRIGGER_PROJECTILE:
1332                 trigger->SetProjectileType(e.GetSelection() - 1);
1333                 break;
1334         case MENU_TRIGGER_AMMO_TYPE:
1335                 trigger->SetAmmunitionType(e.GetSelection() - 1);
1336                 break;
1337         case MENU_TRIGGER_FIRING:
1338                 trigger->SetFiringSound(e.GetSelection() - 1);
1339                 break;
1340         case MENU_TRIGGER_CLICK:
1341                 trigger->SetClickSound(e.GetSelection() - 1);
1342                 break;
1343         case MENU_TRIGGER_CHARGING:
1344                 trigger->SetChargingSound(e.GetSelection() - 1);
1345                 break;
1346         case MENU_TRIGGER_SHELL_CASING:
1347                 trigger->SetShellCasingSound(e.GetSelection() - 1);
1348                 break;
1349         case MENU_TRIGGER_RELOADING:
1350                 trigger->SetReloadingSound(e.GetSelection() - 1);
1351                 break;
1352         case MENU_TRIGGER_CHARGED:
1353                 trigger->SetChargedSound(e.GetSelection() - 1);
1354                 break;
1355         case MENU_TRIGGER_SHELL_CASING_TYPE:
1356                 trigger->SetShellCasingType(e.GetSelection() - 1);
1357                 break;
1358         }
1359
1360         static_cast<PhysicsDocument*>(GetDocument())->Modify(true);
1361 }