Example #1
0
    /// <summary>
    /// Gurranteed to be local
    /// </summary>
    /// <param name="activator"></param>
    /// <param name="fire_point"></param>
    /// <param name="blt_dir"></param>
    /// <param name="hasAuthority"></param>
    /// <param name="lag_prediction"></param>
    GameObject[] fire_tesla_init(GameObject activator, Vector2 fire_point, float blt_dir, float max_bounce_range, LayerMask hit_fltr, LayerMask obstacle_fltr)
    {
        Vector2             spread_origin        = fire_point;
        Vector2             aimdir               = (new Vector2(Mathf.Cos(blt_dir * Mathf.PI / 180), Mathf.Sin(blt_dir * Mathf.PI / 180))).normalized;
        Body_generic        activator_body       = activator.GetComponent <Body_generic>();
        Player_controller   activator_controller = activator.GetComponent <Player_controller>();
        Body_generic        victim_body          = null;
        RaycastHit2D        hit          = Physics2D.Raycast(transform.position, aimdir, blt_speed * CONSTANTS.VOLT_DIST_RATIO / 2, hit_fltr + obstacle_fltr);
        List <GameObject>   collidedlist = new List <GameObject>();
        Body_hitbox_generic hitbox;
        float volts_left     = blt_speed;
        int   number_streams = 0;

        if (hit)
        {
            hitbox = hit.collider.GetComponent <Body_hitbox_generic>();
            if (hitbox != null) //If hit body, Damage and spread
            {
                volts_left = (1 - (Vector2.Distance(hit.point, transform.position) / (blt_speed * CONSTANTS.VOLT_DIST_RATIO))) * blt_speed;
                collidedlist.Add(hitbox.body.gameObject);
                number_streams = Mathf.Max(1, (int)(volts_left / blt_speed_min));
                spread_origin  = hit.point;
            }
        }

        if (number_streams == 0)
        {
            //Send trail paths
            spawn_muzzle();
            if (activator_controller != null)
            {
                activator_body.Cmd_spawn_tesla_muzzle(gameObject);
            }
            else
            {
                activator_body.Rpc_spawn_tesla_muzzle(gameObject);
            }
            return(null);
        }

        List <GameObject>[]            stream_path = new List <GameObject> [number_streams];
        List <Tesla_generic.teslaNode> spread_list = new List <Tesla_generic.teslaNode>();

        Tesla_generic.teslaNode initial_node = new Tesla_generic.teslaNode();
        initial_node.target       = hit.collider.gameObject;
        initial_node.volts_left   = volts_left;
        initial_node.stream_idxes = new int[number_streams];
        collidedlist.Add(hit.collider.gameObject);
        for (int i = 0; i < number_streams; i++)
        {
            initial_node.stream_idxes[i] = i;
        }
        //Debug.LogError("distance: "+ Vector2.Distance(hit.point, transform.position) + "; volt left: "+volts_left+ "; number streams: "+number_streams);
        spread_list.Add(initial_node);



        int path_size = 0;

        //while there are stem that is branching out
        while (spread_list.Count > 0)//Each step
        {
            //Debug.LogError("step: "+spread_list.Count);
            List <Tesla_generic.teslaNode> spread_temp = new List <Tesla_generic.teslaNode>();
            //For each of the stem
            for (int i = 0; i < spread_list.Count; i++)
            {
                List <Tesla_generic.teslaNode> current_spread_temp = new List <Tesla_generic.teslaNode>();
                int j;
                Tesla_generic.teslaNode node = spread_list[i];
                victim_body = node.target.GetComponent <Body_generic>();
                if (victim_body == null)//structure doesnt take damage from tesla
                {
                    continue;
                }
                if (activator_body.isServer)
                {
                    if (node.target.layer != activator.layer)//Only if damaging opposite team will bleed
                    {
                        victim_body.request_bleed(victim_body.transform.position, 0, false);
                    }
                    victim_body.damage(activator, Vector2.zero, dmg_electric: node.volts_left / 30);
                }
                else
                {
                    activator_controller.add_to_shot_list(victim_body.gameObject, node.volts_left / 30, victim_body.transform.position, 0, 0, false, 2);
                }
                if (activator_body.isLocalPlayer)
                {
                    activator_controller.hit_mark();
                }
                spread_origin = node.target.transform.position;
                //Debug.LogError("From node: "+node.target + "; volt: "+node.volts_left);
                //Mark all the stream with its index
                for (j = 0; j < node.stream_idxes.Length; j++)
                {
                    if (stream_path[node.stream_idxes[j]] == null)
                    {
                        stream_path[node.stream_idxes[j]] = new List <GameObject>();
                    }
                    stream_path[node.stream_idxes[j]].Add(node.target);
                    path_size++;
                    //Debug.LogError("add: " + node.target);
                }
                //overlap circle

                Collider2D[] victims = Physics2D.OverlapCircleAll(spread_origin, Mathf.Min(node.volts_left * CONSTANTS.VOLT_DIST_RATIO, radius), hit_fltr);
                //Debug.LogError("hit count: " + victims.Length);
                if (victims.Length == 0)
                {
                    continue;
                }

                //Sort circle
                victims = victims.OrderBy(o => Vector2.Distance(o.transform.position, spread_origin)).ToArray();
                //Pointer
                j = 0;
                //Compute distance for the next stem, put on dist_to_parent
                float volt = node.volts_left;
                float total_volt_to_parent        = 0;
                Tesla_generic.teslaNode next_node = new Tesla_generic.teslaNode();
                next_node.target         = victims[j].gameObject;
                next_node.volt_to_parent = Vector2.Distance(victims[j].transform.position, spread_origin) / CONSTANTS.VOLT_DIST_RATIO;
                //While this stem has voltage && can reach next stem
                int hits = 0;
                while (volt > blt_speed_min + next_node.volt_to_parent && hits <= CONSTANTS.TESLA_MAX_SPLIT)
                {
                    //If the next stemmed object isnt on collided list
                    if (!collidedlist.Contains(next_node.target) && !Physics2D.Linecast(spread_origin, next_node.target.transform.position, obstacle_fltr))
                    {
                        //subtract copy of dist/volt_ratio\
                        volt -= next_node.volt_to_parent + blt_speed_min;
                        total_volt_to_parent += next_node.volt_to_parent;

                        //Copy the stem onto a spread_temp list
                        spread_temp.Add(next_node);
                        current_spread_temp.Add(next_node);
                        hits++;
                        //Put the stemmed object on collided list
                        collidedlist.Add(next_node.target);
                        //Debug.LogError("spread to: " + next_node.target + "; volt distance: " + next_node.volt_to_parent);
                    }

                    //Increment pointer
                    j++;

                    if (j >= victims.Length)
                    {
                        break;
                    }
                    next_node = new Tesla_generic.teslaNode();
                    //take the next stem on the sorted list
                    next_node.target = victims[j].gameObject;
                    //Compute distance for the next stem
                    next_node.volt_to_parent = Vector2.Distance(victims[j].transform.position, spread_origin) / CONSTANTS.VOLT_DIST_RATIO;
                }
                //Pointer current_idx = 0
                int current_idx = 0;
                //For each on the spread_temp list
                for (int k = 0; k < current_spread_temp.Count; k++)
                {
                    next_node = current_spread_temp[k];
                    //stem volt = (1 - dist_to_parent / volt_of_current_stem) * volt_of_current_stem
                    if (current_spread_temp.Count == 1)
                    {
                        next_node.volts_left = volt;
                    }
                    else
                    {
                        next_node.volts_left = ((total_volt_to_parent - next_node.volt_to_parent) / (current_spread_temp.Count - 1)) * volt / total_volt_to_parent;
                    }

                    //Debug.LogError("spread to: " + next_node.target + "; volt distance: " + next_node.volt_to_parent);
                    //Debug.LogError("volts total: "+node.volts_left+"; total parent: "+ total_volt_to_parent + "; this: "+ next_node.volts_left+ "; volt to parent: "+ next_node.volt_to_parent);
                    //Initialize volt / minimum for the stream idxes
                    if (next_node.volts_left <= 0)
                    {
                        current_spread_temp.RemoveAt(k);
                        k--;
                        continue;
                    }
                    next_node.stream_idxes = new int[Mathf.Max(1, (int)(next_node.volts_left / blt_speed_min))]; //Must be at least one stream
                                                                                                                 //For volt / minimum

                    for (int y = 0; y < next_node.stream_idxes.Length; y++)
                    {
                        //stream_idxes[] = current_stream_idxes[k]
                        next_node.stream_idxes[y] = node.stream_idxes[current_idx];

                        /*
                         * try
                         * {
                         *
                         * }
                         * catch
                         * {
                         *  Debug.LogError("bug!");
                         *  Debug.LogError("next node volt: " + next_node.volts_left);
                         *  Debug.LogError("spread count: " + current_spread_temp.Count + "; number rays: " + next_node.stream_idxes.Length + "; number ray current: " + node.stream_idxes.Length + "; currect:" + current_idx);
                         * }
                         */
                        current_idx++;
                    }
                }
            }
            spread_list.Clear();
            spread_list = spread_temp;
        }

        if (stream_path.Length == 0)
        {
            return(null);
        }
        GameObject[] serialized_path  = new GameObject[path_size + stream_path.Length];
        int          serialized_index = 0;

        for (int i = 0; i < stream_path.Length; i++)
        {
            for (int j = 0; j < stream_path[i].Count; j++)
            {
                serialized_path[serialized_index] = stream_path[i][j];
                serialized_index++;
            }
            serialized_index++;
        }

        //Send trail paths
        if (activator_body.isPlayer && activator_body.hasAuthority)
        {
            activator_body.Cmd_send_tesla_path(serialized_path, gameObject);
        }
        else
        {
            activator_body.Rpc_send_tesla_path(serialized_path, gameObject);
        }
        return(serialized_path);
    }