warcraft-3-w3ts-utils 0.1.11 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dist/tstl_output.lua +11424 -0
- package/dist/dist/tstl_output.lua.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/package.json +40 -39
- package/dist/utils/abilities.d.ts +2 -0
- package/dist/utils/abilities.d.ts.map +1 -0
- package/dist/utils/camera.d.ts +2 -0
- package/dist/utils/camera.d.ts.map +1 -0
- package/dist/utils/chat-command.d.ts +2 -0
- package/dist/utils/chat-command.d.ts.map +1 -0
- package/dist/utils/color.d.ts +2 -103
- package/dist/utils/color.d.ts.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/item.d.ts +2 -0
- package/dist/utils/item.d.ts.map +1 -0
- package/dist/utils/math.d.ts +2 -0
- package/dist/utils/math.d.ts.map +1 -0
- package/dist/utils/minimapIcons.d.ts +2 -0
- package/dist/utils/minimapIcons.d.ts.map +1 -0
- package/dist/utils/misc.d.ts +2 -0
- package/dist/utils/misc.d.ts.map +1 -0
- package/dist/utils/physics.d.ts +2 -0
- package/dist/utils/physics.d.ts.map +1 -0
- package/dist/utils/players.d.ts +2 -0
- package/dist/utils/players.d.ts.map +1 -0
- package/dist/utils/point.d.ts +2 -0
- package/dist/utils/point.d.ts.map +1 -0
- package/dist/utils/quests.d.ts +2 -0
- package/dist/utils/quests.d.ts.map +1 -0
- package/dist/utils/textTag.d.ts +2 -0
- package/dist/utils/textTag.d.ts.map +1 -0
- package/dist/utils/timer.d.ts +2 -0
- package/dist/utils/timer.d.ts.map +1 -0
- package/dist/utils/units.d.ts +2 -0
- package/dist/utils/units.d.ts.map +1 -0
- package/package.json +40 -39
- package/readme.md +1 -7
- package/src/index.ts +1 -0
- package/src/utils/abilities.ts +158 -0
- package/src/utils/camera.ts +63 -0
- package/src/utils/chat-command.ts +22 -0
- package/src/utils/color.ts +139 -0
- package/src/utils/index.ts +15 -0
- package/src/utils/item.ts +163 -0
- package/src/utils/math.ts +14 -0
- package/src/utils/minimapIcons.ts +34 -0
- package/src/utils/misc.ts +179 -0
- package/src/utils/physics.ts +295 -0
- package/src/utils/players.ts +213 -0
- package/src/utils/point.ts +81 -0
- package/src/utils/quests.ts +38 -0
- package/src/utils/textTag.ts +80 -0
- package/src/utils/timer.ts +14 -0
- package/src/utils/units.ts +84 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Point, Rectangle } from "w3ts";
|
|
2
|
+
const MAP_EDGE_BUFFER_DIST = 300;
|
|
3
|
+
|
|
4
|
+
export function createValidPoint(maxAttempts: number, validatorFn: (p: Point) => {}) {
|
|
5
|
+
const MAX_ATTEMPTS = 65000; // 100 was about 10 seconds; 1000 gets good coverage
|
|
6
|
+
let currentAttempts = 0;
|
|
7
|
+
const worldBounds = Rectangle.fromHandle(GetWorldBounds());
|
|
8
|
+
if (!worldBounds) return;
|
|
9
|
+
const [maxX, maxY] = [GetCameraBoundMaxX(), GetCameraBoundMaxY()];
|
|
10
|
+
|
|
11
|
+
while (currentAttempts <= MAX_ATTEMPTS) {
|
|
12
|
+
const dirX = Math.floor(Math.random() * 100) >= 50 ? 1 : -1;
|
|
13
|
+
const dirY = Math.floor(Math.random() * 100) >= 50 ? 1 : -1;
|
|
14
|
+
|
|
15
|
+
//multiply dir by the buffer distance from max bounds since we can get a negative number
|
|
16
|
+
const randX = dirX * Math.ceil(Math.random() * maxX) - dirX * MAP_EDGE_BUFFER_DIST;
|
|
17
|
+
const randY = dirY * Math.ceil(Math.random() * maxY) - dirY * MAP_EDGE_BUFFER_DIST;
|
|
18
|
+
|
|
19
|
+
const p = Point.create(randX, randY);
|
|
20
|
+
|
|
21
|
+
const isValidPoint = validatorFn(p);
|
|
22
|
+
|
|
23
|
+
if (isValidPoint) {
|
|
24
|
+
// pointsChosen.push(p);
|
|
25
|
+
return p;
|
|
26
|
+
} else {
|
|
27
|
+
//well add it here later, just testing for now
|
|
28
|
+
currentAttempts++;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function getRandomCoordinatesInCircularArea(relativeX: number, relativeY: number, radius: number) {
|
|
34
|
+
const randomTheta = Math.random() * 360;
|
|
35
|
+
const randomRadius = Math.random() * radius;
|
|
36
|
+
|
|
37
|
+
const randomX = relativeX + randomRadius * Cos(randomTheta);
|
|
38
|
+
const randomY = relativeY + randomRadius * Sin(randomTheta);
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
x: randomX,
|
|
42
|
+
y: randomY,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function getRandomCoordinatesOnCircle(relativeX: number, relativeY: number, radius: number) {
|
|
47
|
+
const randomTheta = Math.random() * 360;
|
|
48
|
+
|
|
49
|
+
const randomX = relativeX + radius * Cos(randomTheta);
|
|
50
|
+
const randomY = relativeY + radius * Sin(randomTheta);
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
x: randomX,
|
|
54
|
+
y: randomY,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Returns degrees or radians?
|
|
60
|
+
*/
|
|
61
|
+
export function getAngleBetweenPoints(x1: number, y1: number, x2: number, y2: number) {
|
|
62
|
+
const locA = Location(x1, y1);
|
|
63
|
+
const locB = Location(x2, y2);
|
|
64
|
+
|
|
65
|
+
const angle = AngleBetweenPoints(locA, locB);
|
|
66
|
+
//arc tan
|
|
67
|
+
RemoveLocation(locA);
|
|
68
|
+
RemoveLocation(locB);
|
|
69
|
+
|
|
70
|
+
return angle;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function distanceBetweenPoints(x1: number, y1: number, x2: number, y2: number) {
|
|
74
|
+
const deltaX = x1 - x2;
|
|
75
|
+
const deltaY = y1 - y2;
|
|
76
|
+
const squaredDist = deltaX * deltaX + deltaY * deltaY;
|
|
77
|
+
// const squaredDist = Math.pow(deltaX, 2) + Math.pow(deltaY, 2);
|
|
78
|
+
const dist = Math.sqrt(squaredDist);
|
|
79
|
+
|
|
80
|
+
return dist;
|
|
81
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Quest, Timer } from "w3ts";
|
|
2
|
+
import { tColor } from "./misc";
|
|
3
|
+
|
|
4
|
+
export function setup_quests() {
|
|
5
|
+
Timer.create().start(1, false, () => {
|
|
6
|
+
addQuest(
|
|
7
|
+
"Basic Game Info",
|
|
8
|
+
`\nA roguelite base assault game. \nChoose from a wide variety of units that are trained in various schools of magic and skills.\n Outsmart and counter your opponent..
|
|
9
|
+
`,
|
|
10
|
+
"ReplaceableTextures\\CommandButtons\\BTNPeasant.blp"
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
// \n${tColor("-fixSpawns", "goldenrod")}: Player 1 can only use this. This will fix add all player's spawn units to their corresponding spawn pool.
|
|
14
|
+
addQuest(
|
|
15
|
+
"Commands",
|
|
16
|
+
`
|
|
17
|
+
\n${tColor("-cam ####", "goldenrod")}: Sets the camera distance.
|
|
18
|
+
\n-playername xxxx This will change your name.
|
|
19
|
+
`,
|
|
20
|
+
"ReplaceableTextures\\WorldEditUI\\Doodad-Cinematic.blp",
|
|
21
|
+
false
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
addQuest("|cffffcc00Evolution Castle Assault v0.01|r", "Created by JediMindTrix/NihilismIsDeath", "ReplaceableTextures\\CommandButtons\\BTNClayFigurine.blp", false);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function addQuest(title: string, description: string, iconPath?: string, required: boolean = true) {
|
|
29
|
+
const q = Quest.create();
|
|
30
|
+
if (q) {
|
|
31
|
+
q.setTitle(title);
|
|
32
|
+
q.required = required;
|
|
33
|
+
q.setDescription(description);
|
|
34
|
+
if (iconPath) {
|
|
35
|
+
q.setIcon(iconPath);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { TextTag, Trigger, Unit } from "w3ts";
|
|
2
|
+
import { ptColor } from "./misc";
|
|
3
|
+
import { delayedTimer } from "./timer";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* https://www.hiveworkshop.com/threads/floating-text.149719/
|
|
7
|
+
*
|
|
8
|
+
* function CreateFloatingText takes string text, real x, real y, real heightOffset, real duration, real size returns nothing
|
|
9
|
+
local texttag tt = CreateTextTag()
|
|
10
|
+
call SetTextTagText(tt, text, size)
|
|
11
|
+
call SetTextTagPos(tt, x, y, heightOffset)
|
|
12
|
+
call SetTextTagColor(tt, 255, 255, 255, 255) // RGBA format
|
|
13
|
+
call SetTextTagVisibility(tt, true)
|
|
14
|
+
call SetTextTagLifespan(tt, duration)
|
|
15
|
+
call SetTextTagPermanent(tt, false)
|
|
16
|
+
endfunction
|
|
17
|
+
|
|
18
|
+
function ExampleUsage takes nothing returns nothing
|
|
19
|
+
call CreateFloatingText("Hello World", 0.0, 0.0, 25.0, 5.0, 10.0)
|
|
20
|
+
endfunction
|
|
21
|
+
* @param unit
|
|
22
|
+
* @param text
|
|
23
|
+
* @param duration
|
|
24
|
+
*/
|
|
25
|
+
export function createFloatingTextTagOnUnit(unit: Unit, text: string, config?: { duration?: number; yVelocity?: number; xVelocity?: number; useFade?: boolean }) {
|
|
26
|
+
const tag = TextTag.create();
|
|
27
|
+
tag?.setVisible(true);
|
|
28
|
+
|
|
29
|
+
tag?.setText(text, 10, true);
|
|
30
|
+
|
|
31
|
+
tag?.setLifespan(config?.duration === undefined ? 2 : config.duration);
|
|
32
|
+
|
|
33
|
+
if (config?.useFade !== false) {
|
|
34
|
+
tag?.setFadepoint(0.01);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
tag?.setVelocity(config?.xVelocity === undefined ? 0 : config.xVelocity, config?.yVelocity === undefined ? 0.025 : config.yVelocity);
|
|
38
|
+
tag?.setPermanent(false);
|
|
39
|
+
|
|
40
|
+
tag?.setPosUnit(unit, 10);
|
|
41
|
+
|
|
42
|
+
if (config && config.duration && config.duration === 0) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
delayedTimer(config?.duration ?? 2, () => {
|
|
47
|
+
tag?.destroy();
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function createPermanentTextTagOnPoint(text: string, x: number, y: number) {
|
|
52
|
+
const tag = TextTag.create();
|
|
53
|
+
tag?.setVisible(true);
|
|
54
|
+
|
|
55
|
+
tag?.setText(text, 20, true);
|
|
56
|
+
tag?.setLifespan(2);
|
|
57
|
+
|
|
58
|
+
tag?.setVelocity(0, 0);
|
|
59
|
+
tag?.setPermanent(true);
|
|
60
|
+
tag?.setPos(x, y, 20);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function setup_createTextForSpellCast() {
|
|
64
|
+
const t = Trigger.create();
|
|
65
|
+
|
|
66
|
+
t.registerAnyUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT);
|
|
67
|
+
|
|
68
|
+
t.addAction(() => {
|
|
69
|
+
const u = Unit.fromEvent();
|
|
70
|
+
|
|
71
|
+
if (u) {
|
|
72
|
+
const spellNumber = GetSpellAbilityId();
|
|
73
|
+
const spellName = GetAbilityName(spellNumber);
|
|
74
|
+
if (!spellName || spellName === "Default String") return;
|
|
75
|
+
//alt + 0164 ¤
|
|
76
|
+
//alt + 0149 •
|
|
77
|
+
createFloatingTextTagOnUnit(u, ptColor(u.owner, "¤ ") + spellName);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Timer } from "w3ts";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @param duration milliseconds
|
|
5
|
+
*/
|
|
6
|
+
export function delayedTimer(duration: number, cb: (...args: any[]) => any) {
|
|
7
|
+
const timer = Timer.create();
|
|
8
|
+
timer.start(duration, false, () => {
|
|
9
|
+
cb();
|
|
10
|
+
timer.destroy();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
return timer;
|
|
14
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { Group, MapPlayer, Timer, Unit } from "w3ts";
|
|
2
|
+
import { adjustGold, adjustLumber } from "./players";
|
|
3
|
+
|
|
4
|
+
export function createUnits(quantity: number, useFood: boolean, ...args: Parameters<typeof Unit.create>) {
|
|
5
|
+
const units: Unit[] = [];
|
|
6
|
+
for (let x = 0; x < quantity; x++) {
|
|
7
|
+
const u = Unit.create(...args);
|
|
8
|
+
|
|
9
|
+
if (u) {
|
|
10
|
+
u.setUseFood(useFood);
|
|
11
|
+
units.push(u);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return units;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Refund unit's gold and wood cost.
|
|
20
|
+
* @param u
|
|
21
|
+
*/
|
|
22
|
+
export function refundUnitCost(u: Unit) {
|
|
23
|
+
const gold = GetUnitGoldCost(u.typeId);
|
|
24
|
+
const wood = GetUnitWoodCost(u.typeId);
|
|
25
|
+
adjustGold(u.owner, gold);
|
|
26
|
+
adjustLumber(u.owner, wood);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Returns true if the ALIVE unit has the ability within their first 12 abilities
|
|
31
|
+
* @param unit
|
|
32
|
+
* @param abilityId
|
|
33
|
+
* @returns
|
|
34
|
+
*/
|
|
35
|
+
export function unitHasAbility(unit: Unit, abilityId: number): boolean {
|
|
36
|
+
for (let x = 0; x < 12; x++) {
|
|
37
|
+
const currentAbility = unit.getAbilityByIndex(x);
|
|
38
|
+
|
|
39
|
+
if (currentAbility && currentAbility === unit.getAbility(abilityId) && unit.isAlive()) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function unitsInRange(x: number, y: number, radius: number, cb: (unit: Unit) => void) {
|
|
48
|
+
const g = Group.create();
|
|
49
|
+
if (g) {
|
|
50
|
+
g.enumUnitsInRange(x, y, radius, () => {
|
|
51
|
+
const unit = Unit.fromFilter();
|
|
52
|
+
if (unit) {
|
|
53
|
+
cb(unit);
|
|
54
|
+
}
|
|
55
|
+
return true;
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
g.destroy();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
*
|
|
64
|
+
* @param cb
|
|
65
|
+
* @param abilityId
|
|
66
|
+
* @param owner
|
|
67
|
+
*/
|
|
68
|
+
export function useTempDummyUnit(dummyUnitCode: number, cb: (dummy: Unit) => void, abilityId: number, owner: MapPlayer, x: number, y: number, config?: { facing?: number; abilityLevel?: number; dummyLifeSpan?: number }) {
|
|
69
|
+
let dummy: Unit | undefined = undefined;
|
|
70
|
+
dummy = Unit.create(owner, dummyUnitCode, x, y, config?.facing ?? 0);
|
|
71
|
+
|
|
72
|
+
const t = Timer.create();
|
|
73
|
+
|
|
74
|
+
if (dummy) {
|
|
75
|
+
dummy.addAbility(abilityId);
|
|
76
|
+
dummy.setAbilityManaCost(abilityId, config?.abilityLevel ? config.abilityLevel - 1 : 0, 0);
|
|
77
|
+
cb(dummy);
|
|
78
|
+
|
|
79
|
+
t.start(config?.dummyLifeSpan ?? 2, false, () => {
|
|
80
|
+
dummy?.destroy();
|
|
81
|
+
t.destroy();
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|