diff --git a/system.json b/system.json index 62df523..d56cde6 100644 --- a/system.json +++ b/system.json @@ -2,7 +2,7 @@ "id": "zero-engine", "title": "Zero Engine (SLA Industries)", "description": "A basic game system for SLA Industries using the Zero Engine rules.", - "version": "1.4.2", + "version": "1.4.3", "compatibility": { "minimum": 13, "verified": "14.359" diff --git a/zero-engine.mjs b/zero-engine.mjs index 9128c57..62bc70a 100644 --- a/zero-engine.mjs +++ b/zero-engine.mjs @@ -1529,7 +1529,7 @@ class ZeroEngineActorSheet extends foundry.appv1.sheets.ActorSheet { if (taxPaid > 0) { const cpr = _getAmmoCostForWeapon(weaponData); ui.notifications.warn( - `๐Ÿ’ธ Bullet Tax: ${ammoSpent} round${ammoSpent !== 1 ? 's' : ''} ร— ${cpr}c = โˆ’${taxPaid}c` + `๐Ÿ’ธ Bullet Tax: ${ammoSpent} ร— ${cpr}c (ร—2) = โˆ’${taxPaid}c charged to ${this.actor.name}` ); } } @@ -1554,7 +1554,7 @@ class ZeroEngineActorSheet extends foundry.appv1.sheets.ActorSheet { fireMode: fireMode, ammoType: ammoType, ammoSpent: isMelee ? 0 : ammoSpent, - bulletTaxPaid: isMelee ? 0 : (ammoSpent * _getAmmoCostForWeapon(weaponData)), + bulletTaxPaid: isMelee ? 0 : (ammoSpent * _getAmmoCostForWeapon(weaponData) * 2), modeBonusDice: modeBonusDice, ammoBonusDice: ammoBonusDice, modeDamageBonus: modeDamageBonus, @@ -2431,11 +2431,11 @@ class ZeroEngineActorSheet extends foundry.appv1.sheets.ActorSheet { html += `
Mode: ${weaponInfo.fireMode || 'single'} | Ammo: ${weaponInfo.ammoType || 'standard'}
`; } if (weaponInfo.ammoSpent) { - const cpr = weaponInfo.bulletTaxPaid > 0 - ? ` ยท ๐Ÿ’ธ Tax: โˆ’${weaponInfo.bulletTaxPaid}c` - : ''; const calLabel = weaponInfo.caliber ? ` [${weaponInfo.caliber} ${weaponInfo.roundType || 'std'}]` : ''; - html += `
Ammo Spent: ${weaponInfo.ammoSpent}${calLabel} (Remaining ${weaponInfo.ammo}/${weaponInfo.magazine})${cpr}
`; + const taxLine = weaponInfo.bulletTaxPaid > 0 + ? `๐Ÿ’ธ Bullet Tax: โˆ’${weaponInfo.bulletTaxPaid}c` + : ''; + html += `
Rounds fired: ${weaponInfo.ammoSpent}${calLabel}${taxLine ? ' ยท ' + taxLine : ''}
`; } html += `
`; html += `AP ${weaponInfo.apEffective ?? weaponInfo.ap}`; @@ -5802,6 +5802,36 @@ const SLA_AMMO_CATALOG = { he: { name: "10mm High Explosive", costPerRound: 35, apBonus: 0, damageMod: 1, blastRadius: 0, description: "+1 damage on impact. Fragmentation effect." } } }, + ".44": { + label: ".44 Revolver", + fitWeaponTypes: ["revolver"], + magazineDefault: 6, + rounds: { + standard: { name: ".44 Standard", costPerRound: 8, apBonus: 0, damageMod: 0, blastRadius: 0, description: "Standard heavy revolver round." }, + ap: { name: ".44 Armor Piercing", costPerRound: 24, apBonus: 2, damageMod: 0, blastRadius: 0, description: "+2 AP. Hardened penetrator." }, + he: { name: ".44 High Explosive", costPerRound: 45, apBonus: 0, damageMod: 1, blastRadius: 0, description: "+1 damage. Cavity round." } + } + }, + ".454": { + label: ".454 Heavy Pistol", + fitWeaponTypes: ["pistol"], + magazineDefault: 12, + rounds: { + standard: { name: ".454 Standard", costPerRound: 10, apBonus: 0, damageMod: 0, blastRadius: 0, description: "Large-bore semi-auto pistol round." }, + ap: { name: ".454 Armor Piercing", costPerRound: 28, apBonus: 2, damageMod: 0, blastRadius: 0, description: "+2 AP. Corporate armor buster." }, + he: { name: ".454 High Explosive", costPerRound: 50, apBonus: 0, damageMod: 1, blastRadius: 0, description: "+1 damage. Devastating at close range." } + } + }, + ".50": { + label: ".50 Heavy Pistol", + fitWeaponTypes: ["pistol"], + magazineDefault: 8, + rounds: { + standard: { name: ".50 Standard", costPerRound: 12, apBonus: 0, damageMod: 0, blastRadius: 0, description: "Anti-armor pistol cartridge." }, + ap: { name: ".50 Armor Piercing", costPerRound: 35, apBonus: 3, damageMod: 0, blastRadius: 0, description: "+3 AP. Punches through vehicle glass." }, + he: { name: ".50 High Explosive", costPerRound: 60, apBonus: 0, damageMod: 2, blastRadius: 0, description: "+2 damage. Explosive tip." } + } + }, // โ”€โ”€ SMG calibres โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ "9mm": { label: "9mm SMG", @@ -5813,7 +5843,17 @@ const SLA_AMMO_CATALOG = { he: { name: "9mm High Explosive", costPerRound: 28, apBonus: 0, damageMod: 1, blastRadius: 0, description: "+1 damage. Micro-charge detonation." } } }, - // โ”€โ”€ Assault rifle calibres โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + "3mm": { + label: "3mm Machine Pistol", + fitWeaponTypes: ["machine pistol"], + magazineDefault: 20, + rounds: { + standard: { name: "3mm Standard", costPerRound: 3, apBonus: 0, damageMod: 0, blastRadius: 0, description: "High-rate tiny caliber round. Cheap, disposable." }, + ap: { name: "3mm Armor Piercing", costPerRound: 9, apBonus: 1, damageMod: 0, blastRadius: 0, description: "+1 AP. Needle penetrator tip." }, + he: { name: "3mm High Explosive", costPerRound: 20, apBonus: 0, damageMod: 1, blastRadius: 0, description: "+1 damage. Micro-explosive." } + } + }, + // โ”€โ”€ Assault/Carbine rifle calibres โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ "5.56mm": { label: "5.56mm NATO", fitWeaponTypes: ["rifle", "assault rifle", "carbine"], @@ -5824,7 +5864,17 @@ const SLA_AMMO_CATALOG = { he: { name: "5.56mm High Explosive", costPerRound: 45, apBonus: 0, damageMod: 2, blastRadius: 1, description: "+2 damage, 1m blast. Detonates on impact." } } }, - // โ”€โ”€ Battle rifle / LMG โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + "7mm": { + label: "7mm SLA Carbine", + fitWeaponTypes: ["carbine", "lmg"], + magazineDefault: 24, + rounds: { + standard: { name: "7mm Standard", costPerRound: 10, apBonus: 0, damageMod: 0, blastRadius: 0, description: "SLA-standard intermediate carbine round." }, + ap: { name: "7mm Armor Piercing", costPerRound: 28, apBonus: 3, damageMod: 0, blastRadius: 0, description: "+3 AP. Composite penetrator." }, + he: { name: "7mm High Explosive", costPerRound: 55, apBonus: 0, damageMod: 2, blastRadius: 1, description: "+2 damage, 1m blast." } + } + }, + // โ”€โ”€ Battle rifle / Sniper โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ "7.62mm": { label: "7.62mm Battle Rifle", fitWeaponTypes: ["battle rifle", "lmg", "sniper"], @@ -5835,6 +5885,27 @@ const SLA_AMMO_CATALOG = { he: { name: "7.62mm High Explosive", costPerRound: 70, apBonus: 0, damageMod: 3, blastRadius: 2, description: "+3 damage, 2m blast. Anti-vehicle." } } }, + "8mm": { + label: "8mm Sniper", + fitWeaponTypes: ["sniper rifle", "sniper"], + magazineDefault: 10, + rounds: { + standard: { name: "8mm Standard", costPerRound: 14, apBonus: 0, damageMod: 0, blastRadius: 0, description: "High-precision sniper cartridge." }, + ap: { name: "8mm Armor Piercing", costPerRound: 40, apBonus: 4, damageMod: 0, blastRadius: 0, description: "+4 AP. Long-range penetration round." }, + he: { name: "8mm High Explosive", costPerRound: 75, apBonus: 0, damageMod: 3, blastRadius: 0, description: "+3 damage. Detonates inside target." } + } + }, + // โ”€โ”€ Shotgun โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + "12g": { + label: "12-Gauge Shotgun", + fitWeaponTypes: ["shotgun"], + magazineDefault: 8, + rounds: { + standard: { name: "12g Buckshot", costPerRound: 18, apBonus: 0, damageMod: 0, blastRadius: 0, description: "Multi-pellet scatter. Devastating close range." }, + ap: { name: "12g Sabot Slug", costPerRound: 45, apBonus: 2, damageMod: 0, blastRadius: 0, description: "+2 AP. Single hardened slug." }, + he: { name: "12g Frag Shell", costPerRound: 80, apBonus: 0, damageMod: 2, blastRadius: 1, description: "+2 damage, 1m blast. Explosive round." } + } + }, // โ”€โ”€ Heavy weapon calibres โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ "12.7mm": { label: "12.7mm Heavy Autocannon", @@ -5845,21 +5916,51 @@ const SLA_AMMO_CATALOG = { ap: { name: "12.7mm Armor Piercing", costPerRound: 65, apBonus: 5, damageMod: 0, blastRadius: 0, description: "+5 AP. Penetrates vehicle hull." }, he: { name: "12.7mm High Explosive", costPerRound: 120, apBonus: 0, damageMod: 4, blastRadius: 3, description: "+4 damage, 3m blast. Anti-materiel." } } + }, + // โ”€โ”€ Specialist calibres โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + "40mm": { + label: "40mm Grenade", + fitWeaponTypes: ["grenade", "launcher"], + magazineDefault: 6, + rounds: { + standard: { name: "40mm Fragmentation", costPerRound: 80, apBonus: 0, damageMod: 0, blastRadius: 3, description: "Standard fragmentation grenade round. 3m blast." }, + ap: { name: "40mm HEAT", costPerRound: 180, apBonus: 5, damageMod: 2, blastRadius: 1, description: "+5 AP, +2 damage. High-explosive anti-tank." }, + he: { name: "40mm Incendiary", costPerRound: 140, apBonus: 0, damageMod: 3, blastRadius: 4, description: "+3 damage, 4m blast. Burns on contact." } + } + }, + "Rail": { + label: "Rail Cannon Slug", + fitWeaponTypes: ["rail gun"], + magazineDefault: 5, + rounds: { + standard: { name: "Rail Slug Standard", costPerRound: 50, apBonus: 0, damageMod: 0, blastRadius: 0, description: "Electromagnetically accelerated tungsten slug." }, + ap: { name: "Rail Slug AP", costPerRound: 120, apBonus: 6, damageMod: 0, blastRadius: 0, description: "+6 AP. Penetrates any personal armor." }, + he: { name: "Rail Slug Explosive", costPerRound: 200, apBonus: 0, damageMod: 5, blastRadius: 2, description: "+5 damage, 2m blast. Catastrophic terminal effect." } + } } }; // Weapon type โ†’ default caliber mapping (matches weaponType field) +// Used as fallback only โ€” explicit caliber on the item always takes priority. const SLA_WEAPON_DEFAULT_CALIBER = { - "Pistol": "10mm", - "SMG": "9mm", - "Rifle": "5.56mm", - "Assault Rifle": "5.56mm", - "Battle Rifle": "7.62mm", - "Sniper": "7.62mm", - "LMG": "7.62mm", - "HW": "12.7mm", - "Heavy Weapon": "12.7mm", - "Autocannon": "12.7mm" + "Revolver": ".44", + "Pistol": "10mm", + "Machine Pistol": "3mm", + "SMG": "9mm", + "Carbine": "7mm", + "Rifle": "5.56mm", + "Assault Rifle": "5.56mm", + "Battle Rifle": "7.62mm", + "Sniper": "7.62mm", + "Sniper Rifle": "8mm", + "LMG": "7mm", + "HW": "12.7mm", + "Heavy Weapon": "12.7mm", + "Autocannon": "12.7mm", + "Shotgun": "12g", + "Launcher": "40mm", + "Grenade": "40mm", + "Rail Gun": "Rail" }; /** @@ -5896,16 +5997,18 @@ function _getAmmoModifiers(weaponData) { /** * Deduct bullet tax from actor credits and update session ammo log. - * Called after a weapon fires. + * Bullet tax = 2ร— the base round cost (ammo purchase price + field levy). + * Called immediately when a weapon fires. */ async function _applyBulletTax(actor, weaponData, roundsFired) { if (!actor || roundsFired <= 0) return 0; const costPerRound = _getAmmoCostForWeapon(weaponData); if (costPerRound <= 0) return 0; - const totalCost = costPerRound * roundsFired; + // Bullet tax is DOUBLED: base cost (ammo) + tax of equal value = 2ร— + const totalCost = costPerRound * roundsFired * 2; const currentCredits = Number(actor.system?.details?.credits ?? 0); - const newCredits = currentCredits - totalCost; + const newCredits = Math.max(0, currentCredits - totalCost); // Deduct from credits; track session bullet tax const sessionSpent = Number(actor.system?.finances?.ammoSpentSession ?? 0) + totalCost;