Implement Fire1 animation and camera effect

Implement RotateAroundFocus camera opcode
This commit is contained in:
ficedula 2023-12-01 11:06:35 +00:00
parent 8b3f632359
commit 6692cefc6d
9 changed files with 95 additions and 7 deletions

View File

@ -49,6 +49,8 @@ namespace Braver.Battle {
public bool DamageMP { get; set; }
public int MPTurboLevel { get; set; }
public bool IsRestore { get; set; }
public int? SingleTargetCamera { get; set; }
public int? MultiTargetCamera { get; set; }
public bool HasElement(Element e) {
if (e == Element.None)
@ -166,6 +168,8 @@ namespace Braver.Battle {
MAtPercent = attack.AttackPC,
PAtPercent = attack.AttackPC,
NoSplit = noSplit,
SingleTargetCamera = attack.SingleTargetCameraID,
MultiTargetCamera = attack.MultiTargetCameraID,
};
}

View File

@ -82,6 +82,19 @@ namespace Braver.Battle {
IEnumerable<ICharacterAction> Actions { get; }
}
public static class MenuSourceUtil {
public static IEnumerable<ICharacterAction> AllActions(this IMenuSource menu) {
foreach(var action in menu.Actions) {
if (action.Ability != null)
yield return action;
if (action is IMenuSource subMenu) {
foreach (var child in subMenu.Actions.Where(a => a.Ability != null))
yield return child;
}
}
}
}
public class CharacterActionItem : ICharacterAction {
public int ID { get; set; }
public Ability Ability { get; set; }
@ -145,6 +158,7 @@ namespace Braver.Battle {
LongRange = !weapon.TargettingFlags.HasFlag(TargettingFlags.ShortRange),
InflictStatus = weapon.Statuses,
Formula = AttackFormula.Physical, //TODO
//TODO camera?!?!?!
},
TargetFlags = weapon.TargettingFlags,
});
@ -193,6 +207,8 @@ namespace Braver.Battle {
InflictStatus = a.Item.StatusType == AttackStatusType.Inflict ? a.Item.Statuses : Statuses.None,
RemoveStatus = a.Item.StatusType == AttackStatusType.Cure ? a.Item.Statuses : Statuses.None,
ToggleStatus = a.Item.StatusType == AttackStatusType.Toggle ? a.Item.Statuses : Statuses.None,
SingleTargetCamera = a.Item.CameraMovementID,
MultiTargetCamera = a.Item.CameraMovementID, //TODO - verify it's correct for both single and multi?
},
TargetFlags = a.Item.TargettingFlags,
Name = a.Item.Name,

View File

