Skip to content

Commit 62a86ce

Browse files
feat(combat): added multiple sizes for trees, fixed word filter, combat changes
added multiple sizes for trees, fixed word filter to not filter words like hello with banned words in them, added health to /set command, added weapon data for all weapons, added item data, optimized for local development, fixed knockback scale
1 parent 5671bc2 commit 62a86ce

12 files changed

+2152
-79
lines changed

.data/sanctuary.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"bannedIPs": [],
3+
"moderatorIPs": []
4+
}

package.json

+8-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
"author": "",
1212
"license": "ISC",
1313
"devDependencies": {
14-
"@types/node": "^14.0.1",
14+
"@types/node": "^14.0.24",
15+
"cz-conventional-changelog": "3.2.0",
1516
"typescript": "^3.9.2"
1617
},
1718
"dependencies": {
@@ -36,6 +37,11 @@
3637
"ws": "^7.3.1"
3738
},
3839
"engines": {
39-
"node": "10.x"
40+
"node": ">=10.x"
41+
},
42+
"config": {
43+
"commitizen": {
44+
"path": "./node_modules/cz-conventional-changelog"
45+
}
4046
}
4147
}

src/console.ts

+6
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ dispatcher.register(
146146
player.wood = resourceAmount;
147147
break;
148148

149+
case "health":
150+
case "hp":
151+
case "hitpoints":
152+
player.health = resourceAmount;
153+
break;
154+
149155
default:
150156
error("Invalid resource type " + resourceType);
151157
break;

src/gameobjects/gameobjects.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ enum GameObjectType {
1515
Cactus
1616
}
1717

18-
let gameObjectSizes: Partial<Record<GameObjectType, number>> = { };
19-
gameObjectSizes[GameObjectType.Tree] = 140;
18+
let gameObjectSizes: Partial<Record<GameObjectType, number[]>> = { };
19+
gameObjectSizes[GameObjectType.Tree] = [150, 160, 165, 175];
2020

2121
gameObjectSizes = Object.freeze(gameObjectSizes);
2222

src/items/items.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[{"group":{"id":0,"name":"food","layer":0},"name":"apple","desc":"restores 20 health when consumed","req":["food",10],"scale":22,"holdOffset":15},{"age":3,"group":{"id":0,"name":"food","layer":0},"name":"cookie","desc":"restores 40 health when consumed","req":["food",15],"scale":27,"holdOffset":15},{"age":7,"group":{"id":0,"name":"food","layer":0},"name":"cheese","desc":"restores 30 health and another 50 over 5 seconds","req":["food",25],"scale":27,"holdOffset":15},{"group":{"id":1,"name":"walls","place":true,"limit":30,"layer":0},"name":"wood wall","desc":"provides protection for your village","req":["wood",10],"projDmg":true,"health":380,"scale":50,"holdOffset":20,"placeOffset":-5},{"age":3,"group":{"id":1,"name":"walls","place":true,"limit":30,"layer":0},"name":"stone wall","desc":"provides improved protection for your village","req":["stone",25],"health":900,"scale":50,"holdOffset":20,"placeOffset":-5},{"age":7,"pre":1,"group":{"id":1,"name":"walls","place":true,"limit":30,"layer":0},"name":"castle wall","desc":"provides powerful protection for your village","req":["stone",35],"health":1500,"scale":52,"holdOffset":20,"placeOffset":-5},{"group":{"id":2,"name":"spikes","place":true,"limit":15,"layer":0},"name":"spikes","desc":"damages enemies when they touch them","req":["wood",20,"stone",5],"health":400,"dmg":20,"scale":49,"spritePadding":-23,"holdOffset":8,"placeOffset":-5},{"age":5,"group":{"id":2,"name":"spikes","place":true,"limit":15,"layer":0},"name":"greater spikes","desc":"damages enemies when they touch them","req":["wood",30,"stone",10],"health":500,"dmg":35,"scale":52,"spritePadding":-23,"holdOffset":8,"placeOffset":-5},{"age":9,"pre":1,"group":{"id":2,"name":"spikes","place":true,"limit":15,"layer":0},"name":"poison spikes","desc":"poisons enemies when they touch them","req":["wood",35,"stone",15],"health":600,"dmg":30,"pDmg":5,"scale":52,"spritePadding":-23,"holdOffset":8,"placeOffset":-5},{"age":9,"pre":2,"group":{"id":2,"name":"spikes","place":true,"limit":15,"layer":0},"name":"spinning spikes","desc":"damages enemies when they touch them","req":["wood",30,"stone",20],"health":500,"dmg":45,"turnSpeed":0.003,"scale":52,"spritePadding":-23,"holdOffset":8,"placeOffset":-5},{"group":{"id":3,"name":"mill","place":true,"limit":7,"layer":1},"name":"windmill","desc":"generates gold over time","req":["wood",50,"stone",10],"health":400,"pps":1,"turnSpeed":0.0016,"spritePadding":25,"iconLineMult":12,"scale":45,"holdOffset":20,"placeOffset":5},{"age":5,"pre":1,"group":{"id":3,"name":"mill","place":true,"limit":7,"layer":1},"name":"faster windmill","desc":"generates more gold over time","req":["wood",60,"stone",20],"health":500,"pps":1.5,"turnSpeed":0.0025,"spritePadding":25,"iconLineMult":12,"scale":47,"holdOffset":20,"placeOffset":5},{"age":8,"pre":1,"group":{"id":3,"name":"mill","place":true,"limit":7,"layer":1},"name":"power mill","desc":"generates more gold over time","req":["wood",100,"stone",50],"health":800,"pps":2,"turnSpeed":0.005,"spritePadding":25,"iconLineMult":12,"scale":47,"holdOffset":20,"placeOffset":5},{"age":5,"group":{"id":4,"name":"mine","place":true,"limit":1,"layer":0},"type":2,"name":"mine","desc":"allows you to mine stone","req":["wood",20,"stone",100],"iconLineMult":12,"scale":65,"holdOffset":20,"placeOffset":0},{"age":5,"group":{"id":11,"name":"sapling","place":true,"limit":2,"layer":0},"type":0,"name":"sapling","desc":"allows you to farm wood","req":["wood",150],"iconLineMult":12,"colDiv":0.5,"scale":110,"holdOffset":50,"placeOffset":-15},{"age":4,"group":{"id":5,"name":"trap","place":true,"limit":6,"layer":-1},"name":"pit trap","desc":"pit that traps enemies if they walk over it","req":["wood",30,"stone",30],"trap":true,"ignoreCollision":true,"hideFromEnemy":true,"health":500,"colDiv":0.2,"scale":50,"holdOffset":20,"placeOffset":-5},{"age":4,"group":{"id":6,"name":"booster","place":true,"limit":12,"layer":-1},"name":"boost pad","desc":"provides boost when stepped on","req":["stone",20,"wood",5],"ignoreCollision":true,"boostSpeed":1.5,"health":150,"colDiv":0.7,"scale":45,"holdOffset":20,"placeOffset":-5},{"age":7,"group":{"id":7,"name":"turret","place":true,"limit":2,"layer":1},"doUpdate":true,"name":"turret","desc":"defensive structure that shoots at enemies","req":["wood",200,"stone",150],"health":800,"projectile":1,"shootRange":700,"shootRate":2200,"scale":43,"holdOffset":20,"placeOffset":-5},{"age":7,"group":{"id":8,"name":"watchtower","place":true,"limit":12,"layer":1},"name":"platform","desc":"platform to shoot over walls and cross over water","req":["wood",20],"ignoreCollision":true,"zIndex":1,"health":300,"scale":43,"holdOffset":20,"placeOffset":-5},{"age":7,"group":{"id":9,"name":"buff","place":true,"limit":4,"layer":-1},"name":"healing pad","desc":"standing on it will slowly heal you","req":["wood",30,"food",10],"ignoreCollision":true,"healCol":15,"health":400,"colDiv":0.7,"scale":45,"holdOffset":20,"placeOffset":-5},{"age":9,"group":{"id":10,"name":"spawn","place":true,"limit":1,"layer":-1},"name":"spawn pad","desc":"you will spawn here when you die but it will dissapear","req":["wood",100,"stone",100],"health":400,"ignoreCollision":true,"spawnPoint":true,"scale":45,"holdOffset":20,"placeOffset":-5},{"age":7,"group":{"id":12,"name":"blocker","place":true,"limit":3,"layer":-1},"name":"blocker","desc":"blocks building in radius","req":["wood",30,"stone",25],"ignoreCollision":true,"blocker":300,"health":400,"colDiv":0.7,"scale":45,"holdOffset":20,"placeOffset":-5},{"age":7,"group":{"id":13,"name":"teleporter","place":true,"limit":2,"layer":-1},"name":"teleporter","desc":"teleports you to a random point on the map","req":["wood",60,"stone",60],"ignoreCollision":true,"teleport":true,"health":200,"colDiv":0.7,"scale":45,"holdOffset":20,"placeOffset":-5}]

src/items/items.ts

+7-52
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import weapons from './weapons.json';
2+
13
/**
24
* An enum containing the names of all the items. Saves you the effort of differentiating weapon items and other items
35
*/
@@ -79,61 +81,14 @@ function getHitTime(weapon: Weapons) {
7981
}
8082
}
8183

