/*/// <summary> * /// attempt at adding this to the combatObject. it's not working too well though. * /// </summary> * /// <param name="battletick"></param> * /// <param name="attacker"></param> * /// <param name="weapon"></param> * /// <param name="Sector"></param> * /// <param name="IsReplay"></param> * /// <returns></returns> * * public CombatTakeFireEvent FireWeapon(int battletick, CombatObject attacker, CombatWeapon weapon, Space.Sector Sector, bool IsReplay) * { * var wpninfo = weapon.weapon.Template.ComponentTemplate.WeaponInfo; * Fix16 rangeForDamageCalcs = (Fix16)0; * Fix16 rangetotarget = Trig.distance(attacker.cmbt_loc, this.cmbt_loc); * int targettic = battletick; * * //reset the weapon nextReload. * weapon.nextReload = battletick + (int)(weapon.reloadRate * Battle_Space.TicksPerSecond); // TODO - round up, so weapons that fire more than 10 times per second don't fire at infinite rate * * var target_icomobj = this.WorkingObject; * //Vehicle defenderV = (Vehicle)target_icomobj; * * if (!weapon.CanTarget(target_icomobj)) * return null; * * // TODO - check range too * var tohit = * Mod.Current.Settings.WeaponAccuracyPointBlank // default weapon accuracy at point blank range + weapon.weapon.Template.WeaponAccuracy // weapon's intrinsic accuracy modifier + weapon.weapon.Container.Accuracy // firing ship's accuracy modifier + - target_icomobj.Evasion // target's evasion modifier + - Sector.GetAbilityValue(this.WorkingObject.Owner, "Sector - Sensor Interference").ToInt() // sector evasion modifier + Sector.GetAbilityValue(attacker.WorkingObject.Owner, "Combat Modifier - Sector").ToInt() // generic combat bonuses + - Sector.GetAbilityValue(this.WorkingObject.Owner, "Combat Modifier - Sector").ToInt() + Sector.StarSystem.GetAbilityValue(attacker.WorkingObject.Owner, "Combat Modifier - System").ToInt() + - Sector.StarSystem.GetAbilityValue(this.WorkingObject.Owner, "Combat Modifier - System").ToInt() + attacker.WorkingObject.Owner.GetAbilityValue("Combat Modifier - Empire").ToInt() + - this.WorkingObject.Owner.GetAbilityValue("Combat Modifier - Empire").ToInt(); + // TODO - moddable min/max hit chances with per-weapon overrides + if (tohit > 99) + tohit = 99; + if (tohit < 1) + tohit = 1; + if (weapon.weapon.Container.HasAbility("Weapons Always Hit")) + tohit = 100; + + //bool hit = RandomHelper.Range(0, 99) < tohit; + PRNG dice = attacker.getDice(); + bool hit = dice.Range(0, 99) < tohit; + + CombatTakeFireEvent target_event = null; + + if (weapon.weaponType == "Seeker") + { + + //create seeker and node. + CombatSeeker seeker = new CombatSeeker(attacker, weapon, -tempObjCounter); + seeker.waypointTarget = new combatWaypoint(this); + seeker.weaponTarget = new List<CombatObject>() { this }; + seeker.deathTick = battletick + weapon.maxRange_time; + seeker.cmbt_head = attacker.cmbt_head; + seeker.cmbt_att = attacker.cmbt_att; + FreshNodes.Add(seeker); + + foreach (var emp in Empires.Values) + { + if (emp.ownships.Contains(attacker)) + emp.ownships.Add(seeker); + if (emp.friendly.Contains(attacker)) + emp.friendly.Add(seeker); + if (emp.neutral.Contains(attacker)) + emp.neutral.Add(seeker); + if (emp.hostile.Contains(attacker)) + emp.hostile.Add(seeker); + } + + if (IsReplay) + { + //read the event + target_event = ReplayLog.EventsForObjectAtTick(this, targettic).OfType<CombatTakeFireEvent>().ToList<CombatTakeFireEvent>()[0]; + target_event.BulletNode = seeker; + } + else + { + //*write* the event + target_event = new CombatTakeFireEvent(battletick, this, this.cmbt_loc, false); + target_event.BulletNode = seeker; + seeker.seekertargethit = target_event; + } + } + //for bolt calc, need again for adding to list. + else if (weapon.weaponType == "Bolt") + { + + rangeForDamageCalcs = rangeForDamageCalcs_bolt(attacker, weapon, this); + Fix16 boltTTT = weapon.boltTimeToTarget(attacker, target); + //set target tick for the future. + targettic += (int)boltTTT; + + + + if (IsReplay) + { + //read the event + target_event = ReplayLog.EventsForObjectAtTick(this, targettic).OfType<CombatTakeFireEvent>().ToList<CombatTakeFireEvent>()[0]; + + //because bullets don't need to be created during processing + Fix16 rThis_distance = (target_event.Location - target_event.fireOnEvent.Location).Length; + PointXd bulletVector = Trig.intermediatePoint(attacker.cmbt_loc, target_event.Location, rThis_distance); + if (!target_event.IsHit) //jitter it! + { + // TODO - take into account firing ship's accuracy and target's evasion + int accuracy = target_event.fireOnEvent.Weapon.weapon.Template.WeaponAccuracy; + int jitterAmount = 0; + if (accuracy < 50) + jitterAmount = (int)System.Math.Pow(50 - accuracy, 2) / 50; + if (jitterAmount < 5) + jitterAmount = 5; + if (jitterAmount > 30) + jitterAmount = 30; + //do *NOT* use ship prng here!!!! (since this is not done during normal processing, it'll cause differences, use any rand) + Compass jitter = new Compass(RandomHelper.Range(-jitterAmount, jitterAmount), false); + Compass bulletCompass = bulletVector.Compass; + Compass offsetCompass = bulletCompass + jitter; + bulletVector = offsetCompass.Point(bulletVector.Length); + } + CombatNode bullet = new CombatNode(attacker.cmbt_loc, bulletVector, -tempObjCounter, "BLT"); + target_event.BulletNode = bullet; + FreshNodes.Add(bullet); + if (target_event.IsHit) + { + bullet.deathTick = target_event.Tick; + } + else + { + bullet.deathTick = battletick + target_event.fireOnEvent.Weapon.maxRange; + } + } + else + { + //*write* the event + target_event = new CombatTakeFireEvent(targettic, this, this.cmbt_loc, hit); + int nothing = tempObjCounter; //increase it just so processing has the same number of tempObjects created as replay will. + } + + } + else //not bolt + { + if (IsReplay) + { //read the replay... nothing to do if a beam. + } + else + { //write the event. + rangeForDamageCalcs = rangetotarget / (Fix16)1000; + target_event = new CombatTakeFireEvent(targettic, this, this.cmbt_loc, hit); + } + } + + rangeForDamageCalcs = Fix16.Max((Fix16)1, rangeForDamageCalcs); //don't be less than 1. + + if (hit && !target_icomobj.IsDestroyed) + { + var shot = new Combat.Shot(weapon.weapon, target_icomobj, (int)rangeForDamageCalcs); + //defender.TakeDamage(weapon.Template.ComponentTemplate.WeaponInfo.DamageType, shot.Damage, battle); + int damage = shot.Damage; + combatDamage(battletick, this, weapon, damage, attacker.getDice()); + if (target_icomobj.MaxNormalShields < target_icomobj.NormalShields) + target_icomobj.NormalShields = target_icomobj.MaxNormalShields; + if (target_icomobj.MaxPhasedShields < target_icomobj.PhasedShields) + target_icomobj.PhasedShields = target_icomobj.MaxPhasedShields; + //if (defender.IsDestroyed) + //battle.LogTargetDeath(defender); + } + return target_event; + } */ public void TakeDamage(Battle_Space battle, Hit hit, PRNG dice) { // special combat damage effects TakeSpecialDamage(battle, hit, dice); // basic damage effects WorkingObject.TakeDamage(hit, dice); }
public void From(WorkingObject obj) { Name = obj.Name; m_mesh.From(obj.Mesh); m_materialIds = new List <string>(); for (int i = 0; i < obj.Materials.Count; ++i) { m_materialIds.Add(obj.Materials[i].Guid); } }
private static Vector2 clampHitCircleToPlayfield(WorkingObject workingObject) { var previousPosition = workingObject.PositionModified; workingObject.EndPositionModified = workingObject.PositionModified = clampToPlayfieldWithPadding( workingObject.PositionModified, (float)workingObject.HitObject.Radius ); workingObject.HitObject.Position = workingObject.PositionModified; return(workingObject.PositionModified - previousPosition); }
private void Combine(Vector3 rootPosition, HLODBuildInfo info) { var materialTable = new Dictionary <string, WorkingMaterial>(); var combineInfos = new Dictionary <string, List <MeshCombiner.CombineInfo> >(); for (int i = 0; i < info.WorkingObjects.Count; ++i) { var materials = info.WorkingObjects[i].Materials; for (int m = 0; m < materials.Count; ++m) { //var mat = materials[m]; MeshCombiner.CombineInfo combineInfo = new MeshCombiner.CombineInfo(); combineInfo.Transform = info.WorkingObjects[i].LocalToWorld; combineInfo.Transform.m03 -= rootPosition.x; combineInfo.Transform.m13 -= rootPosition.y; combineInfo.Transform.m23 -= rootPosition.z; combineInfo.Mesh = info.WorkingObjects[i].Mesh; combineInfo.MeshIndex = m; if (combineInfos.ContainsKey(materials[m].Identifier) == false) { combineInfos.Add(materials[m].Identifier, new List <MeshCombiner.CombineInfo>()); materialTable.Add(materials[m].Identifier, materials[m]); } combineInfos[materials[m].Identifier].Add(combineInfo); } } using (var originWorkingObject = info.WorkingObjects) { DisposableList <WorkingObject> combinedObjects = new DisposableList <WorkingObject>(); info.WorkingObjects = combinedObjects; MeshCombiner combiner = new MeshCombiner(); foreach (var pair in combineInfos) { WorkingMesh combinedMesh = combiner.CombineMesh(Allocator.Persistent, pair.Value); WorkingObject combinedObject = new WorkingObject(Allocator.Persistent); WorkingMaterial material = materialTable[pair.Key].Clone(); combinedMesh.name = info.Name + "_Mesh" + pair.Key; combinedObject.Name = info.Name; combinedObject.SetMesh(combinedMesh); combinedObject.Materials.Add(material); combinedObjects.Add(combinedObject); } } }
private static void computeModifiedPosition(WorkingObject current, WorkingObject?previous, WorkingObject?beforePrevious) { float previousAbsoluteAngle = 0f; if (previous != null) { if (previous.HitObject is Slider s) { previousAbsoluteAngle = getSliderRotation(s); } else { Vector2 earliestPosition = beforePrevious?.HitObject.EndPosition ?? playfield_centre; Vector2 relativePosition = previous.HitObject.Position - earliestPosition; previousAbsoluteAngle = MathF.Atan2(relativePosition.Y, relativePosition.X); } } float absoluteAngle = previousAbsoluteAngle + current.PositionInfo.RelativeAngle; var posRelativeToPrev = new Vector2( current.PositionInfo.DistanceFromPrevious * MathF.Cos(absoluteAngle), current.PositionInfo.DistanceFromPrevious * MathF.Sin(absoluteAngle) ); Vector2 lastEndPosition = previous?.EndPositionModified ?? playfield_centre; posRelativeToPrev = RotateAwayFromEdge(lastEndPosition, posRelativeToPrev); current.PositionModified = lastEndPosition + posRelativeToPrev; if (!(current.HitObject is Slider slider)) { return; } absoluteAngle = MathF.Atan2(posRelativeToPrev.Y, posRelativeToPrev.X); Vector2 centreOfMassOriginal = calculateCentreOfMass(slider); Vector2 centreOfMassModified = rotateVector(centreOfMassOriginal, current.PositionInfo.Rotation + absoluteAngle - getSliderRotation(slider)); centreOfMassModified = RotateAwayFromEdge(current.PositionModified, centreOfMassModified); float relativeRotation = MathF.Atan2(centreOfMassModified.Y, centreOfMassModified.X) - MathF.Atan2(centreOfMassOriginal.Y, centreOfMassOriginal.X); if (!Precision.AlmostEquals(relativeRotation, 0)) { RotateSlider(slider, relativeRotation); } }
private void Combine(Vector3 rootPosition, TexturePacker packer, HLODBuildInfo info, dynamic options) { var atlas = packer.GetAtlas(info); if (atlas == null) { return; } List <TextureInfo> textureInfoList = options.TextureInfoList; List <MeshCombiner.CombineInfo> combineInfos = new List <MeshCombiner.CombineInfo>(); for (int i = 0; i < info.WorkingObjects.Count; ++i) { var obj = info.WorkingObjects[i]; ConvertMesh(obj.Mesh, obj.Materials, atlas, textureInfoList[0].InputName); for (int si = 0; si < obj.Mesh.subMeshCount; ++si) { var ci = new MeshCombiner.CombineInfo(); ci.Mesh = obj.Mesh; ci.MeshIndex = si; ci.Transform = obj.LocalToWorld; ci.Transform.m03 -= rootPosition.x; ci.Transform.m13 -= rootPosition.y; ci.Transform.m23 -= rootPosition.z; combineInfos.Add(ci); } } MeshCombiner combiner = new MeshCombiner(); WorkingMesh combinedMesh = combiner.CombineMesh(Allocator.Persistent, combineInfos); WorkingObject newObj = new WorkingObject(Allocator.Persistent); WorkingMaterial newMat = m_createdMaterials[atlas].Clone(); combinedMesh.name = info.Name + "_Mesh"; newObj.Name = info.Name; newObj.SetMesh(combinedMesh); newObj.Materials.Add(newMat); info.WorkingObjects.Dispose(); info.WorkingObjects = new DisposableList <WorkingObject>(); info.WorkingObjects.Add(newObj); }
private WorkingObject CreateBakedTerrain(string name, Bounds bounds, Heightmap heightmap, int distance) { WorkingObject wo = new WorkingObject(Allocator.Persistent); wo.Name = name; m_queue.EnqueueJob(() => { WorkingMesh mesh = CreateBakedGeometry(name, heightmap, bounds, distance); wo.SetMesh(mesh); }); m_queue.EnqueueJob(() => { WorkingMaterial material = CreateBakedMaterial(name, bounds); wo.Materials.Add(material); }); return(wo); }
private WorkingObject CreateBakedTerrain(string name, Bounds bounds, Heightmap heightmap, int distance, bool isLeaf) { WorkingObject wo = new WorkingObject(Allocator.Persistent); wo.Name = name; wo.LightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off; m_queue.EnqueueJob(() => { WorkingMesh mesh = CreateBakedGeometry(name, heightmap, bounds, distance); wo.SetMesh(mesh); }); m_queue.EnqueueJob(() => { WorkingMaterial material = CreateBakedMaterial(name, bounds, isLeaf); wo.Materials.Add(material); }); return(wo); }
private static Vector2 clampSliderToPlayfield(WorkingObject workingObject) { var slider = (Slider)workingObject.HitObject; var possibleMovementBounds = calculatePossibleMovementBounds(slider); var previousPosition = workingObject.PositionModified; // Clamp slider position to the placement area // If the slider is larger than the playfield, at least make sure that the head circle is inside the playfield float newX = possibleMovementBounds.Width < 0 ? Math.Clamp(possibleMovementBounds.Left, 0, OsuPlayfield.BASE_SIZE.X) : Math.Clamp(previousPosition.X, possibleMovementBounds.Left, possibleMovementBounds.Right); float newY = possibleMovementBounds.Height < 0 ? Math.Clamp(possibleMovementBounds.Top, 0, OsuPlayfield.BASE_SIZE.Y) : Math.Clamp(previousPosition.Y, possibleMovementBounds.Top, possibleMovementBounds.Bottom); slider.Position = workingObject.PositionModified = new Vector2(newX, newY); workingObject.EndPositionModified = slider.EndPosition; shiftNestedObjects(slider, workingObject.PositionModified - workingObject.PositionOriginal); return(workingObject.PositionModified - previousPosition); }
private static Vector2 clampSliderToPlayfield(WorkingObject workingObject) { var slider = (Slider)workingObject.HitObject; var possibleMovementBounds = calculatePossibleMovementBounds(slider); var previousPosition = workingObject.PositionModified; // Clamp slider position to the placement area // If the slider is larger than the playfield, force it to stay at the original position float newX = possibleMovementBounds.Width < 0 ? workingObject.PositionOriginal.X : Math.Clamp(previousPosition.X, possibleMovementBounds.Left, possibleMovementBounds.Right); float newY = possibleMovementBounds.Height < 0 ? workingObject.PositionOriginal.Y : Math.Clamp(previousPosition.Y, possibleMovementBounds.Top, possibleMovementBounds.Bottom); slider.Position = workingObject.PositionModified = new Vector2(newX, newY); workingObject.EndPositionModified = slider.EndPosition; shiftNestedObjects(slider, workingObject.PositionModified - workingObject.PositionOriginal); return(workingObject.PositionModified - previousPosition); }
private static void computeModifiedPosition(WorkingObject current, WorkingObject?previous, WorkingObject?beforePrevious) { float previousAbsoluteAngle = 0f; if (previous != null) { Vector2 earliestPosition = beforePrevious?.HitObject.EndPosition ?? playfield_centre; Vector2 relativePosition = previous.HitObject.Position - earliestPosition; previousAbsoluteAngle = (float)Math.Atan2(relativePosition.Y, relativePosition.X); } float absoluteAngle = previousAbsoluteAngle + current.PositionInfo.RelativeAngle; var posRelativeToPrev = new Vector2( current.PositionInfo.DistanceFromPrevious * (float)Math.Cos(absoluteAngle), current.PositionInfo.DistanceFromPrevious * (float)Math.Sin(absoluteAngle) ); Vector2 lastEndPosition = previous?.EndPositionModified ?? playfield_centre; posRelativeToPrev = RotateAwayFromEdge(lastEndPosition, posRelativeToPrev); current.PositionModified = lastEndPosition + posRelativeToPrev; }
public IEnumerator CreateImpl() { try { using (m_queue = new JobQueue(8)) { Stopwatch sw = new Stopwatch(); AssetDatabase.Refresh(); AssetDatabase.SaveAssets(); sw.Reset(); sw.Start(); EditorUtility.DisplayProgressBar("Bake HLOD", "Initialize Bake", 0.0f); TerrainData data = m_hlod.TerrainData; m_size = data.size; m_heightmap = new Heightmap(data.heightmapResolution, data.heightmapResolution, data.size, data.GetHeights(0, 0, data.heightmapResolution, data.heightmapResolution)); string materialPath = AssetDatabase.GUIDToAssetPath(m_hlod.MaterialGUID); m_terrainMaterial = AssetDatabase.LoadAssetAtPath <Material>(materialPath); if (m_terrainMaterial == null) { m_terrainMaterial = new Material(Shader.Find("Standard")); } m_terrainMaterialInstanceId = m_terrainMaterial.GetInstanceID(); m_terrainMaterialName = m_terrainMaterial.name; using (m_alphamaps = new DisposableList <WorkingTexture>()) using (m_layers = new DisposableList <Layer>()) { for (int i = 0; i < data.alphamapTextures.Length; ++i) { m_alphamaps.Add(new WorkingTexture(Allocator.Persistent, data.alphamapTextures[i])); } for (int i = 0; i < data.terrainLayers.Length; ++i) { m_layers.Add(new Layer(data.terrainLayers[i])); } QuadTreeSpaceSplitter splitter = new QuadTreeSpaceSplitter(0.0f); SpaceNode rootNode = splitter.CreateSpaceTree(m_hlod.GetBounds(), m_hlod.ChunkSize * 2.0f, m_hlod.transform.position, null, progress => { }); EditorUtility.DisplayProgressBar("Bake HLOD", "Create mesh", 0.0f); using (DisposableList <HLODBuildInfo> buildInfos = CreateBuildInfo(data, rootNode)) { yield return(m_queue.WaitFinish()); //Write material & textures for (int i = 0; i < buildInfos.Count; ++i) { int curIndex = i; m_queue.EnqueueJob(() => { ISimplifier simplifier = (ISimplifier)Activator.CreateInstance(m_hlod.SimplifierType, new object[] { m_hlod.SimplifierOptions }); simplifier.SimplifyImmidiate(buildInfos[curIndex]); }); } EditorUtility.DisplayProgressBar("Bake HLOD", "Simplify meshes", 0.0f); yield return(m_queue.WaitFinish()); Debug.Log("[TerrainHLOD] Simplify: " + sw.Elapsed.ToString("g")); sw.Reset(); sw.Start(); EditorUtility.DisplayProgressBar("Bake HLOD", "Make border", 0.0f); for (int i = 0; i < buildInfos.Count; ++i) { HLODBuildInfo info = buildInfos[i]; m_queue.EnqueueJob(() => { for (int oi = 0; oi < info.WorkingObjects.Count; ++oi) { WorkingObject o = info.WorkingObjects[oi]; int borderVertexCount = m_hlod.BorderVertexCount * Mathf.RoundToInt(Mathf.Pow(2.0f, (float)info.Distances[oi])); using (WorkingMesh m = MakeBorder(o.Mesh, info.Heightmap, borderVertexCount)) { ReampUV(m, info.Heightmap); o.SetMesh(MakeFillHoleMesh(m)); } } }); } yield return(m_queue.WaitFinish()); Debug.Log("[TerrainHLOD] Make Border: " + sw.Elapsed.ToString("g")); sw.Reset(); sw.Start(); for (int i = 0; i < buildInfos.Count; ++i) { SpaceNode node = buildInfos[i].Target; HLODBuildInfo info = buildInfos[i]; if (node.HasChild() == false) { SpaceNode parent = node.ParentNode; node.ParentNode = null; GameObject go = new GameObject(buildInfos[i].Name); for (int wi = 0; wi < info.WorkingObjects.Count; ++wi) { WorkingObject wo = info.WorkingObjects[wi]; GameObject targetGO = null; if (wi == 0) { targetGO = go; } else { targetGO = new GameObject(wi.ToString()); targetGO.transform.SetParent(go.transform, false); } List <Material> materials = new List <Material>(); for (int mi = 0; mi < wo.Materials.Count; ++mi) { WorkingMaterial wm = wo.Materials[mi]; if (wm.NeedWrite() == false) { materials.Add(wm.ToMaterial()); continue; } Material mat = new Material(wm.ToMaterial()); string[] textureNames = wm.GetTextureNames(); for (int ti = 0; ti < textureNames.Length; ++ti) { WorkingTexture wt = wm.GetTexture(textureNames[ti]); Texture2D tex = wt.ToTexture(); tex.wrapMode = wt.WrapMode; mat.name = targetGO.name + "_Mat"; mat.SetTexture(textureNames[ti], tex); } mat.EnableKeyword("_NORMALMAP"); materials.Add(mat); } targetGO.AddComponent <MeshFilter>().sharedMesh = wo.Mesh.ToMesh(); targetGO.AddComponent <MeshRenderer>().sharedMaterials = materials.ToArray(); } go.transform.SetParent(m_hlod.transform, false); m_hlod.AddGeneratedResource(go); parent.Objects.Add(go); buildInfos.RemoveAt(i); i -= 1; } } //controller IStreamingBuilder builder = (IStreamingBuilder)Activator.CreateInstance(m_hlod.StreamingType, new object[] { m_hlod, m_hlod.StreamingOptions }); builder.Build(rootNode, buildInfos, m_hlod.gameObject, m_hlod.CullDistance, m_hlod.LODDistance, true, false, progress => { EditorUtility.DisplayProgressBar("Bake HLOD", "Storing results.", 0.75f + progress * 0.25f); }); Debug.Log("[TerrainHLOD] Build: " + sw.Elapsed.ToString("g")); } } EditorUtility.SetDirty(m_hlod.gameObject); } } finally { EditorUtility.ClearProgressBar(); GC.Collect(); } }