Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Freeplace entity/crowbar melee damage #2002

Merged
merged 12 commits into from
Mar 12, 2024
16 changes: 0 additions & 16 deletions src/servers/ZoneServer2016/data/lootspawns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3344,14 +3344,6 @@ export const containerLootSpawners: {
max: 1
}
},
{
item: Items.WOOD_PLANK,
weight: 20,
spawnCount: {
min: 1,
max: 1
}
},
{
item: Items.CLOTH,
weight: 15,
Expand Down Expand Up @@ -3382,14 +3374,6 @@ export const containerLootSpawners: {
spawnChance: 50,
maxItems: 1,
items: [
{
item: Items.WOOD_PLANK,
weight: 50,
spawnCount: {
min: 1,
max: 1
}
},
{
item: Items.CANNED_FOOD01,
weight: 10,
Expand Down
38 changes: 37 additions & 1 deletion src/servers/ZoneServer2016/entities/crate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { randomIntFromInterval, isPosInRadius } from "../../../utils/utils";
import { containerLootSpawners } from "../data/lootspawns";
import { getRandomItem } from "../managers/worldobjectmanager";
import { BaseSimpleNpc } from "./basesimplenpc";
import { Effects } from "../models/enums";
import { Effects, Items } from "../models/enums";
import { CharacterRemovePlayer } from "../../../types/zone2016packets";

export function getActorModelId(actorModel: string): number {
Expand Down Expand Up @@ -135,9 +135,45 @@ export class Crate extends BaseSimpleNpc {
this.pGetSimpleProxyHealth()
);
if (this.health > 0) return;

this.generateWoodPlanks(server, damageInfo);
this.destroy(server);
}

generateWoodPlanks(server: ZoneServer2016, damageInfo: DamageInfo) {
const client = server.getClientByCharId(damageInfo.entity);
if (!client) return;

const weapon = client.character.getEquippedWeapon();
if (!weapon) return;

// 20% chance to spawn wood planks, 60% if it's a crowbar
const woodPlanksChance = Math.floor(Math.random() * 100) + 1;
const spawnChanceWoodPlank =
weapon.itemDefinitionId == Items.WEAPON_CROWBAR ? 60 : 20;

if (woodPlanksChance < spawnChanceWoodPlank) {
const woodPlankItem = server.worldObjectManager.createLootEntity(
server,
server.generateItem(Items.WOOD_PLANK),
new Float32Array([
this.state.position[0],
this.actorModelId == 9088
Nikolassparrow marked this conversation as resolved.
Show resolved Hide resolved
? this.state.position[1] + 0.1
: this.state.position[1],
this.state.position[2],
1
]),
new Float32Array([0, 0, 0, 0])
);
if (!woodPlankItem) return;
server.executeFuncForAllReadyClientsInRange((c) => {
c.spawnedEntities.add(woodPlankItem);
server.addLightweightNpc(c, woodPlankItem);
}, woodPlankItem);
}
}

destroy(server: ZoneServer2016): boolean {
this.spawnLoot(server);

Expand Down
106 changes: 64 additions & 42 deletions src/servers/ZoneServer2016/entities/lootableconstructionentity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export class LootableConstructionEntity extends BaseLootableEntity {
interactionDistance = 3;
subEntity?: SmeltingEntity | CollectingEntity;
isDecayProtected: boolean = false;
isProp: boolean = false;
constructor(
characterId: string,
transientId: number,
Expand All @@ -60,14 +61,16 @@ export class LootableConstructionEntity extends BaseLootableEntity {
scale: Float32Array,
itemDefinitionId: number,
parentObjectCharacterId: string,
subEntityType: string
subEntityType: string,
isProp = false
) {
super(characterId, transientId, actorModelId, position, rotation, server);
this.parentObjectCharacterId = parentObjectCharacterId || "";
this.itemDefinitionId = itemDefinitionId;
const itemDefinition = server.getItemDefinition(itemDefinitionId);
if (itemDefinition) this.nameId = itemDefinition.NAME_ID;
this.profileId = 999; /// mark as construction
this.isProp = isProp;

this.maxHealth = getMaxHealth(this.itemDefinitionId);
this.health = this.maxHealth;
Expand Down Expand Up @@ -267,55 +270,74 @@ export class LootableConstructionEntity extends BaseLootableEntity {
}
}

async OnMeleeHit(server: ZoneServer2016, damageInfo: DamageInfo) {
if (
this.itemDefinitionId == Items.BEE_BOX &&
damageInfo.weapon != Items.WEAPON_HAMMER_DEMOLITION
) {
const client = server.getClientByCharId(damageInfo.entity);
const dictionary = server.getEntityDictionary(this.characterId);
async handleBeeboxSwarm(server: ZoneServer2016, damageInfo: DamageInfo) {
const client = server.getClientByCharId(damageInfo.entity);
const dictionary = server.getEntityDictionary(this.characterId);
if (!client || !dictionary) return;

if (!client) return;
if (!dictionary) return;
server.sendDataToAllWithSpawnedEntity<CharacterPlayWorldCompositeEffect>(
dictionary,
this.characterId,
"Character.PlayWorldCompositeEffect",
{
characterId: this.characterId,
effectId: Effects.PFX_Bee_Swarm_Attack,
position: client.character.state.position,
effectTime: 5
}
);

server.sendDataToAllWithSpawnedEntity<CharacterPlayWorldCompositeEffect>(
dictionary,
this.characterId,
"Character.PlayWorldCompositeEffect",
{
characterId: this.characterId,
effectId: Effects.PFX_Bee_Swarm_Attack,
position: client.character.state.position,
effectTime: 5
}
);
for (let i = 0; i < 12; i++) {
const dmgInfo: DamageInfo = {
entity: "",
damage: 25
};
client.character.damage(server, dmgInfo);
await scheduler.wait(500);
}

for (let i = 0; i < 3; i++) {
const dmgInfo: DamageInfo = {
entity: "",
damage: 100
};
client.character.damage(server, dmgInfo);
await scheduler.wait(500);
}
let hudIndicator: HudIndicator | undefined = undefined;
hudIndicator = server._hudIndicators[ResourceIndicators.BEES];

let hudIndicator: HudIndicator | undefined = undefined;
hudIndicator = server._hudIndicators[ResourceIndicators.BEES];
if (!hudIndicator) return;

if (!hudIndicator) return;
if (client.character.hudIndicators[hudIndicator.typeName]) {
client.character.hudIndicators[hudIndicator.typeName].expirationTime +=
5000;
} else {
client.character.hudIndicators[hudIndicator.typeName] = {
typeName: hudIndicator.typeName,
expirationTime: Date.now() + 5000
};
server.sendHudIndicators(client);
}
}

if (client.character.hudIndicators[hudIndicator.typeName]) {
client.character.hudIndicators[hudIndicator.typeName].expirationTime +=
5000;
} else {
client.character.hudIndicators[hudIndicator.typeName] = {
typeName: hudIndicator.typeName,
expirationTime: Date.now() + 5000
};
server.sendHudIndicators(client);
}
OnMeleeHit(server: ZoneServer2016, damageInfo: DamageInfo) {
if (this.isProp) return;
if (
this.itemDefinitionId == Items.BEE_BOX &&
damageInfo.weapon != Items.WEAPON_HAMMER_DEMOLITION
) {
this.handleBeeboxSwarm(server, damageInfo);
}

server.constructionManager.OnMeleeHit(server, damageInfo, this);
}

OnProjectileHit(server: ZoneServer2016, damageInfo: DamageInfo) {
if (this.isProp) return;
let freePlaceDmgMultiplier = 1;

const dictionary = server.getEntityDictionary(this.characterId);
if (
dictionary == server._worldLootableConstruction ||
(server._worldSimpleConstruction && !this.parentObjectCharacterId)
) {
freePlaceDmgMultiplier = 2;
}
// 26 308 shots for freeplaced objects, 13 for parented objects
const damage = damageInfo.damage * (3 * freePlaceDmgMultiplier);
this.damage(server, { ...damageInfo, damage });
}
}
40 changes: 38 additions & 2 deletions src/servers/ZoneServer2016/managers/constructionmanager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1486,7 +1486,8 @@ export class ConstructionManager {
position: Float32Array,
rotation: Float32Array,
scale: Float32Array,
parentObjectCharacterId?: string
parentObjectCharacterId?: string,
isProp: boolean = false
): boolean {
const characterId = server.generateGuid(),
transientId = server.getTransientId(characterId);
Expand All @@ -1500,7 +1501,8 @@ export class ConstructionManager {
scale,
itemDefinitionId,
parentObjectCharacterId || "",
"SmeltingEntity"
"SmeltingEntity",
isProp
);

const parent = obj.getParent(server);
Expand Down Expand Up @@ -2520,6 +2522,37 @@ export class ConstructionManager {
);
}

crowbarConstructionEntity(
server: ZoneServer2016,
client: Client,
entity: ConstructionEntity,
weaponItem: LoadoutItem
) {
switch (entity.itemDefinitionId) {
case Items.CAMPFIRE:
case Items.DEW_COLLECTOR:
case Items.BEE_BOX:
case Items.ANIMAL_TRAP:
return;
}
let worldFreeplaceMultiplier = 1;
const dictionary = server.getEntityDictionary(entity.characterId);

if (
dictionary == server._worldSimpleConstruction ||
(server._worldLootableConstruction && !entity.parentObjectCharacterId)
) {
worldFreeplaceMultiplier = 2;
}

// 8 melee hits for entities with parents, 4 for freeplace world entities
entity.damage(server, {
entity: "",
damage: entity.maxHealth / (8 / worldFreeplaceMultiplier)
});
server.damageItem(client, weaponItem, 50);
}

fullyRepairFoundation(
server: ZoneServer2016,
entity: ConstructionParentEntity
Expand Down Expand Up @@ -2638,6 +2671,9 @@ export class ConstructionManager {
case Items.WEAPON_HAMMER:
this.hammerConstructionEntity(server, client, construction, weapon);
return;
case Items.WEAPON_CROWBAR:
this.crowbarConstructionEntity(server, client, construction, weapon);
return;
}

if (this.isConstructionInSecuredArea(server, construction)) {
Expand Down
18 changes: 14 additions & 4 deletions src/servers/ZoneServer2016/managers/decaymanager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ export class DecayManager {
entity:
| LootableConstructionEntity
| ConstructionDoor
| ConstructionChildEntity
| ConstructionChildEntity,
freeplaceDecayMultiplier: number = 1
) {
if (entity.isDecayProtected) {
entity.isDecayProtected = false;
Expand All @@ -173,7 +174,8 @@ export class DecayManager {

entity.damage(server, {
entity: "Server.DecayManager",
damage: entity.maxHealth / this.ticksToFullDecay
damage:
entity.maxHealth / (this.ticksToFullDecay / freeplaceDecayMultiplier)
});
}

Expand Down Expand Up @@ -243,10 +245,18 @@ export class DecayManager {
}

for (const a in server._worldLootableConstruction) {
this.decayDamage(server, server._worldLootableConstruction[a]);
this.decayDamage(
server,
server._worldLootableConstruction[a],
this.worldFreeplaceDecayMultiplier
);
}
for (const a in server._worldSimpleConstruction) {
this.decayDamage(server, server._worldSimpleConstruction[a]);
this.decayDamage(
server,
server._worldSimpleConstruction[a],
this.worldFreeplaceDecayMultiplier
);
}
for (const a in server._constructionSimple) {
const simple = server._constructionSimple[a];
Expand Down
3 changes: 2 additions & 1 deletion src/servers/ZoneServer2016/managers/worldobjectmanager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,8 @@ export class WorldObjectManager {
new Float32Array(propInstance.position),
new Float32Array(fixEulerOrder(propInstance.rotation)),
new Float32Array(propInstance.scale),
server._serverGuid
server._serverGuid,
true
);
return;
}
Expand Down
Loading