@ -65,9 +65,11 @@ namespace Braver.Battle {
else {
var model = _screen.Renderer.Models[_source];
if ((byte)op.Value.Op < 0x8E) {
model.PlayAnimation((byte)op.Value.Op, false, 1f, onlyIfDifferent: false);
if (model.AnimationState.Animation != (byte)op.Value.Op)
model.PlayAnimation((byte)op.Value.Op, false, 1f, onlyIfDifferent: false);
int countNow = model.AnimationState.CompletionCount;
_paused = true;
_shouldContinue = () => model.AnimationState.CompletionCount > 0;
_shouldContinue = () => model.AnimationState.CompletionCount > countNow;
WaitingFor = WaitingForKind.Animation;
} else {
@ -102,6 +104,10 @@ namespace Braver.Battle {
WaitingFor = WaitingForKind.Action;
break;
case AnimScriptOp.RunIdleAnimScript:
_screen.UpdateVisualState(_source);
break;
default:
System.Diagnostics.Trace.WriteLine($"Skipping unimplemented op {op.Value.Op}");
break;

View File

@ -55,8 +55,10 @@ namespace Braver.Battle {
_sprites.FrameStep();
if (_effect != null) {
_effect.Step();
if (_effect.IsComplete)
if (_effect.IsComplete) {
_screen.CameraController.ResetToIdleCamera();
_effect = null;
}
}
}
@ -107,9 +109,11 @@ namespace Braver.Battle {
_sprites.Add(sprite, () => _screen.GetModelScreenPos(_engine.ActiveCombatants.ElementAt(_cMenu)));
*/
var source = _engine.ActiveCombatants.ElementAt(_cMenu);
var fire1 = (source as CharacterCombatant).AllActions()
.SingleOrDefault(a => a.Name == "Fire");
var action = new QueuedAction(
source,
(source as CharacterCombatant).Actions.Select(a => a.Ability).First(a => a.HasValue).Value,
fire1.Ability.Value,
_engine.ActiveCombatants.Where(c => !c.IsPlayer).ToArray(),
ActionPriority.Normal,
"Fire1"

View File

@ -92,6 +92,7 @@ namespace Braver.Battle {
_executor[EffectCommand.DeathFade] = (effect, parms) => effect.CmdDeathFade(parms);
_executor[EffectCommand.ApplyResults] = (effect, parms) => effect.CmdApplyResults(parms);
_executor[EffectCommand.DisplayText] = (effect, parms) => effect.CmdDisplayText(parms);
_executor[EffectCommand.Camera] = (effect, parms) => effect.CmdCamera(parms);
}
private IWaitableEffect WaitableFromInProgress(IEnumerable<IInProgress> effects) {
@ -211,6 +212,28 @@ namespace Braver.Battle {
};
}
private IWaitableEffect CmdCamera(IEnumerable<string> parms) {
int id;
var source = _models["source"];
var targets = _models.Values.Where(c => c != source).Select(c => _screen.Renderer.Models[c]);
if (parms.First().Equals("auto")) {
id = (targets.Count() > 1 ? _action.Ability.MultiTargetCamera : _action.Ability.SingleTargetCamera) ?? 0;
} else
id = int.Parse(parms.First());
bool isDone = false;
_screen.CameraController.Execute(
id,
_screen.Renderer.Models[source],
targets,
() => isDone = true
);
return new CallbackWaitEffect {
CheckComplete = () => isDone
};
}
private IWaitableEffect CmdSfx(IEnumerable<string> parms) {
int id = int.Parse(parms.First());
//TODO - 3d position

View File

@ -51,6 +51,8 @@ namespace Braver.Battle {
}
public void ResetToIdleCamera() {
_getPosition = null;
_getFocus = null;
var cam = _cameras[_idleCamera];
_view = cam.ToView3D();
_game.Net.Send(new SetBattleCameraMessage { Camera = cam });
@ -122,7 +124,23 @@ namespace Braver.Battle {
//We want to run our camera transitions at 60fps
private const int FRAME_MULTIPLIER = 2;
private Func<Vector3> GetRotateTransition(Vector3 rotateAround, Vector3 offset,
float initialRotation, float rotateIncrement, int frames) {
int frame = 0;
return () => {
float rotation = initialRotation + rotateIncrement * frame;
var transform = Matrix.CreateRotationY(rotation * (float)Math.PI / 2048);
var rotated = Vector3.Transform(offset, transform);
if (frame < frames) frame++;
return rotateAround - rotated;
};
}
private bool Execute(DecodedCameraOp<CameraPositionOpcode> op) {
Trace.WriteLine($"Position {op.Opcode} {string.Join(" ", op.Operands ?? Enumerable.Empty<int>())}");
switch (op.Opcode) {
case CameraPositionOpcode.InterpolateModeSmooth:
_transitionPos = TransitionKind.Smooth;
@ -131,6 +149,14 @@ namespace Braver.Battle {
_transitionPos = TransitionKind.Linear;
return true;
case CameraPositionOpcode.RotateAroundFocus:
_getPosition = GetRotateTransition(
_view.CameraPosition + _view.CameraForwards,
new Vector3(op.Operands[0], op.Operands[1], op.Operands[2]),
op.Operands[3], op.Operands[4], op.Operands[5]
);
return true;
case CameraPositionOpcode.JumpToAttackerJoint:
int bone = op.Operands[0];
Vector3 offset = new Vector3(op.Operands[1], op.Operands[2], op.Operands[3]);
@ -200,6 +226,7 @@ namespace Braver.Battle {
}
}
private bool Execute(DecodedCameraOp<CameraFocusOpcode> op) {
Trace.WriteLine($"Focus {op.Opcode} {string.Join(" ", op.Operands ?? Enumerable.Empty<int>())}");
switch (op.Opcode) {
case CameraFocusOpcode.InterpolateModeSmooth:
_transitionFocus = TransitionKind.Smooth;

View File

@ -126,6 +126,14 @@ namespace Braver.UI {
case 3:
Game.NewGame();
Game.SaveData.Characters[1].WeaponMateria[0] = new OwnedMateria {
AP = 0,
MateriaID = 49, //grant fire for testing
};
Game.SaveData.Characters[2].WeaponMateria[0] = new OwnedMateria {
AP = 0,
MateriaID = 49, //grant fire for testing
};
//Game.PushScreen(new TestScreen());
//Game.ChangeScreen(this, new TestScreen());
//Game.ChangeScreen(this, new WorldMap.WMScreen(139348, 126329));

View File

@ -189,7 +189,7 @@ namespace Ficedula.FF7.Battle {
[CameraPositionOpcode.UnknownF3] = new[] { 1, 2, 2 },
[CameraPositionOpcode.SetWait] = new[] { 1 },
[CameraPositionOpcode.UnknownF7] = new[] { 1, 2, 2, 2 },
[CameraPositionOpcode.UnknownF8] = new[] { 2, 2, 2, 2, 2, 2 },
[CameraPositionOpcode.RotateAroundFocus] = new[] { 2, 2, 2, 2, 2, 2 },
[CameraPositionOpcode.LoadPoint] = new[] { 2, 2, 2 },
};
}
@ -269,7 +269,7 @@ namespace Ficedula.FF7.Battle {
Wait = 0xF4,
SetWait = 0xF5,
UnknownF7 = 0xF7,
UnknownF8 = 0xF8,
RotateAroundFocus = 0xF8,
LoadPoint = 0xF9,
ConditionalRestart = 0xFE,
ScriptEnd = 0xFF,

View File

@ -6,9 +6,9 @@ PreloadSfx 8
@:Wait !txt
}
Camera 36
!cast Anim source 17
Wait !cast
#Camera
Sfx 8
@foreach(var result in Model.Results) {