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(turnXminX and turnY>minY and turnY 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 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 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.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