/// <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); }