82-
function getWeaponAttackDetails(item: Weapons) {
83-
switch (item) {
84-
case Weapons.ToolHammer:
85-
return { kbMultiplier: 1, attackRange: 10 };
86-
default:
87-
return { kbMultiplier: 2.1, attackRange: 10 };
88-
}
84+
function getWeaponAttackDetails(item: Weapons): AttackDetails {
85+
let weapon = weapons.find(weapon => weapon.id == item);
86+
return { kbMultiplier: weapon?.knock || 1, attackRange: weapon?.range || 10 };
8987
}
9088

9189
function getWeaponDamage(item: Weapons) {
92-
switch (item) {
93-
case Weapons.ToolHammer:
94-
return 25;
95-
96-
case Weapons.Axe:
97-
return 560;
98-
99-
case Weapons.Bat:
100-
return 450;
101-
102-
case Weapons.Bow:
103-
return 785;
104-
105-
case Weapons.Crossbow:
106-
return 900;
107-
108-
case Weapons.Daggers:
109-
return 225;
110-
111-
case Weapons.GreatHammer:
112-
return 560;
113-
114-
case Weapons.McGrabby:
115-
return 900;
116-
117-
case Weapons.Musket:
118-
return 1685;
119-
120-
case Weapons.Polearm:
121-
return 900;
122-
123-
case Weapons.RepeaterCrossbow:
124-
return 450;
125-
126-
case Weapons.Shield:
127-
throw 'Shield does not have damage!';
128-
129-
case Weapons.Stick:
130-
return 560;
131-
132-
case Weapons.Sword:
133-
return 450;
134-
}
135-
136-
return 0;
90+
let weapon = weapons.find(weapon => weapon.id == item);
91+
return weapon?.dmg || 0;
13792
}
13893

13994
function getWeaponId(item: Weapons): number {

src/items/weapons.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[{"id":0,"type":0,"name":"tool hammer","desc":"tool for gathering all resources","src":"hammer_1","length":140,"width":140,"xOff":-3,"yOff":18,"dmg":25,"range":65,"gather":1,"speed":300},{"id":1,"type":0,"age":2,"name":"hand axe","desc":"gathers resources at a higher rate","src":"axe_1","length":140,"width":140,"xOff":3,"yOff":24,"dmg":30,"spdMult":1,"range":70,"gather":2,"speed":400},{"id":2,"type":0,"age":8,"pre":1,"name":"great axe","desc":"deal more damage and gather more resources","src":"great_axe_1","length":140,"width":140,"xOff":-8,"yOff":25,"dmg":35,"spdMult":1,"range":75,"gather":4,"speed":400},{"id":3,"type":0,"age":2,"name":"short sword","desc":"increased attack power but slower move speed","src":"sword_1","iPad":1.3,"length":130,"width":210,"xOff":-8,"yOff":46,"dmg":35,"spdMult":0.85,"range":110,"gather":1,"speed":300},{"id":4,"type":0,"age":8,"pre":3,"name":"katana","desc":"greater range and damage","src":"samurai_1","iPad":1.3,"length":130,"width":210,"xOff":-8,"yOff":59,"dmg":40,"spdMult":0.8,"range":118,"gather":1,"speed":300},{"id":5,"type":0,"age":2,"name":"polearm","desc":"long range melee weapon","src":"spear_1","iPad":1.3,"length":130,"width":210,"xOff":-8,"yOff":53,"dmg":45,"knock":0.2,"spdMult":0.82,"range":142,"gather":1,"speed":700},{"id":6,"type":0,"age":2,"name":"bat","desc":"fast long range melee weapon","src":"bat_1","iPad":1.3,"length":110,"width":180,"xOff":-8,"yOff":53,"dmg":20,"knock":0.7,"range":110,"gather":1,"speed":300},{"id":7,"type":0,"age":2,"name":"daggers","desc":"really fast short range weapon","src":"dagger_1","iPad":0.8,"length":110,"width":110,"xOff":18,"yOff":0,"dmg":20,"knock":0.1,"range":65,"gather":1,"hitSlow":0.1,"spdMult":1.13,"speed":100},{"id":8,"type":0,"age":2,"name":"stick","desc":"great for gathering but very weak","src":"stick_1","length":140,"width":140,"xOff":3,"yOff":24,"dmg":1,"spdMult":1,"range":70,"gather":7,"speed":400},{"id":9,"type":1,"age":6,"name":"hunting bow","desc":"bow used for ranged combat and hunting","src":"bow_1","req":["wood",4],"length":120,"width":120,"xOff":-6,"yOff":0,"projectile":0,"spdMult":0.75,"speed":600},{"id":10,"type":1,"age":6,"name":"great hammer","desc":"hammer used for destroying structures","src":"great_hammer_1","length":140,"width":140,"xOff":-9,"yOff":25,"dmg":10,"spdMult":0.88,"range":75,"sDmg":7.5,"gather":1,"speed":400},{"id":11,"type":1,"age":6,"name":"wooden shield","desc":"blocks projectiles and reduces melee damage","src":"shield_1","length":120,"width":120,"shield":0.2,"xOff":6,"yOff":0,"spdMult":0.7},{"id":12,"type":1,"age":8,"pre":9,"name":"crossbow","desc":"deals more damage and has greater range","src":"crossbow_1","req":["wood",5],"aboveHand":true,"armS":0.75,"length":120,"width":120,"xOff":-4,"yOff":0,"projectile":2,"spdMult":0.7,"speed":700},{"id":13,"type":1,"age":9,"pre":12,"name":"repeater crossbow","desc":"high firerate crossbow with reduced damage","src":"crossbow_2","req":["wood",10],"aboveHand":true,"armS":0.75,"length":120,"width":120,"xOff":-4,"yOff":0,"projectile":3,"spdMult":0.7,"speed":230},{"id":14,"type":1,"age":6,"name":"mc grabby","desc":"steals resources from enemies","src":"grab_1","length":130,"width":210,"xOff":-8,"yOff":53,"dmg":0,"steal":250,"knock":0.2,"spdMult":1.05,"range":125,"gather":0,"speed":700},{"id":15,"type":1,"age":9,"pre":12,"name":"musket","desc":"slow firerate but high damage and range","src":"musket_1","req":["stone",10],"aboveHand":true,"rec":0.35,"armS":0.6,"hndS":0.3,"hndD":1.6,"length":205,"width":205,"xOff":25,"yOff":0,"projectile":5,"hideProjectile":true,"spdMult":0.6,"speed":1500}]

src/moomoo/Game.ts

+21-17
Original file line numberDiff line numberDiff line change
@@ -64,22 +64,26 @@ export default class Game {
6464
outerLoop: for (let i = 0; i < 200; i++) {
6565
let gameObjectType =
6666
gameObjectTypes[Math.floor(Math.random() * gameObjectTypes.length)];
67-
let newGameObject = new GameObject(
68-
this.state.gameObjects.length > 0
69-
? Math.max(...this.state.gameObjects.map((gameObj) => gameObj.id)) + 1
70-
: 0,
71-
randomPos(12e3, 12e3),
72-
0,
73-
gameObjectSizes[gameObjectType],
74-
gameObjectType
75-
);
67+
let sizes = gameObjectSizes[gameObjectType];
68+
69+
if (sizes) {
70+
let newGameObject = new GameObject(
71+
this.state.gameObjects.length > 0
72+
? Math.max(...this.state.gameObjects.map((gameObj) => gameObj.id)) + 1
73+
: 0,
74+
randomPos(12e3, 12e3),
75+
0,
76+
sizes[Math.floor(Math.random() * sizes.length)],
77+
gameObjectType
78+
);
7679

77-
for (let gameObject of this.state.gameObjects) {
78-
if (Physics.collideGameObjects(gameObject, newGameObject))
79-
continue outerLoop;
80-
}
80+
for (let gameObject of this.state.gameObjects) {
81+
if (Physics.collideGameObjects(gameObject, newGameObject))
82+
continue outerLoop;
83+
}
8184

82-
this.state.gameObjects.push(newGameObject);
85+
this.state.gameObjects.push(newGameObject);
86+
}
8387
}
8488
}
8589

@@ -176,7 +180,7 @@ export default class Game {
176180

177181
async banClient(client: Client) {
178182
if (this.db) {
179-
if (!(await (await (await this.db.get("bannedIPs")).includes(client.ip)).value())){
183+
if (!(await (await (await this.db.get("bannedIPs")).includes(client.ip)).value())) {
180184
await (await (await this.db.get("bannedIPs")).push(client.ip)).write();
181185
}
182186

@@ -336,7 +340,7 @@ export default class Game {
336340
},
337341
[]
338342
)
339-
]
343+
]
340344
)
341345
)
342346
);
@@ -589,7 +593,7 @@ export default class Game {
589593
case PacketType.CHAT:
590594
for (let badWord of badWords) {
591595
if (packet.data[0].includes(badWord))
592-
packet.data[0] = packet.data[0].replace(new RegExp(badWord.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), "M" + "o".repeat(badWord.length - 1));
596+
packet.data[0] = packet.data[0].replace(new RegExp(`\\b${badWord.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`, 'g'), "M" + "o".repeat(badWord.length - 1));
593597
}
594598

595599
if (packet.data[0].startsWith("/")) {

src/moomoo/Physics.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ function movePlayer(player: Player, delta: number) {
2929
if (player.velocity.x || player.velocity.y) {
3030
let angle = Math.atan2(player.velocity.y, player.velocity.x);
3131
tryMovePlayer(player, delta, player.velocity.x, player.velocity.y);
32-
player.velocity = player.velocity.multiply(.85, .85);
32+
player.velocity = player.velocity.multiply(0.993 ** delta, 0.993 ** delta);
3333
}
3434
}
3535

@@ -51,23 +51,23 @@ function checkAttack(player: Player, angle: number, players: Player[]) {
5151
let hitPlayers: Player[] = [];
5252

5353
for (let hitPlayer of players) {
54-
if (collideCircles(getAttackLocation(player), 10, hitPlayer.location, 35 * 2))
54+
if (pointCircle(getAttackLocation(player), hitPlayer.location, 35 * 2))
5555
hitPlayers.push(hitPlayer);
5656
}
5757

5858
return hitPlayers;
5959
}
6060

6161
function collideGameObjects(gameObject1: GameObject, gameObject2: GameObject) {
62-
return collideCircles(gameObject1.location, gameObjectSizes[gameObject1.type] || 0, gameObject2.location, gameObjectSizes[gameObject2.type] || 0);
62+
return collideCircles(gameObject1.location, gameObject1.scale, gameObject2.location, gameObject1.scale);
6363
}
6464

6565
function checkAttackGameObj(player: Player, angle: number, gameObjects: GameObject[]) {
6666
let weaponDetails = getWeaponAttackDetails(player.weapon);
6767
let hitGameObjects: GameObject[] = [];
6868

6969
for (let gameObject of gameObjects) {
70-
if (collideCircles(getAttackLocation(player), 10, gameObject.location, gameObjectSizes[gameObject.type] || 0))
70+
if (pointCircle(getAttackLocation(player), gameObject.location, gameObject.scale))
7171
hitGameObjects.push(gameObject);
7272
}
7373

src/moomoo/Player.ts

-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ export default class Player extends Entity {
100100

101101
public set points(newPoints: number) {
102102
let packetFactory = PacketFactory.getInstance();
103-
console.log("send");
104103
this.client?.socket.send(
105104
packetFactory.serializePacket(
106105
new Packet(PacketType.UPDATE_STATS, ["points", newPoints, 1])

src/server.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,4 @@ server.on('upgrade', function upgrade(request, socket, head) {
7777

7878
console.startConsole();
7979

80-
server.listen(3000, () => console.log(`Sanctuary listening at https://localhost:${port}`));
80+
server.listen(port || 3000, () => console.log(`Sanctuary listening at https://localhost:${port || 3000}`));

0 commit comments

Comments
 (0)