/// <summary> /// DEBUG: uncomment this to test item drop logic /// </summary> /* * protected void Update() * { * * if (Input.GetKeyUp(KeyCode.F)) * TryDropAmmoClip("Bullet", 19); // try to drop a clip with 19 bullets * * if (Input.GetKeyUp(KeyCode.G)) * TryDropWeapon("Pistol", 15); // try to drop a pistol loaded with 15 bullets * * if (Input.GetKeyUp(KeyCode.H)) * TryDropWeapon("Machinegun", 35); // try to drop a machinegun loaded with 35 bullets * * if (Input.GetKeyUp(KeyCode.J)) * TryDropCurrentWeapon(); // try to drop the currently wielded weapon, with its currently loaded ammo * * if (Input.GetKeyUp(KeyCode.K)) * transform.root.SendMessage("Die"); // insta kill player (for testing death drop modes) * * } */ /// <summary> /// scans the level and 'Droppables' list for item pickups and prepares hidden /// copies for dropping instances at runtime /// </summary> protected virtual void GenerateItemDrops() { List <vp_ItemPickup> pickups = new List <vp_ItemPickup>(FindObjectsOfType <vp_ItemPickup>()); foreach (GameObject o in ExtraPickups) { if (o == null) { continue; } vp_ItemPickup i = (vp_ItemPickup)o.GetComponent <vp_ItemPickup>(); if (i == null) { continue; } pickups.Add(i); } GameObject g = GameObject.Find("Droppables"); if (g != null) { m_DroppablesGroup = g.transform; } if (m_DroppablesGroup == null) { m_DroppablesGroup = new GameObject("Droppables").transform; } foreach (vp_ItemPickup pickup in pickups) { string name = pickup.ItemTypeObject.name; if (pickup.ItemTypeObject is vp_UnitType) { name += "," + pickup.Amount; } if (!m_SceneDroppables.ContainsKey(name)) { GameObject c = ClonePickup(name, pickup); if (c != null) { m_SceneDroppables.Add(name, c); if (!m_SceneItemTypesByName.ContainsKey(pickup.ItemTypeObject.name)) { m_SceneItemTypesByName.Add(pickup.ItemTypeObject.name, pickup.ItemTypeObject); } if ((pickup.ItemTypeObject is vp_UnitType) && (!m_AvailableUnitAmounts.Contains(pickup.Amount))) { m_AvailableUnitAmounts.Add(pickup.Amount); m_AvailableUnitAmounts.Sort(); } } } } StoreAmmoClipTypes(); }
/// <summary> /// sends RPC to remote machines telling them to reenable a pickup /// </summary> protected virtual void TransmitPickupRespawn(vp_ItemPickup pickup) { if (!PhotonNetwork.isMasterClient) { return; } //Debug.Log("Picked up: " + pickup + " with ID: " + pickup.ID); photonView.RPC("ReceivePickupRespawn", PhotonTargets.Others, pickup.ID); }
/// <summary> /// sends RPC to remote machines telling them to hide a certain pickup /// and try to give its contents to a certain player /// </summary> protected virtual void TransmitPickup(vp_ItemPickup pickup, Transform recipient) { //Debug.Log("TransmitPickup: " + pickup.ID); if (!PhotonNetwork.isMasterClient) { return; } vp_MPNetworkPlayer player; if (!vp_MPNetworkPlayer.Players.TryGetValue(recipient.transform.root, out player)) { return; } //Debug.Log(pickup + " with ID: " + pickup.ID + " was picked up on Master by player " + player.ID); photonView.RPC("ReceivePickup", PhotonTargets.Others, pickup.ID, player.ID); }
/// <summary> /// registers a pickup under a position-based ID /// </summary> protected virtual void RegisterPickup(vp_ItemPickup p) { // since a single gameobject may have several vp_Pickup components // on them, pickups are stored in a dictionary with id keys and // pickup list values. (an example of a multi-pickup object is a // grenade, which has both a grenade thrower pickup and an ammo // pickup on the same object) if (!vp_MPPickupManager.Instance.Pickups.ContainsKey(p.ID)) { // if the pickup does not exist, we add a list with a single pickup // under the position based ID List <vp_ItemPickup> ip = new List <vp_ItemPickup>(); ip.Add(p); vp_MPPickupManager.Instance.Pickups.Add(p.ID, ip); vp_Respawner r = p.GetComponent <vp_Respawner>(); if ((r != null) && !vp_MPPickupManager.Instance.PickupRespawners.ContainsKey(p.ID)) { vp_MPPickupManager.Instance.PickupRespawners.Add(p.ID, r); r.m_SpawnMode = vp_Respawner.SpawnMode.SamePosition; } //else TODO: warn } else { // if a pickup already exists with this id, we unpack the list, // remove it from the dictionary, add the new pickup and re-add // it under the same id List <vp_ItemPickup> ip; if (vp_MPPickupManager.Instance.Pickups.TryGetValue(p.ID, out ip) && ip != null) { vp_MPPickupManager.Instance.Pickups.Remove(p.ID); ip.Add(p); vp_MPPickupManager.Instance.Pickups.Add(p.ID, ip); } } //else TODO: warn }
/// <summary> /// logs all the various ammo pickup types available in the scene (and any /// components of this type's 'Droppables' list) by item type and amount. /// for more info, see the 'TryDropAllAmmo' comments /// </summary> protected virtual void StoreAmmoClipTypes() { foreach (vp_ItemType itemType in m_SceneItemTypesByName.Values) { if (itemType is vp_UnitType) { foreach (GameObject o in m_SceneDroppables.Values) { if (o == null) { continue; } vp_ItemPickup ip = o.GetComponent <vp_ItemPickup>(); if (ip == null) { continue; } if (!(ip.ItemTypeObject is vp_UnitType)) { continue; } for (int v = (m_AvailableUnitAmounts.Count - 1); v > -1; v--) { if (m_AvailableUnitAmounts[v] == ip.Amount) { if (!m_AvailableAmmoClips.Contains(new AmmoClipType(ip.ItemTypeObject.name, ip.Amount))) { m_AvailableAmmoClips.Add(new AmmoClipType(ip.ItemTypeObject.name, ip.Amount)); //Debug.Log("added AmmoClipType: " + ip.ItemTypeObject.name + ", " + ip.Amount); } } } } } } }
protected override void RegisterPickup(vp_ItemPickup p) { base.RegisterPickup(p); }
/// <summary> /// sends RPC to remote machines telling them to reenable a pickup /// </summary> protected virtual void TransmitPickupRespawn(vp_ItemPickup pickup) { if (!PhotonNetwork.isMasterClient) return; //Debug.Log("Picked up: " + pickup + " with ID: " + pickup.ID); photonView.RPC("ReceivePickupRespawn", PhotonTargets.Others, pickup.ID); }
/// <summary> /// sends RPC to remote machines telling them to hide a certain pickup /// and try to give its contents to a certain player /// </summary> protected virtual void TransmitPickup(vp_ItemPickup pickup, Transform recipient) { if (!PhotonNetwork.isMasterClient) return; vp_MPNetworkPlayer player; if (!vp_MPNetworkPlayer.Players.TryGetValue(recipient.transform.root, out player)) return; //Debug.Log(pickup + " with ID: " + pickup.ID + " was picked up on Master by player " + player.ID); photonView.RPC("ReceivePickup", PhotonTargets.Others, pickup.ID, player.ID); }
/// <summary> /// registers a pickup under a position-based ID /// </summary> protected virtual void RegisterPickup(vp_ItemPickup p) { // since a single gameobject may have several vp_Pickup components // on them, pickups are stored in a dictionary with id keys and // pickup list values. (an example of a multi-pickup object is a // grenade, which has both a grenade thrower pickup and an ammo // pickup on the same object) if (!Pickups.ContainsKey(p.ID)) { // if the pickup does not exist, we add a list with a single pickup // under the position based ID List<vp_ItemPickup> ip = new List<vp_ItemPickup>(); ip.Add(p); Pickups.Add(p.ID, ip); vp_Respawner r = p.GetComponent<vp_Respawner>(); if ((r != null) && !PickupRespawners.ContainsKey(p.ID)) { PickupRespawners.Add(p.ID, r); r.m_SpawnMode = vp_Respawner.SpawnMode.SamePosition; } //else TODO: warn } else { // if a pickup already exists with this id, we unpack the list, // remove it from the dictionary, add the new pickup and re-add // it under the same id List<vp_ItemPickup> ip; if(Pickups.TryGetValue(p.ID, out ip) && ip != null) { Pickups.Remove(p.ID); ip.Add(p); Pickups.Add(p.ID, ip); } } //else TODO: warn }
/// <summary> /// internal method for handling all aspects of dropping any item type. /// NOTE: in multiplayer, this only gets run on the master, which in turn /// triggers 'MPClientDropItem' on clients /// </summary> protected virtual bool TryDropItemInternal(vp_ItemType itemType, Vector3 direction, int units = 0, int id = 0) { //Debug.Log("TryDropItemInternal: " + itemType + ", " + units); if (!vp_Gameplay.IsMaster) { return(false); } // fetch pickup prefab of the item type GameObject prefab = GetPickupPrefab(itemType, units); if (prefab == null) { return(false); } // try to remove item records or units from the inventory if (!TryRemoveItem(itemType, units, id)) { return(false); } // keep track of the number of item drop attempts for circular distribution and max cap UpdateDropCount(); // abort if we can't drop any more items at once if (m_ItemDropsThisFrame >= MaxDrops) { return(false); } // spawn a pickup GameObject pickup = SpawnPickup( prefab, transform.position // position of inventory owner + (Vector3.up * SpawnHeight) // plus a height offset + (direction * SpawnDistance) // plus a little bit away from body of inventory holder ); if (pickup == null) { return(false); } // in the UFPS multiplayer add-on, every pickup must be assigned a unique id on // spawn / startup (+ the id feature is reserved for the vp_MPPickupManager system) if (vp_Gameplay.IsMultiplayer) { id = vp_Utility.UniqueID; } // initialize the pickup with a collision timer, units, id and a toss component vp_Toss toss = InitPickup(pickup, units, id); if (toss == null) { Object.Destroy(pickup); return(false); } // item drop success! play drop sound TryPlayDropSound(); // offset direction based on how many items we have thrown this frame, so as // to not throw items inside each other direction = GetCircleDirection(direction); // toss the pickup away from the owner // the first 8 items will be tossed to 'm_DestDistance'. after that, // 75% of the initial distance will be added every 8 items, causing // large amounts of items to be arranged in concentric rings float additionalDistance = (((int)((m_ItemDropsThisFrame - 1) / 8)) * (TossDistance * 0.75f)); float targetYaw = Random.Range(-180, 180); Vector3 finalPosition = toss.Toss(pickup.transform.position, targetYaw, direction, (TossDistance + additionalDistance), !DisableBob, !DisableSpin); //Debug.Log("item drops: " + m_ItemDropsThisFrame + ", additional: " + additionalDistance); // notify master object vp_ItemPickup itemPickup = pickup.GetComponentInChildren <vp_ItemPickup>(); if (itemPickup != null) { vp_GlobalEvent <object[]> .Send("TransmitDropItem", new object[] { itemType.name, finalPosition, targetYaw, transform.root, itemPickup.ID, itemPickup.Amount }); } return(true); }
/// <summary> /// creates a deactivated clone template of a pickup object that is /// adapted for instantiation and dropping in the scene. templates are /// stored in a scene group called 'Droppables' /// </summary> protected virtual GameObject ClonePickup(string name, vp_ItemPickup i) { GameObject template = (GameObject)vp_Utility.Instantiate(i.gameObject, Vector3.zero, i.gameObject.transform.rotation); template.name = name; // if there is a remover on the pickup, override its lifetime // if not, add a remover with our own lifetime, even if 0 vp_Remover rm = template.GetComponent <vp_Remover>(); if (rm == null) { rm = template.AddComponent <vp_Remover>(); } rm.LifeTime = ItemLifeTime; // if there is a respawner on the pickup and our lifetime is 0, // use the max respawn time of the respawner as lifetime. // however, kill the respawner afterwards // NOTE: this will make dropped pickups be destroyed (or pooled) // when picked up, unlike scene pickups that have respawners (which // are merely temp-deactivated) vp_Respawner rs = template.GetComponent <vp_Respawner>(); if (rs != null) { if (ItemLifeTime == 0.0f) { rm.LifeTime = rs.MaxRespawnTime; } Object.Destroy(rs); } // if lifetime is 0 at this point, fallback to 10 secs if (rm.LifeTime == 0.0f) { rm.LifeTime = 10.0f; } // add 0-2 seconds randomly to lifetime, so clusters of pickups won't // pop away exactly at the same time vp_MathUtility.SetSeed(i.ID); rm.LifeTime += Random.value * 2; // disable rigidbodiy and colliders (trigger colliders will be reactivated later) Rigidbody rb = template.GetComponent <Rigidbody>(); if (rb != null) { rb.isKinematic = true; } Collider[] cs = template.GetComponents <Collider>(); foreach (Collider c in cs) { c.enabled = false; } // set up item pickup vp_ItemPickup ip = template.GetComponent <vp_ItemPickup>(); if (ip != null) { ip.ID = 0; } ip.Amount = i.Amount; // disable object and child it to the 'Droppables' group vp_Utility.Activate(template, false); template.transform.parent = m_DroppablesGroup; return(template); }