Files
2HUCardTDGame/scripts/vscripts/common.lua
2021-10-24 15:36:18 -04:00

1733 lines
56 KiB
Lua
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
THTD_Custom_Hit_Block = {}
function GetHeroFairyList(hero)
local fairyList = {}
local count = 0
for k,v in pairs(hero.thtd_hero_tower_list) do
if v:GetUnitName() == "sunny" and v.thtd_combo_fairyList ~= nil then
table.insert(fairyList,v.thtd_combo_fairyList)
end
end
return fairyList
end
function IsUnitInFairy(fairyArea,unit)
local pos1 = fairyArea.sunny:GetAbsOrigin()
local pos2 = fairyArea.star:GetAbsOrigin()
local pos3 = fairyArea.luna:GetAbsOrigin()
local origin = unit:GetAbsOrigin()
if IsInTriangle(pos1,pos2,pos3,origin) == true then
return true
else
return false
end
end
function GetTriangleArea(p0,p1,p2)
local ab = Vector(p1.x - p0.x, p1.y - p0.y, 0)
local bc = Vector(p2.x - p1.x, p2.y - p1.y, 0)
return math.abs((ab.x * bc.y - ab.y * bc.x) / 2.0)
end
function IsInTriangle(a,b,c,d)
local sabc = GetTriangleArea(a, b, c)
local sadb = GetTriangleArea(a, d, b)
local sbdc = GetTriangleArea(b, d, c)
local sadc = GetTriangleArea(a, d, c)
local sumSuqar = sadb + sbdc + sadc
if (-5 < (sabc - sumSuqar) and (sabc - sumSuqar) < 5) then
return true
else
return false
end
end
--判断三点是否一条线
function IsThreePointsOnOneLine(p1,p2,p3)
local a = math.floor(GetDistanceBetweenTwoVec2D(p1, p2) + 0.5)
local b = math.floor(GetDistanceBetweenTwoVec2D(p2, p3) + 0.5)
local c = math.floor(GetDistanceBetweenTwoVec2D(p3, p1) + 0.5)
local max = math.max(a, b, c)
if a == max and a == (b + c) then return true end
if b == max and b == (a + c) then return true end
if c == max and c == (a + b) then return true end
return false
end
--求三角形的重心和最大半径
function GetCircleCenterAndRadius(p1,p2,p3)
local center = Vector((p1.x + p2.x + p3.x)/3, (p1.y + p2.y + p3.y)/3, 0)
return center, math.max(math.floor(GetDistanceBetweenTwoVec2D(p1, center) + 0.5), math.floor(GetDistanceBetweenTwoVec2D(p2, center) + 0.5), math.floor(GetDistanceBetweenTwoVec2D(p3, center) + 0.5))
end
-- 两点连线上任意点的坐标
function GetTwoVectorSub(pos1, pos2, p1vsp2)
--Px点到两端点的距离P1Px与PxP2比值为p1vsp2
local x=(pos1.x + p1vsp2 * pos2.x)/(1+p1vsp2)
local y=(pos1.y + p1vsp2 * pos2.y)/(1+p1vsp2)
local z=(pos1.z + p1vsp2 * pos2.z)/(1+p1vsp2)
return Vector(x, y, z)
end
--求三角形的外接圆圆心和半径如果三点共线则返回nil
function GetOuterCircleCenterAndRadius(p1,p2,p3)
local a = math.floor(GetDistanceBetweenTwoVec2D(p1, p2) + 0.5)
local b = math.floor(GetDistanceBetweenTwoVec2D(p2, p3) + 0.5)
local c = math.floor(GetDistanceBetweenTwoVec2D(p3, p1) + 0.5)
--如果在一条线上,则返回中点
local max = math.max(a, b, c)
if a == max and a == (b + c) then
local x = (p1.x + p2.x) / 2
local y = (p1.y + p2.y) / 2
local r = a / 2
return Vector(math.floor(x + 0.5),math.floor(y + 0.5),0), r
end
if b == max and b == (a + c) then
local x = (p2.x + p3.x) / 2
local y = (p2.y + p3.y) / 2
local r = b / 2
return Vector(math.floor(x + 0.5),math.floor(y + 0.5),0), r
end
if c == max and c == (a + b) then
local x = (p1.x + p3.x) / 2
local y = (p1.y + p3.y) / 2
local r = c / 2
return Vector(math.floor(x + 0.5),math.floor(y + 0.5),0), r
end
--外接圆半径
local p = (a + b +c)/2
local s = math.sqrt(p*(p-a)*(p-b)*(p-c))
local r = math.floor(a*b*c/(4*s) + 0.5)
--外接圆圆心
local x1 = p1.x
local x2 = p2.x
local x3 = p3.x
local y1 = p1.y
local y2 = p2.y
local y3 = p3.y
local t1 = x1*x1+y1*y1
local t2 = x2*x2+y2*y2
local t3 = x3*x3+y3*y3
local temp = x1*y2+x2*y3+x3*y1-x1*y3-x2*y1-x3*y2
local x = (t2*y3+t1*y2+t3*y1-t2*y1-t3*y2-t1*y3)/temp/2
local y = (t3*x2+t2*x1+t1*x3-t1*x2-t2*x3-t3*x1)/temp/2
return Vector(math.floor(x + 0.5),math.floor(y + 0.5),0), r
end
--求三角形的内接圆圆心和半径
function GetInnerCircleCenterAndRadius(p0,p1,p2)
local x1 = p0.x
local x2 = p1.x
local x3 = p2.x
local y1 = p0.y
local y2 = p1.y
local y3 = p2.y
local x=((y2-y1)*(y3*y3-y1*y1+x3*x3-x1*x1)-(y3-y1)*(y2*y2-y1*y1+x2*x2-x1*x1))/(2*(x3-x1)*(y2-y1)-2*((x2-x1)*(y3-y1)))
local y=((x2-x1)*(x3*x3-x1*x1+y3*y3-y1*y1)-(x3-x1)*(x2*x2-x1*x1+y2*y2-y1*y1))/(2*(y3-y1)*(x2-x1)-2*((y2-y1)*(x3-x1)))
local radius = math.sqrt((p0.x - x)*(p0.x - x) + (p0.y - y)*(p0.y - y))
return Vector(x,y,0),radius
end
-- 获取各刷怪路线的偏移位置x, y 为偏移量,增长方向默认为左右集中,一致向下
function GetSpawnLineOffsetVector(lineid,vec,x,y)
-- lineid从左上顺时针
if lineid == 2 or lineid == 3 then
return vec + Vector(-x,-y,0)
else
return vec + Vector(x,-y,0)
end
end
-- 判断点在直线哪一边,-1为AB的左侧1为右侧
function PointToLineSide(point, vecA, vecB)
local a = vecB.y - vecA.y
local b = vecA.x - vecB.x
local c = vecB.x * vecA.y - vecA.x * vecB.y
local v = a * point.x + b * point.y + c
if v < 0 then
return -1
elseif v > 0 then
return 1
else
return 0
end
end
-- 是否在三角形内
function IsPointInTriangle(point, vecA, vecB, vecC)
local d1 = PointToLineSide(point, vecA, vecB)
local d2 = PointToLineSide(point, vecB, vecC)
local d3 = PointToLineSide(point, vecC, vecA)
return (d1 * d2 > 0) and (d2 * d3 > 0)
end
-- 点是否在直线AB左边右手掌指向线段大拇指方向
function IsLeftToLineSide(point, vecA, vecB)
return (vecB.x - vecA.x) * (point.y - vecA.y) > (point.x - vecA.x) * (vecB.y - vecA.y)
end
-- 点是否在三角形内
function IsPointInTriangle2(point, vecA, vecB, VecC)
local x = point.x
local y = point.y
local ax = vecA.x
local ay = vecA.y
local bx = vecB.x
local by = vecB.y
local cx = VecC.x
local cy = VecC.y
if (bx - ax) * (y - ay) > (by - ay) * (x - ax) and (cx - bx) * (y - by) > (cy - by) * (x - bx) and (ax - cx) * (y - cy) > (ay - cy) * (x - cx) then
return false
else
return true
end
end
-- 计算点与A、B两点形成的角度即形成三角形中点所在顶点的角度
function GetAngle(point, vecA, vecB)
local a = (point - vecA):Length2D()
local b = (vecA - vecB):Length2D()
local c = (point - vecB):Length2D()
-- 计算弧度表示的角
local rad = math.acos((a*a + c*c - b*b)/(2.0*a*c));
-- 用角度表示的角
return 180*rad/math.pi
end
-- /**
-- * 点到线的最短距离实际上就是点到线的垂直距离。
-- * (x,y)为点的坐标
-- * (x1,y1)为线段上点的坐标
-- * (x2,y2)为线段另外一点的坐标
-- * 将点连接上两个线段的
-- */
function GetLengthPointToLine(point, vecA, vecB)
local x = point.x
local y = point.y
local x1 = vecA.x
local y1 = vecA.y
local x2 = vecB.x
local y2 = vecB.y
-- 三角形三个边长
local A = math.abs(math.sqrt(math.pow((x - x1), 2) + math.pow((y - y1), 2)))
local B = math.abs(math.sqrt(math.pow((x - x2), 2) + math.pow((y - y2), 2)))
local C = math.abs(math.sqrt(math.pow((x1 - x2), 2) + math.pow((y1 - y2), 2)))
-- 利用海伦公式计算三角形面积
-- 周长的一半
local P = (A + B + C) / 2
local allArea = math.abs(math.sqrt(P * (P - A) * (P - B) * (P - C)))
-- 普通公式计算三角形面积反推点到线的垂直距离
local dis = (2 * allArea) / C
return dis
end
--------------------------------------------------------------------------------
-- 判断单位是否有效,即非空、存活、激活
function THTD_IsValid(unit)
if unit ~= nil and unit:IsNull() == false and unit:IsAlive() and unit:HasModifier("modifier_touhoutd_release_hidden") == false then
return true
else
return false
end
end
-- 判断是否有效且存活
function IsValidAlive(unit)
if unit ~= nil and unit:IsNull() == false and unit:IsAlive() then
return true
else
return false
end
end
--------------------------------------------------------------------------------
-- PlayerResource:ModifyGold 强化版,超出金钱将保存
thtd_extra_gold = {[0] = 0,[1] = 0,[2] = 0,[3] = 0}
function THTD_ModifyGoldEx(playerid, gold, reliable, flag)
if flag == nil then flag = DOTA_ModifyGold_Unspecified end
if reliable ~= false then reliable = true end
if thtd_extra_gold[playerid] == nil then
thtd_extra_gold[playerid] = 0
end
local current_gold = PlayerResource:GetGold(playerid)
if gold ~= nil then
local add_gold = gold
if current_gold + gold > 99999 then
add_gold = math.min(gold, 99999-current_gold)
thtd_extra_gold[playerid] = thtd_extra_gold[playerid] + (gold - add_gold)
elseif thtd_extra_gold[playerid] > 0 then
add_gold = math.min(thtd_extra_gold[playerid], 99999-(gold+current_gold))
thtd_extra_gold[playerid] = thtd_extra_gold[playerid] - add_gold
end
PlayerResource:ModifyGold(playerid, add_gold, reliable, flag)
else
if current_gold < 99999 and thtd_extra_gold[playerid] > 0 then
local move_gold = math.min(99999 - current_gold, thtd_extra_gold[playerid])
thtd_extra_gold[playerid] = thtd_extra_gold[playerid] - move_gold
PlayerResource:ModifyGold(playerid, move_gold, true, flag)
end
end
THTD_RefreshExtraGold(playerid)
end
-- 刷新超出上限金钱显示
function THTD_RefreshExtraGold(playerid)
PlayerResource:SetLastBuybackTime(playerid, thtd_extra_gold[playerid] or 0)
end
-- 获取总金钱
function CDOTA_BaseNPC:GetGold()
local playerid = self:GetPlayerOwnerID()
if PlayerResource:IsValidPlayerID(playerid) then
return PlayerResource:GetGold(playerid) + (thtd_extra_gold[playerid] or 0)
else
return 0
end
end
--------------------------------------------------------------------------------
function THTD_IsTempleOfGodTower(unit)
local unitName = unit:GetUnitName()
if unitName == "miko" or unitName == "soga" or unitName == "futo" or unitName == "yoshika" or unitName == "seiga" then
return true
else
return false
end
end
function THTD_IsTempleOfGodCanBuffedTower(unit)
local unitName = unit:GetUnitName()
if unitName == "soga" or unitName == "futo" or unitName == "yoshika" or unitName == "seiga" then
return true
else
return false
end
end
function THTD_GetTempleOfGodBuffedTowerStarCount(caster)
local hero = GameRules.HeroList[caster:GetPlayerOwnerID()]
if hero == nil then return 0 end
local star = 0
for k,v in pairs(hero.thtd_hero_tower_list) do
if THTD_IsValid(v) and THTD_IsTempleOfGodTower(v) then
if v:HasModifier("modifier_miko_02_buff") or v:GetUnitName() == "miko" then
star = star + v:THTD_GetStar()
end
end
end
return star
end
--------------------------------------------------------------------------------
-- 是否星莲船单位
function THTD_IsStarLotusTower(unit)
local unitName = unit:GetUnitName()
if unitName == "byakuren" or unitName == "nazrin" or unitName == "toramaru" or unitName == "minamitsu" or unitName == "nue" or unitName == "kogasa" or unitName == "kyouko" then
return true
else
return false
end
end
-- 获取教徒数量,教徒不包括圣白莲
function THTD_GetStarLotusBuffedTowerCount(caster)
local hero = GameRules.HeroList[caster:GetPlayerOwnerID()]
if hero == nil then return 0 end
local count = 0
for k,v in pairs(hero.thtd_hero_tower_list) do
if v:GetUnitName() ~= "byakuren" and THTD_IsStarLotusTower(v) then
if v:HasModifier("modifier_byakuren_03_buff") then
count = count + 1
end
end
end
return count
end
-- 获取星莲船单位数量
function THTD_GetStarLotusTowerCount(caster)
local hero = GameRules.HeroList[caster:GetPlayerOwnerID()]
if hero == nil then return 0 end
local count = 0
for k,v in pairs(hero.thtd_hero_tower_list) do
if THTD_IsStarLotusTower(v) then
count = count + 1
end
end
return count
end
--------------------------------------------------------------------------------
function THTD_FindFriendlyUnitsAll(caster)
local hero = GameRules.HeroList[caster:GetPlayerOwnerID()]
if hero == nil then return {} end
return hero.thtd_hero_tower_list
end
function THTD_FindFriendlyUnitsInRadius(caster,point,radius)
local hero = GameRules.HeroList[caster:GetPlayerOwnerID()]
if hero == nil then return {} end
local targets = {}
for k,v in pairs(hero.thtd_hero_tower_list) do
if THTD_IsValid(v) then
if GetDistanceBetweenTwoVec2D(v:GetOrigin(), point) < radius then
table.insert(targets,v)
end
end
end
return targets
end
function THTD_FindUnitsInRadius(caster,point,radius)
local hero = GameRules.HeroList[caster:GetPlayerOwnerID()]
if hero == nil then return {} end
local id = hero.thtd_player_id
local targets = {}
if id ~= nil then
for k,v in pairs(THTD_EntitiesRectInner[id]) do
if THTD_IsValid(v) and v.thtd_is_outer ~= true then
if GetDistanceBetweenTwoVec2D(v:GetOrigin(), point) < radius then
if v.thtd_is_yukari_01_hidden ~= true then
table.insert(targets,v)
end
end
end
end
if not(point.x+radius < 4432 and point.x-radius > -4432 and point.y+radius < 3896 and point.y-radius > -3896) then
for k,v in pairs(THTD_EntitiesRectOuter) do
if THTD_IsValid(v) then
if GetDistanceBetweenTwoVec2D(v:GetOrigin(), point) < radius then
if v.thtd_is_yukari_01_hidden ~= true then
table.insert(targets,v)
end
end
end
end
end
end
return targets
end
function THTD_FindUnitsAll(caster)
local hero = GameRules.HeroList[caster:GetPlayerOwnerID()]
if hero == nil then return {} end
local id = hero.thtd_player_id
local targets = {}
if id ~= nil then
for k,v in pairs(THTD_EntitiesRectInner[id]) do
if THTD_IsValid(v) and v.thtd_is_outer ~= true then
if v.thtd_is_yukari_01_hidden ~= true then
table.insert(targets,v)
end
end
end
for k,v in pairs(THTD_EntitiesRectOuter) do
if THTD_IsValid(v) then
if v.thtd_is_yukari_01_hidden ~= true then
table.insert(targets,v)
end
end
end
end
return targets
end
function THTD_FindUnitsInner(caster)
local hero = GameRules.HeroList[caster:GetPlayerOwnerID()]
if hero == nil then
print("------- THTD_FindUnitsInner : hero is nil caster : "..caster:GetUnitName())
return {}
end
local id = hero.thtd_player_id
local targets = {}
if id ~= nil then
for k,v in pairs(THTD_EntitiesRectInner[id]) do
if THTD_IsValid(v) and v.thtd_is_outer ~= true then
if v.thtd_is_yukari_01_hidden ~= true then
table.insert(targets,v)
end
end
end
end
return targets
end
function THTD_FindUnitsOuter(caster)
local hero = GameRules.HeroList[caster:GetPlayerOwnerID()]
if hero == nil then return {} end
local id = hero.thtd_player_id
local targets = {}
if id ~= nil then
for k,v in pairs(THTD_EntitiesRectOuter) do
if THTD_IsValid(v) then
if v.thtd_is_yukari_01_hidden ~= true then
table.insert(targets,v)
end
end
end
end
return targets
end
function THTD_HasUnitsInRadius(caster,point,radius)
local hero = GameRules.HeroList[caster:GetPlayerOwnerID()]
if hero == nil then return false end
local id = hero.thtd_player_id
if id ~= nil then
for k,v in pairs(THTD_EntitiesRectInner[id]) do
if THTD_IsValid(v) then
if GetDistanceBetweenTwoVec2D(v:GetOrigin(), point) < radius then
if v.thtd_is_yukari_01_hidden ~= true then
return true
end
end
end
end
if not(point.x+radius < 4432 and point.x-radius > -4432 and point.y+radius < 3896 and point.y-radius > -3896) then
for k,v in pairs(THTD_EntitiesRectOuter) do
if THTD_IsValid(v) then
if GetDistanceBetweenTwoVec2D(v:GetOrigin(), point) < radius then
if v.thtd_is_yukari_01_hidden ~= true then
return true
end
end
end
end
end
end
return false
end
function THTD_IsUnitInGroup(unit,group)
for k,v in pairs(group) do
if v == unit then
return true
end
end
return false
end
--------------------------------------------------------------------------------
-- _print = print
-- function print(str,value)
-- if PlayerResource ~= nil and tostring(PlayerResource:GetSteamID(0)) == string.decode("EE54BFF625C40D3D05AB039344290EA2A1","9527") then
-- _print(str, value)
-- end
-- end
-- _PrintTable = PrintTable
-- function PrintTable(t, indent, done)
-- if PlayerResource ~= nil and tostring(PlayerResource:GetSteamID(0)) == string.decode("EE54BFF625C40D3D05AB039344290EA2A1","9527") then
-- _PrintTable(t, indent, done)
-- end
-- end
-- _DeepPrintTable = DeepPrintTable
-- function DeepPrintTable(t)
-- if PlayerResource ~= nil and tostring(PlayerResource:GetSteamID(0)) == string.decode("EE54BFF625C40D3D05AB039344290EA2A1","9527") then
-- _DeepPrintTable(t)
-- end
-- end
function UnitStunTarget(caster,target,stuntime)
if target:HasModifier("modifier_bosses_random_resist_effect") then
target:AddNewModifier(caster, nil, "modifier_stunned", {duration=stuntime * 0.75})
else
target:AddNewModifier(caster, nil, "modifier_stunned", {duration=stuntime})
end
end
function UnitNoPathingfix(caster,target,duration)
target:AddNewModifier(caster, nil, "modifier_spectre_spectral_dagger_path_phased", {duration=duration})
end
--------------------------------------------------------------------------------
function GetDistanceBetweenTwoVec2D(a, b)
local xx = (a.x-b.x)
local yy = (a.y-b.y)
return math.sqrt(xx*xx + yy*yy)
end
function GetDistanceBetweenTwoEntity(ent1,ent2)
local pos_1=ent1:GetOrigin()
local pos_2=ent2:GetOrigin()
local x_=(pos_1[1]-pos_2[1])^2
local y_=(pos_1[2]-pos_2[2])^2
local dis=(x_+y_)^(0.5)
return dis
end
function GetRadBetweenTwoVec2D(a,b)
local y = b.y - a.y
local x = b.x - a.x
return math.atan2(y,x)
end
function GetRadBetweenTwoVecZ3D(a,b)
local y = b.y - a.y
local x = b.x - a.x
local z = b.z - a.z
local s = math.sqrt(x*x + y*y)
return math.atan2(z,s)
end
--aVec:原点向量
--rectOrigin单位原点向量
--rectWidth矩形宽度
--rectLenth矩形长度
--rectRad矩形相对Y轴旋转角度
function IsRadInRect(aVec,rectOrigin,rectWidth,rectLenth,rectRad)
local aRad = GetRadBetweenTwoVec2D(rectOrigin,aVec)
local turnRad = aRad + (math.pi/2 - rectRad)
local aRadius = GetDistanceBetweenTwoVec2D(rectOrigin,aVec)
local turnX = aRadius*math.cos(turnRad)
local turnY = aRadius*math.sin(turnRad)
local maxX = rectWidth/2
local minX = -rectWidth/2
local maxY = rectLenth
local minY = 0
if(turnX<maxX and turnX>minX and turnY>minY and turnY<maxY)then
return true
else
return false
end
return false
end
function IsValueInTable(Table,v)
if Table == nil then return false end
if type(Table) ~= "table" then return false end
for i= 1,#Table do
if v == Table[i] then
return true
end
end
return false
end
-- cx = 目标的x
-- cy = 目标的y
-- ux = math.cos(theta) (rad是caster和target的夹角的弧度制表示)
-- uy = math.sin(theta)
-- r = 目标和原点之间的距离
-- theta = 夹角的弧度制
-- px = 原点的x
-- py = 原点的y
-- 返回 true or false(目标是否在扇形内,在的话=true不在=false)
function IsPointInCircularSector(cx,cy,ux,uy,r,theta,px,py)
local dx = px - cx
local dy = py - cy
local length = math.sqrt(dx * dx + dy * dy)
if (length > r) then
return false
end
local vec = Vector(dx,dy,0):Normalized()
return math.acos(vec.x * ux + vec.y * uy) < theta
end
--删除table中的table第二个参数为子表
function TableRemoveSubTable(table_1 , table_2)
for i,v in pairs(table_1) do
if v == table_2 then
table.remove(table_1,i)
return
end
end
end
GameRules.AbilityBehavior = {
DOTA_ABILITY_BEHAVIOR_ATTACK,
DOTA_ABILITY_BEHAVIOR_AURA,
DOTA_ABILITY_BEHAVIOR_AUTOCAST,
DOTA_ABILITY_BEHAVIOR_CHANNELLED,
DOTA_ABILITY_BEHAVIOR_DIRECTIONAL,
DOTA_ABILITY_BEHAVIOR_DONT_ALERT_TARGET,
DOTA_ABILITY_BEHAVIOR_DONT_CANCEL_MOVEMENT,
DOTA_ABILITY_BEHAVIOR_DONT_RESUME_ATTACK,
DOTA_ABILITY_BEHAVIOR_DONT_RESUME_MOVEMENT,
DOTA_ABILITY_BEHAVIOR_IGNORE_BACKSWING,
DOTA_ABILITY_BEHAVIOR_IGNORE_CHANNEL,
DOTA_ABILITY_BEHAVIOR_IGNORE_PSEUDO_QUEUE,
DOTA_ABILITY_BEHAVIOR_IGNORE_TURN ,
DOTA_ABILITY_BEHAVIOR_IMMEDIATE,
DOTA_ABILITY_BEHAVIOR_ITEM,
DOTA_ABILITY_BEHAVIOR_NOASSIST,
DOTA_ABILITY_BEHAVIOR_NONE,
DOTA_ABILITY_BEHAVIOR_NORMAL_WHEN_STOLEN,
DOTA_ABILITY_BEHAVIOR_NOT_LEARNABLE,
DOTA_ABILITY_BEHAVIOR_ROOT_DISABLES,
DOTA_ABILITY_BEHAVIOR_RUNE_TARGET,
DOTA_ABILITY_BEHAVIOR_UNRESTRICTED ,
}
--判断单体技能
function CDOTABaseAbility:IsUnitTarget()
local b = self:GetBehavior()
if self:IsHidden() then b = b - 1 end
for k,v in pairs(GameRules.AbilityBehavior) do
repeat
if v == 0 then break end
b = b % v
until true
end
if (b - DOTA_ABILITY_BEHAVIOR_AOE) == DOTA_ABILITY_BEHAVIOR_UNIT_TARGET then
b = b - DOTA_ABILITY_BEHAVIOR_AOE
end
if b == DOTA_ABILITY_BEHAVIOR_UNIT_TARGET then
return true
end
return false
end
--判断点目标技能
function CDOTABaseAbility:IsPoint( )
local b = self:GetBehavior()
return bit.band(b,DOTA_ABILITY_BEHAVIOR_POINT) == DOTA_ABILITY_BEHAVIOR_POINT
end
--判断无目标技能
function CDOTABaseAbility:IsNoTarget( )
local b = self:GetBehavior()
return bit.band(b,DOTA_ABILITY_BEHAVIOR_NO_TARGET) == DOTA_ABILITY_BEHAVIOR_NO_TARGET
end
--通用方法之添加技能传入单位实体、技能名必传、等级默认1
function AddAbilityAndSetLevel(u,a,l)
if l == nil then
l = 1
end
if u == nil or u:IsNull() then
return
end
if u:FindAbilityByName(a) == nil then
u:AddAbility(a)
if u:FindAbilityByName(a) ~= nil then
u:FindAbilityByName(a):SetLevel(l)
end
else
u:FindAbilityByName(a):SetLevel(l)
end
end
--增加buff支持lua和技能的如果存在则刷新否则创建。sourceAbility为可选lua的buff输入nil
function CDOTA_BaseNPC:AddModifier(caster, sourceAbility, modifierName, duration, stackCount)
local modifier = self:FindModifierByName(modifierName)
if modifier ~= nil then
if duration ~= nil and duration > 0 then
modifier:SetDuration(duration, false)
end
else
if duration ~= nil and duration > 0 then
modifier = self:AddNewModifier(caster, sourceAbility, modifierName, {Duration = duration})
else
modifier = self:AddNewModifier(caster, sourceAbility, modifierName, nil)
end
end
if stackCount ~= nil and stackCount > 0 and modifier ~= nil then
modifier:SetStackCount(stackCount)
end
return modifier
end
-- 获取技能设定值,在技能的 AbilitySpecial 中定义isConvertPercent 为是否将百分比的转为化对应小数
function CDOTA_BaseNPC:GetAbilityValue(abilityName, itemName, isConvertPercent)
local ability = self:FindAbilityByName(abilityName)
if ability == nil then
print("---------- GetAbilityValue Error!")
print(abilityName..": ability for "..self:GetUnitName().." is nil")
return 0
end
-- 如果没有定义,则 v 等于0不会等于nil
local v = ability:GetSpecialValueFor(itemName)
if isConvertPercent == true then
return v / 100
else
return v
end
end
--------------------------------------------------------------------------------
--弹射函数
--用于检测是否被此次弹射命中过
function CatapultFindImpact( unit,str )
for i,v in pairs(unit.CatapultImpact) do
if v == str then
return true
end
end
return false
end
--caster是施法者或者主要来源
--target是第一个目标
--ability是技能来源
--effectName是弹射的投射物
--move_speed是投射物的速率
--doge是表示能否被躲掉
--radius是每次弹射的范围
--count是弹射次数
--teams,types,flags获取单位的三剑客
--find_tpye是单位组按远近或者随机排列
-- FIND_CLOSEST
-- FIND_FARTHEST
-- FIND_UNITS_EVERYWHERE
function Catapult( caster,target,ability,effectName,move_speed,radius,count,teams,types,flags,find_tpye )
print("Run Catapult")
local old_target = caster
--生成独立的字符串
local str = DoUniqueString(ability:GetAbilityName())
print("Catapult:"..str)
--假设一个马甲
local unit = {}
--绑定信息
--是否发射下一个投射物
unit.CatapultNext = false
unit.count_num = 0
--本次弹射标识的字符串
unit.CatapultThisProjectile = str
unit.old_target = old_target
--本次弹射的目标
unit.CatapultThisTarget = target
--CatapultUnit用来存储unit
if caster.CatapultUnit == nil then
caster.CatapultUnit = {}
end
--把unit插入CatapultUnit
table.insert(caster.CatapultUnit,unit)
--用于决定是否发射投射物
local fire = true
--弹射最大次数
local count_num = 0
GameRules:GetGameModeEntity():SetContextThink(str,
function( )
--满足达到最大弹射次数删除计时器
if count_num>=count then
print("Catapult impact :"..count_num)
print("Catapult:"..str.." is over")
return nil
end
if unit.CatapultNext then
--获取单位组
local group = THTD_FindUnitsInRadius(caster,target:GetOrigin(),radius)
--用于计算循环次数
local num = 0
for i=1,#group do
if group[i].CatapultImpact == nil then
group[i].CatapultImpact = {}
end
--判断是否命中
local impact = CatapultFindImpact(group[i],str)
if impact == false then
--替换old_target
old_target = target
--新target
target = group[i]
--可以发射新投射物
fire = true
unit.count_num = count_num
--等待下一个目标
unit.old_target = old_target
unit.CatapultNext =false
--锁定当前目标
unit.CatapultThisTarget = target
break
end
num = num + 1
end
--如果大于等于单位组的数量那么就删除计时器
if num >= #group then
--从CatapultUnit中删除unit
TableRemoveSubTable(caster.CatapultUnit,unit)
print("Catapult impact :"..count_num)
print("Catapult:"..str.." is over")
return nil
end
end
--发射投射物
if fire then
fire = false
count_num = count_num + 1
local info =
{
Target = target,
Source = old_target,
Ability = ability,
EffectName = effectName,
bDodgeable = false,
iMoveSpeed = move_speed,
bProvidesVision = true,
iVisionRadius = 300,
iVisionTeamNumber = caster:GetTeamNumber(),
iSourceAttachment = DOTA_PROJECTILE_ATTACHMENT_ATTACK_1
}
projectile = ProjectileManager:CreateTrackingProjectile(info)
end
return 0.05
end,0)
end
--此函数在KV里面用OnProjectileHitUnit调用
function CatapultImpact( keys )
local caster = keys.caster
local target = keys.target
--防止意外
if caster.CatapultUnit == nil then
caster.CatapultUnit = {}
end
if target.CatapultImpact == nil then
target.CatapultImpact = {}
end
--挨个检测是否是弹射的目标
for i,v in pairs(caster.CatapultUnit) do
if v.CatapultThisProjectile ~= nil and v.CatapultThisTarget ~= nil then
if v.CatapultThisTarget == target then
--标记target被CatapultThisProjectile命中
table.insert(target.CatapultImpact,v.CatapultThisProjectile)
--允许发射下一次投射物
v.CatapultNext = true
return
end
end
end
end
--------------------------------------------------------------------------------
function ParticleManager:DestroyParticleSystem(effectIndex, bool)
if effectIndex==nil then return end
if bool == true then
ParticleManager:DestroyParticle(effectIndex,true)
ParticleManager:ReleaseParticleIndex(effectIndex)
else
Timer.Wait 'Effect_Destroy_Particle' (4,
function()
ParticleManager:DestroyParticle(effectIndex,true)
ParticleManager:ReleaseParticleIndex(effectIndex)
end
)
end
end
function ParticleManager:DestroyParticleSystemTime(effectIndex,time)
if effectIndex==nil then return end
Timer.Wait 'Effect_Destroy_Particle_Time' (time,
function()
ParticleManager:DestroyParticle(effectIndex,true)
ParticleManager:ReleaseParticleIndex(effectIndex)
end
)
end
function ParticleManager:DestroyParticleSystemTimeFalse(effectIndex,time)
if effectIndex==nil then return end
Timer.Wait 'Effect_Destroy_Particle_Time' (time,
function()
ParticleManager:DestroyParticle(effectIndex,false)
ParticleManager:DestroyParticleSystem(effectIndex,false)
end
)
end
function ParticleManager:DestroyLinearProjectileSystem(effectIndex,bool)
if effectIndex==nil then return end
if(bool)then
ProjectileManager:DestroyLinearProjectile(effectIndex)
else
Timer.Wait 'Effect_Destroy_Particle' (8,
function()
if effectIndex==nil then return end
ProjectileManager:DestroyLinearProjectile(effectIndex)
end
)
end
end
function ParticleManager:DestroyLinearProjectileSystemTime(effectIndex,time)
if effectIndex==nil then return end
Timer.Wait 'Effect_Destroy_Particle_Time' (time,
function()
if effectIndex==nil then return end
ProjectileManager:DestroyLinearProjectile(effectIndex)
end
)
end
function CreateProjectileMoveToTargetPoint(projectileTable,caster,speed,acceleration1,acceleration2,func)
local effectIndex = ParticleManager:CreateParticle(projectileTable.EffectName, PATTACH_CUSTOMORIGIN, nil)
ParticleManager:SetParticleControlForward(effectIndex,3,projectileTable.vVelocity:Normalized())
local acceleration = acceleration1
local ability = projectileTable.Ability
local targets = {}
local targets_remove = {}
local dis = 0
local reflexCount = 0
local pString = DoUniqueString("projectile_string")
local high = projectileTable.vSpawnOriginNew.z - GetGroundHeight(projectileTable.vSpawnOriginNew, nil)
local fixedTime = 10.0
local count = 0
caster:SetContextThink(DoUniqueString("ability_caster_projectile"),
function()
if GameRules:IsGamePaused() then return 0.03 end
local vec = projectileTable.vSpawnOriginNew + projectileTable.vVelocity*speed/50
dis = dis + speed/50
-- 是否反射
if projectileTable.bReflexByBlock~=nil and projectileTable.bReflexByBlock==true then
--if GridNav:CanFindPath(projectileTable.vSpawnOriginNew,projectileTable.vSpawnOriginNew + projectileTable.vVelocity*speed/50)==false or GetHitCustomBlock(projectileTable.vSpawnOriginNew,projectileTable.vSpawnOriginNew + projectileTable.vVelocity*speed/50)~=nil then
if GetHitCustomBlock(projectileTable.vSpawnOriginNew,projectileTable.vSpawnOriginNew + projectileTable.vVelocity*speed/50)~=nil then
local inRad = GetRadBetweenTwoVec2D(vec,projectileTable.vSpawnOriginNew)
local blockRad = GetBlockTurning(inRad,projectileTable.vSpawnOriginNew)
projectileTable.vVelocity = Vector(math.cos(inRad-blockRad+math.pi),math.sin(inRad-blockRad+math.pi),0)
vec = projectileTable.vSpawnOriginNew + projectileTable.vVelocity*speed/50
ParticleManager:SetParticleControlForward(effectIndex,3,projectileTable.vVelocity:Normalized())
reflexCount = reflexCount + 1
for k,v in pairs(targets_remove) do
if v:GetContext(pString)~=0 then
v:SetContextNum(pString,0,0)
table.remove(targets_remove,k)
end
end
end
end
-- 是否判断击中墙壁
if projectileTable.bStopByBlock~=nil and projectileTable.bStopByBlock==true then
if GridNav:CanFindPath(projectileTable.vSpawnOriginNew,projectileTable.vSpawnOriginNew + projectileTable.vVelocity*speed/50)==false then
if(projectileTable.bDeleteOnHit)then
if func then func(nil,vec) end
ParticleManager:DestroyParticleSystem(effectIndex,true)
return nil
else
if func then func(nil,vec) end
end
end
end
targets = THTD_FindUnitsInRadius(caster,vec,projectileTable.fStartRadius)
if(targets[1]~=nil)then
if(projectileTable.bDeleteOnHit)then
if func then func(targets[1],vec,reflexCount) end
ParticleManager:DestroyParticleSystem(effectIndex,true)
return nil
elseif(projectileTable.bDeleteOnHit==false)then
for k,v in pairs(targets) do
if v:GetContext(pString)~=1 then
v:SetContextNum(pString,1,0)
table.insert(targets_remove,v)
if func then func(v,vec,reflexCount) end
end
end
end
end
if(speed <= 0 and acceleration2 ~= 0)then
acceleration = acceleration2
speed = 0
acceleration2 = 0
end
fixedTime = fixedTime - 0.02
if(dis<projectileTable.fDistance and fixedTime > 0)then
ParticleManager:SetParticleControl(effectIndex,3,Vector(vec.x,vec.y,GetGroundHeight(vec, nil)+high))
projectileTable.vSpawnOriginNew = vec
speed = speed + acceleration
return 0.02
else
ParticleManager:DestroyParticleSystem(effectIndex,true)
return nil
end
end,
0.02)
end
function CreateProjectileMoveToPoint(projectileTable,caster,targetPoint,speed,iVelocity,acceleration,func)
local effectIndex = ParticleManager:CreateParticle(projectileTable.EffectName, PATTACH_CUSTOMORIGIN, nil)
ParticleManager:SetParticleControlForward(effectIndex,3,(projectileTable.vVelocity*iVelocity/50 + speed/50 * (targetPoint - caster:GetOrigin()):Normalized()):Normalized())
local ability = projectileTable.Ability
local targets = {}
local targets_remove = {}
local totalDistance = 0
caster:SetContextThink(DoUniqueString("ability_caster_projectile"),
function()
if GameRules:IsGamePaused() then return 0.03 end
-- 向心力单位向量
local vecCentripetal = (projectileTable.vSpawnOriginNew - targetPoint):Normalized()
-- 向心力
local forceCentripetal = speed/50
-- 初速度单位向量
local vecInVelocity = projectileTable.vVelocity
-- 初始力
local forceIn = iVelocity/50
-- 投射物矢量
local vecProjectile = vecInVelocity * forceIn + forceCentripetal * vecCentripetal
local vec = projectileTable.vSpawnOriginNew + vecProjectile
-- 投射物单位向量
local particleForward = vecProjectile:Normalized()
-- 目标和投射物距离
local dis = GetDistanceBetweenTwoVec2D(targetPoint,vec)
ParticleManager:SetParticleControlForward(effectIndex,3,particleForward)
totalDistance = totalDistance + math.sqrt(forceIn*forceIn + forceCentripetal*forceCentripetal)
if(dis<projectileTable.fEndRadius)then
if(projectileTable.bDeleteOnHit)then
if func then func(projectileTable.vSpawnOriginNew) end
ParticleManager:DestroyParticleSystem(effectIndex,true)
return nil
end
end
if(totalDistance<projectileTable.fDistance and dis>=projectileTable.fEndRadius)then
ParticleManager:SetParticleControl(effectIndex,3,vec)
projectileTable.vSpawnOriginNew = vec
speed = speed + acceleration
return 0.02
else
if func then func(projectileTable.vSpawnOriginNew) end
ParticleManager:DestroyParticleSystem(effectIndex,true)
return nil
end
end,
0.02)
end
function CreateProjectileMoveToTarget(projectileTable,caster,target,speed,iVelocity,acceleration,func)
local effectIndex = ParticleManager:CreateParticle(projectileTable.EffectName, PATTACH_CUSTOMORIGIN, nil)
ParticleManager:SetParticleControlForward(effectIndex,3,(projectileTable.vVelocity*iVelocity/50 + speed/50 * (target:GetOrigin() - caster:GetOrigin()):Normalized()):Normalized())
local ability = projectileTable.Ability
local targets = {}
local targets_remove = {}
local totalDistance = 0
caster:SetContextThink(DoUniqueString("ability_caster_projectile"),
function()
if GameRules:IsGamePaused() then return 0.03 end
if target:IsNull() or target==nil then
ParticleManager:DestroyParticleSystem(effectIndex,true)
return nil
end
-- 向心力单位向量
local vecCentripetal = (projectileTable.vSpawnOriginNew - target:GetOrigin()):Normalized()
-- 向心力
local forceCentripetal = speed/50
-- 初速度单位向量
local vecInVelocity = projectileTable.vVelocity
-- 初始力
local forceIn = iVelocity/50
-- 投射物矢量
local vecProjectile = vecInVelocity * forceIn + forceCentripetal * vecCentripetal
local vec = projectileTable.vSpawnOriginNew + vecProjectile
-- 投射物单位向量
local particleForward = vecProjectile:Normalized()
-- 目标和投射物距离
local dis = GetDistanceBetweenTwoVec2D(target:GetOrigin(),vec)
ParticleManager:SetParticleControlForward(effectIndex,3,particleForward)
totalDistance = totalDistance + math.sqrt(forceIn*forceIn + forceCentripetal*forceCentripetal)
if dis < projectileTable.fStartRadius then
targets = THTD_FindUnitsInRadius(caster,vec,projectileTable.fStartRadius)
if(targets[1]~=nil)then
if(projectileTable.bDeleteOnHit)then
if func then func(targets[1],projectileTable.vSpawnOriginNew) end
ParticleManager:DestroyParticleSystem(effectIndex,true)
return nil
else
if #targets_remove==0 then
table.insert(targets_remove,targets[1])
if func then func(targets[1],projectileTable.vSpawnOriginNew) end
else
for k,v in pairs(targets) do
for k1,v1 in pairs(targets_remove) do
if v~=v1 then
table.insert(targets_remove,v)
if func then func(v,projectileTable.vSpawnOriginNew) end
end
end
end
end
end
end
end
if(totalDistance<projectileTable.fDistance and dis>=projectileTable.fEndRadius)then
ParticleManager:SetParticleControl(effectIndex,3,vec)
projectileTable.vSpawnOriginNew = vec
speed = speed + acceleration
return 0.02
else
ParticleManager:DestroyParticleSystem(effectIndex,true)
return nil
end
end,
0.02)
end
function CreateProjectileThrowToTargetPoint(projectileTable,caster,targetPoint,speed,upSpeed,func)
local ability = projectileTable.Ability
local targets = {}
local targets_remove = {}
local totalDistance = 0
-- 过程时间
local distance = GetDistanceBetweenTwoVec2D(caster:GetOrigin(),targetPoint)
local t = distance/speed
-- 重力方向
local vecGravity = Vector(0,0,-1)
local PV = targetPoint.z - 128 - caster:GetOrigin().z
-- 重力大小
local gravity = 0.02 * ((2*upSpeed+PV/16)/t)
-- 初速度单位向量
local vecInVelocity = projectileTable.vVelocity
-- 初始水平方向力
local forceIn = 0.02 * speed
-- 投射物矢量
local vecProjectile = vecInVelocity * forceIn + gravity * vecGravity
-- 投射物单位向量
local particleForward = vecProjectile:Normalized()
local effectIndex = ParticleManager:CreateParticle(projectileTable.EffectName, PATTACH_CUSTOMORIGIN, nil)
ParticleManager:SetParticleControlForward(effectIndex,3,caster:GetForwardVector())
local count = 0
caster:SetContextThink(DoUniqueString("ability_caster_projectile"),
function()
if GameRules:IsGamePaused() then return 0.03 end
distance = distance - forceIn
if distance<0 then
forceIn = 0
end
-- 投射物矢量
vecProjectile = vecInVelocity * forceIn + upSpeed * vecGravity
local vec = projectileTable.vSpawnOriginNew + vecProjectile
totalDistance = totalDistance + math.sqrt(forceIn*forceIn + gravity*gravity)
if(projectileTable.vSpawnOriginNew.z+128>targetPoint.z or t > t/2)then
ParticleManager:SetParticleControl(effectIndex,3,vec)
projectileTable.vSpawnOriginNew = vec
upSpeed = upSpeed - gravity
t = t - 0.02
return 0.02
else
targets = THTD_FindUnitsInRadius(caster,vec,projectileTable.fStartRadius)
if func then func(targets) end
ParticleManager:DestroyParticleSystem(effectIndex,true)
return nil
end
end,
0.02)
end
function GetBlockTurning(face,pos)
local vface = face
local hitblock = GetHitCustomBlock(pos,pos + Vector(math.cos(vface/180*math.pi),math.sin(vface/180*math.pi),0)*50)
if hitblock~=nil then
return 90
end
return 90
end
function GetBlockHeight(rad,pos)
for i=0,200 do
local gridPos = pos + Vector(math.cos(rad),math.sin(rad),0)*i
local height = GetGroundHeight(gridPos,nil)
if height > pos.z + 128 then
return height
end
end
return 0
end
function GetHitCustomBlock(vec,pos)
for k,v in pairs(THTD_Custom_Hit_Block) do
local circlePoint = v.circlePoint
local dis1 = GetDistanceBetweenTwoVec2D(vec,circlePoint)
local dis2 = GetDistanceBetweenTwoVec2D(pos,circlePoint)
if dis1-50 < v.radius and dis2+50 >= v.radius then
return v
end
end
return nil
end
function IsAroundBlock(pos)
for k,v in pairs(THTD_Custom_Hit_Block) do
local circlePoint = v.circlePoint
local dis = GetDistanceBetweenTwoVec2D(pos,circlePoint)
if dis < v.radius then
return true
end
end
return false
end
function clone(object)
local lookup_table = {}
local function _copy(object)
if type(object) ~= "table" then
return object
elseif lookup_table[object] then
return lookup_table[object]
end
local newObject = {}
lookup_table[object] = newObject
for key, value in pairs(object) do
newObject[_copy(key)] = _copy(value)
end
return setmetatable(newObject, getmetatable(object))
end
return _copy(object)
end
--------------------------------------------------------------------------------
--[[
计时器函数Timer
调用方法:
Timer.Wait '5秒后打印一次' (5,
function()
print '我已经打印了一次文本'
end
)
Timer.Loop '每隔1秒打印一次,一共打印5次' (1, 5,
function(i)
print('这是第' .. i .. '次打印')
if i == 5 then
print('我改变主意了,我还要打印10次,但是间隔降低为0.5秒')
return 0.5, i + 10
end
if i == 10 then
print('我好像打印的太多了,算了不打印了')
return true
end
end
)
]]
--全局计时器表
Timer = {}
local Timer = Timer
setmetatable(Timer, Timer)
function Timer.Wait(name)
--[[if not dota_base_game_mode then
print('WARNING: Timer created too soon!')
return
end]]--
return function(t, func)
local ent = GameRules:GetGameModeEntity()
ent:SetThink(func, DoUniqueString(name), t)
end
end
function Timer.Loop(name)
--[[if not dota_base_game_mode then
print('WARNING: Timer created too soon!')
return
end]]--
return function(t, count, func)
if not func then
count, func = -1, count
end
local times = 0
local function func2()
times = times + 1
local t2, count2 = func(times)
t, count = t2 or t, count2 or count
if t == true or times == count then
return nil
end
return t
end
local ent = GameRules:GetGameModeEntity()
ent:SetThink(func2, DoUniqueString(name), t)
end
end
TIMERS_THINK = 0.01
if Timers == nil then
print ( '[Timers] creating Timers' )
Timers = {}
Timers.__index = Timers
end
function Timers:new( o )
o = o or {}
setmetatable( o, Timers )
return o
end
function Timers:start()
Timers = self
self.timers = {}
local ent = Entities:CreateByClassname("info_target") -- Entities:FindByClassname(nil, 'CWorld')
ent:SetThink("Think", self, "timers", TIMERS_THINK)
end
function Timers:Think()
if GameRules:State_Get() >= DOTA_GAMERULES_STATE_POST_GAME then
return
end
-- Track game time, since the dt passed in to think is actually wall-clock time not simulation time.
local now = GameRules:GetGameTime()
-- Process timers
for k,v in pairs(Timers.timers) do
local bUseGameTime = true
if v.useGameTime ~= nil and v.useGameTime == false then
bUseGameTime = false
end
local bOldStyle = false
if v.useOldStyle ~= nil and v.useOldStyle == true then
bOldStyle = true
end
local now = GameRules:GetGameTime()
if not bUseGameTime then
now = Time()
end
if v.endTime == nil then
v.endTime = now
end
-- Check if the timer has finished
if now >= v.endTime then
-- Remove from timers list
Timers.timers[k] = nil
-- Run the callback
local status, nextCall = pcall(v.callback, GameRules:GetGameModeEntity(), v)
-- Make sure it worked
if status then
-- Check if it needs to loop
if nextCall then
-- Change its end time
if bOldStyle then
v.endTime = v.endTime + nextCall - now
else
v.endTime = v.endTime + nextCall
end
Timers.timers[k] = v
end
-- Update timer data
--self:UpdateTimerData()
else
-- Nope, handle the error
Timers:HandleEventError('Timer', k, nextCall)
end
end
end
return TIMERS_THINK
end
function Timers:HandleEventError(name, event, err)
print(err)
-- Ensure we have data
name = tostring(name or 'unknown')
event = tostring(event or 'unknown')
err = tostring(err or 'unknown')
-- Tell everyone there was an error
--Say(nil, name .. ' threw an error on event '..event, false)
--Say(nil, err, false)
-- Prevent loop arounds
if not self.errorHandled then
-- Store that we handled an error
self.errorHandled = true
end
end
function Timers:CreateTimer(name, args)
if type(name) == "function" then
args = {callback = name}
name = DoUniqueString("timer")
elseif type(name) == "table" then
args = name
name = DoUniqueString("timer")
elseif type(name) == "number" then
args = {endTime = name, callback = args}
name = DoUniqueString("timer")
end
if not args.callback then
print("Invalid timer created: "..name)
return
end
local now = GameRules:GetGameTime()
if args.useGameTime ~= nil and args.useGameTime == false then
now = Time()
end
if args.endTime == nil then
args.endTime = now
elseif args.useOldStyle == nil or args.useOldStyle == false then
args.endTime = now + args.endTime
end
Timers.timers[name] = args
end
function Timers:RemoveTimer(name)
Timers.timers[name] = nil
end
function Timers:RemoveTimers(killAll)
local timers = {}
if not killAll then
for k,v in pairs(Timers.timers) do
if v.persist then
timers[k] = v
end
end
end
Timers.timers = timers
end
Timers:start()
--------------------------------------------------------------------------------
function PrecacheEveryThingFromKV( context )
local kv_files = {
"scripts/npc/npc_units_custom.txt",
--[["scripts/npc/npc_abilities_custom.txt",
"scripts/npc/npc_heroes_custom.txt",
"scripts/npc/npc_abilities_override.txt",
"npc_items_custom.txt"]]--
}
for _, kv in pairs(kv_files) do
local kvs = LoadKeyValues(kv)
if kvs then
-- print("BEGIN TO PRECACHE RESOURCE FROM: ", kv)
PrecacheEverythingFromTable( context, kvs)
end
end
local unitKv = LoadKeyValues("scripts/npc/npc_units_custom.txt")
for k,v in pairs(unitKv) do
-- print("PRECACHE UNIT RESOURCE "..k, k)
PrecacheUnitByNameSync(k,context)
end
end
function PrecacheEverythingFromTable( context, kvtable)
for key, value in pairs(kvtable) do
if type(value) == "table" then
PrecacheEverythingFromTable( context, value )
else
if string.find(value, "vpcf") then
PrecacheResource( "particle", value, context)
-- print("PRECACHE PARTICLE RESOURCE", value)
end
if string.find(value, "vmdl") then
PrecacheResource( "model", value, context)
-- print("PRECACHE MODEL RESOURCE", value)
end
if string.find(value, "vsndevts") then
PrecacheResource( "soundfile", value, context)
-- print("PRECACHE SOUND RESOURCE", value)
end
end
end
end
--------------------------------------------------------------------------------
-- 当物品被摧毁时执行,出现场景为升星、培养和出售,以及程序删除,将物品返回卡池,如果是卡牌则同时摧毁关联的塔
-- 参数物品实体玩家id是否出售场景不需要在本函数中进行删除物品
function OnItemDestroyed(caster, item, isSold)
--摧毁关联的塔
local tower = item:THTD_GetTower()
if tower ~= nil then
tower:ForceKill(false)
end
local itemName = item:GetAbilityName()
--炸弹和福弹及赠送的不返回卡池
if itemName ~= "item_2001" and item.card_poor_player_id ~= nil then
THTD_AddItemToListByName(item.card_poor_player_id, itemName)
end
if isSold ~= true then
item:RemoveSelf()
end
end
-- 同步卡池
function SetNetTableTowerPlayerList(playerId)
local steamid = PlayerResource:GetSteamID(playerId)
CustomNetTables:SetTableValue("TowerListInfo", "cardlist"..tostring(steamid), towerPlayerList[playerId+1])
end
-- 同步当前塔清单
function SetNetTableTowerList(caster)
local hero = GameRules.HeroList[caster:GetPlayerOwnerID()]
if hero == nil then return end
local towerList = {}
for k,v in pairs(hero.thtd_hero_tower_list) do
towerList[k] = v:GetEntityIndex()
end
local steamid = PlayerResource:GetSteamID(hero:GetPlayerOwnerID())
CustomNetTables:SetTableValue("TowerListInfo", "towerlist"..tostring(steamid), towerList)
end
-- 获取现实时间,格式为: 2019-04-19 10:00:00
function GetRealDateTime()
local date = GetSystemDate() --04/12/19 月 日 年
local time = GetSystemTime() --00:10:43 时 分 秒
return "20"..string.sub(date,7,8).."-"..string.sub(date,1,2).."-"..string.sub(date,4,5).." "..time
end
-- 判断当前时间是否超过了指定时间,格式必须为 2019-04-19 10:00:00
function IsEndByDateTime(endDateTime)
local currentDateTime = GetRealDateTime()
if GameRules.GameData.server_time ~= "" then
currentDateTime = GameRules.GameData.server_time
end
if currentDateTime > endDateTime then
return true
else
return false
end
end