添加1130

This commit is contained in:
Atsuishio 2025-04-27 14:43:49 +08:00 committed by Light_Quanta
parent 40c6256a8a
commit 68d308b175
No known key found for this signature in database
GPG key ID: 11A39A1B8C890959
12 changed files with 3699 additions and 0 deletions

View file

@ -0,0 +1,24 @@
package com.atsuishio.superbwarfare.client.model.entity;
import com.atsuishio.superbwarfare.Mod;
import com.atsuishio.superbwarfare.entity.vehicle.Hpj11Entity;
import net.minecraft.resources.ResourceLocation;
import software.bernie.geckolib.model.GeoModel;
public class Hpj11Model extends GeoModel<Hpj11Entity> {
@Override
public ResourceLocation getAnimationResource(Hpj11Entity entity) {
return null;
}
@Override
public ResourceLocation getModelResource(Hpj11Entity entity) {
return Mod.loc("geo/1130.geo.json");
}
@Override
public ResourceLocation getTextureResource(Hpj11Entity entity) {
return Mod.loc("textures/entity/1130.png");
}
}

View file

@ -0,0 +1,75 @@
package com.atsuishio.superbwarfare.client.renderer.entity;
import com.atsuishio.superbwarfare.client.model.entity.Hpj11Model;
import com.atsuishio.superbwarfare.entity.vehicle.Hpj11Entity;
import com.atsuishio.superbwarfare.event.ClientEventHandler;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.math.Axis;
import net.minecraft.client.CameraType;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.player.Player;
import org.jetbrains.annotations.NotNull;
import software.bernie.geckolib.cache.object.BakedGeoModel;
import software.bernie.geckolib.cache.object.GeoBone;
import software.bernie.geckolib.renderer.GeoEntityRenderer;
public class Hpj11Renderer extends GeoEntityRenderer<Hpj11Entity> {
public Hpj11Renderer(EntityRendererProvider.Context renderManager) {
super(renderManager, new Hpj11Model());
this.shadowRadius = 1.5f;
// this.addRenderLayer(new Mk42Layer(this));
}
@Override
public RenderType getRenderType(Hpj11Entity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) {
return RenderType.entityTranslucent(getTextureLocation(animatable));
}
@Override
public void preRender(PoseStack poseStack, Hpj11Entity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) {
float scale = 1f;
this.scaleHeight = scale;
this.scaleWidth = scale;
super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color);
}
@Override
public void render(Hpj11Entity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, @NotNull MultiBufferSource bufferIn, int packedLightIn) {
poseStack.pushPose();
poseStack.mulPose(Axis.YP.rotationDegrees(-Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot())));
super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn);
poseStack.popPose();
}
@Override
public void renderRecursively(PoseStack poseStack, Hpj11Entity animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) {
String name = bone.getName();
if (name.equals("root")) {
Player player = Minecraft.getInstance().player;
bone.setHidden(ClientEventHandler.zoomVehicle && animatable.getFirstPassenger() == player);
}
if (name.equals("radar2")) {
Player player = Minecraft.getInstance().player;
bone.setHidden(animatable.getFirstPassenger() == player && Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON);
}
if (name.equals("roll") || name.equals("rdr") || name.equals("rdr2")) {
bone.setRotX(-Mth.lerp(partialTick, animatable.xRotO, animatable.getXRot()) * Mth.DEG_TO_RAD);
}
if (name.equals("paoguanroll")) {
bone.setRotZ(-Mth.lerp(partialTick, animatable.gunRotO, animatable.getGunRot()));
}
super.renderRecursively(poseStack, animatable, bone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color);
}
}

View file

@ -0,0 +1,376 @@
package com.atsuishio.superbwarfare.entity.vehicle;
import com.atsuishio.superbwarfare.Mod;
import com.atsuishio.superbwarfare.config.server.ExplosionConfig;
import com.atsuishio.superbwarfare.config.server.VehicleConfig;
import com.atsuishio.superbwarfare.entity.projectile.GunGrenadeEntity;
import com.atsuishio.superbwarfare.entity.vehicle.base.CannonEntity;
import com.atsuishio.superbwarfare.entity.vehicle.base.ThirdPersonCameraPosition;
import com.atsuishio.superbwarfare.entity.vehicle.base.VehicleEntity;
import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModifier;
import com.atsuishio.superbwarfare.entity.vehicle.weapon.SmallCannonShellWeapon;
import com.atsuishio.superbwarfare.entity.vehicle.weapon.VehicleWeapon;
import com.atsuishio.superbwarfare.init.ModDamageTypes;
import com.atsuishio.superbwarfare.init.ModItems;
import com.atsuishio.superbwarfare.init.ModSounds;
import com.atsuishio.superbwarfare.init.ModTags;
import com.atsuishio.superbwarfare.tools.CustomExplosion;
import com.atsuishio.superbwarfare.tools.InventoryTool;
import com.atsuishio.superbwarfare.tools.ParticleTool;
import com.atsuishio.superbwarfare.tools.SoundTool;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.Mth;
import net.minecraft.world.damagesource.DamageTypes;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.MoverType;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import net.neoforged.neoforge.event.EventHooks;
import org.jetbrains.annotations.NotNull;
import org.joml.Math;
import org.joml.Matrix4f;
import org.joml.Vector4f;
import software.bernie.geckolib.animatable.GeoEntity;
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
import software.bernie.geckolib.animation.AnimatableManager;
import software.bernie.geckolib.util.GeckoLibUtil;
public class Hpj11Entity extends VehicleEntity implements GeoEntity, CannonEntity {
public static final EntityDataAccessor<Integer> COOL_DOWN = SynchedEntityData.defineId(Hpj11Entity.class, EntityDataSerializers.INT);
public static final EntityDataAccessor<Float> GUN_ROTATE = SynchedEntityData.defineId(Hpj11Entity.class, EntityDataSerializers.FLOAT);
private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this);
public Hpj11Entity(EntityType<Hpj11Entity> type, Level world) {
super(type, world);
}
public float gunRot;
public float gunRotO;
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
builder.define(COOL_DOWN, 0)
.define(GUN_ROTATE, 0f);
}
@Override
public VehicleWeapon[][] initWeapons() {
return new VehicleWeapon[][]{
new VehicleWeapon[]{
new SmallCannonShellWeapon()
.damage(40)
.explosionDamage(8)
.explosionRadius(4f)
.icon(Mod.loc("textures/screens/vehicle_weapon/cannon_30mm.png"))
}
};
}
@Override
public ThirdPersonCameraPosition getThirdPersonCameraPosition(int index) {
return new ThirdPersonCameraPosition(5, 0.25, 0);
}
@Override
public void addAdditionalSaveData(CompoundTag compound) {
super.addAdditionalSaveData(compound);
compound.putInt("CoolDown", this.entityData.get(COOL_DOWN));
}
@Override
protected void readAdditionalSaveData(CompoundTag compound) {
super.readAdditionalSaveData(compound);
this.entityData.set(COOL_DOWN, compound.getInt("CoolDown"));
}
@Override
public DamageModifier getDamageModifier() {
return super.getDamageModifier()
.multiply(0.2f)
.multiply(1.5f, DamageTypes.ARROW)
.multiply(1.5f, DamageTypes.TRIDENT)
.multiply(2.5f, DamageTypes.MOB_ATTACK)
.multiply(2f, DamageTypes.MOB_ATTACK_NO_AGGRO)
.multiply(1.5f, DamageTypes.MOB_PROJECTILE)
.multiply(12.5f, DamageTypes.LAVA)
.multiply(6f, DamageTypes.EXPLOSION)
.multiply(6f, DamageTypes.PLAYER_EXPLOSION)
.multiply(2.4f, ModDamageTypes.CUSTOM_EXPLOSION)
.multiply(2f, ModDamageTypes.PROJECTILE_BOOM)
.multiply(0.75f, ModDamageTypes.MINE)
.multiply(1.5f, ModDamageTypes.CANNON_FIRE)
.multiply(0.25f, ModTags.DamageTypes.PROJECTILE)
.multiply(0.85f, ModTags.DamageTypes.PROJECTILE_ABSOLUTE)
.multiply(10f, ModDamageTypes.VEHICLE_STRIKE)
.custom((source, damage) -> getSourceAngle(source, 1f) * damage)
.custom((source, damage) -> {
if (source.getDirectEntity() instanceof GunGrenadeEntity) {
return 1.5f * damage;
}
return damage;
})
.reduce(8);
}
@Override
public @NotNull Vec3 getDeltaMovement() {
return new Vec3(0, Math.min(super.getDeltaMovement().y, 0), 0);
}
@Override
public void baseTick() {
gunRotO = this.getGunRot();
super.baseTick();
if (this.entityData.get(COOL_DOWN) > 0) {
this.entityData.set(COOL_DOWN, this.entityData.get(COOL_DOWN) - 1);
}
this.move(MoverType.SELF, this.getDeltaMovement());
if (this.onGround()) {
this.setDeltaMovement(Vec3.ZERO);
} else {
this.setDeltaMovement(this.getDeltaMovement().add(0.0, -0.04, 0.0));
}
this.entityData.set(GUN_ROTATE, this.entityData.get(GUN_ROTATE) * 0.8f);
setGunRot(getGunRot() + entityData.get(GUN_ROTATE));
if (level().isClientSide && (Math.abs(entityData.get(GUN_ROTATE)) > 0.02)) {
level().playLocalSound(this.getX(), this.getY() + this.getBbHeight() * 0.5, this.getZ(), ModSounds.TURRET_TURN.get(), this.getSoundSource(), (float) Math.min(0.2 * entityData.get(GUN_ROTATE), 1), (random.nextFloat() * 0.05f + 1), false);
}
lowHealthWarning();
}
public float getGunRot() {
return this.gunRot;
}
public void setGunRot(float pGunRot) {
this.gunRot = pGunRot;
}
@Override
public void handleClientSync() {
if (isControlledByLocalInstance()) {
interpolationSteps = 0;
syncPacketPositionCodec(getX(), getY(), getZ());
}
if (interpolationSteps <= 0) {
return;
}
double interpolatedYaw = Mth.wrapDegrees(serverYRot - (double) getYRot());
setYRot(getYRot() + (float) interpolatedYaw / (float) interpolationSteps);
setXRot(getXRot() + (float) (serverXRot - (double) getXRot()) / (float) interpolationSteps);
setRot(getYRot(), getXRot());
}
@Override
public void lerpTo(double x, double y, double z, float yRot, float xRot, int steps) {
serverYRot = yRot;
serverXRot = xRot;
this.interpolationSteps = 10;
}
@Override
public void destroy() {
if (level() instanceof ServerLevel) {
CustomExplosion explosion = new CustomExplosion(this.level(), this,
ModDamageTypes.causeCustomExplosionDamage(this.level().registryAccess(), getAttacker(), getAttacker()), 100f,
this.getX(), this.getY(), this.getZ(), 7f, ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP).setDamageMultiplier(1);
explosion.explode();
EventHooks.onExplosionStart(this.level(), explosion);
explosion.finalizeExplosion(false);
ParticleTool.spawnMediumExplosionParticles(this.level(), this.position());
}
explodePassengers();
this.discard();
}
@Override
public void positionRider(@NotNull Entity passenger, @NotNull MoveFunction callback) {
if (!this.hasPassenger(passenger)) {
return;
}
passenger.setPos(getX(), getY(), getZ());
callback.accept(passenger, getX(), getY(), getZ());
copyEntityData(passenger);
}
public void copyEntityData(Entity entity) {
float f = Mth.wrapDegrees(entity.getYRot() - getYRot());
float g = Mth.clamp(f, -90.0f, 90.0f);
entity.yRotO += g - f;
entity.setYRot(entity.getYRot() + g - f);
entity.setYHeadRot(entity.getYRot());
entity.setYBodyRot(getYRot());
}
public Vec3 driverPos(float ticks) {
Matrix4f transform = getVehicleFlatTransform(ticks);
Vector4f worldPosition = transformPosition(transform, -1.0625f, 3.25f, -1.0625f);
return new Vec3(worldPosition.x, worldPosition.y, worldPosition.z);
}
@Override
public Vec3 driverZoomPos(float ticks) {
Matrix4f transform = getVehicleFlatTransform(ticks);
Vector4f worldPosition = transformPosition(transform, 0f, 1.5f, 0.25f);
return new Vec3(worldPosition.x, worldPosition.y, worldPosition.z);
}
@Override
public void vehicleShoot(Player player, int type) {
// if (this.entityData.get(COOL_DOWN) > 0) return;
Level level = player.level();
if (level instanceof ServerLevel) {
if (!InventoryTool.hasCreativeAmmoBox(player)) {
var ammo = ModItems.SMALL_SHELL.get();
var ammoCount = InventoryTool.countItem(player.getInventory().items, ammo);
if (ammoCount <= 0) return;
InventoryTool.consumeItem(player.getInventory().items, ammo, 1);
}
var entityToSpawn = ((SmallCannonShellWeapon) getWeapon(0)).create(player);
Matrix4f transform = getVehicleFlatTransform(1);
Vector4f worldPosition = transformPosition(transform, 0f, 1.375f, 0.25f);
entityToSpawn.setPos(worldPosition.x, worldPosition.y, worldPosition.z);
entityToSpawn.shoot(getLookAngle().x, getLookAngle().y, getLookAngle().z, 30, 0.3f);
level.addFreshEntity(entityToSpawn);
if (player instanceof ServerPlayer serverPlayer) {
SoundTool.playLocalSound(serverPlayer, ModSounds.MINIGUN_FIRE_1P.get(), 2, 1);
serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.MINIGUN_FIRE_3P.get(), SoundSource.PLAYERS, 6, 1);
serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.MINIGUN_FAR.get(), SoundSource.PLAYERS, 16, 1);
serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.MINIGUN_VERYFAR.get(), SoundSource.PLAYERS, 32, 1);
}
this.entityData.set(GUN_ROTATE, entityData.get(GUN_ROTATE) + 0.5f);
// this.entityData.set(COOL_DOWN, 30);
// server.sendParticles(ParticleTypes.CAMPFIRE_COSY_SMOKE,
// this.getX() + 5 * this.getLookAngle().x,
// this.getY(),
// this.getZ() + 5 * this.getLookAngle().z,
// 100, 7, 0.02, 7, 0.005);
//
// double x = worldPosition.x + 9 * this.getLookAngle().x;
// double y = worldPosition.y + 9 * this.getLookAngle().y;
// double z = worldPosition.z + 9 * this.getLookAngle().z;
//
// server.sendParticles(ParticleTypes.CAMPFIRE_COSY_SMOKE, x, y, z, 10, 0.4, 0.4, 0.4, 0.0075);
// server.sendParticles(ParticleTypes.CLOUD, x, y, z, 10, 0.4, 0.4, 0.4, 0.0075);
//
// int count = 6;
//
// for (float i = 9.5f; i < 16; i += .5f) {
// server.sendParticles(ParticleTypes.CAMPFIRE_COSY_SMOKE,
// this.getX() + i * this.getLookAngle().x,
// this.getEyeY() + i * this.getLookAngle().y,
// this.getZ() + i * this.getLookAngle().z,
// Mth.clamp(count--, 1, 5), 0.15, 0.15, 0.15, 0.0025);
// }
}
}
@Override
public void travel() {
Entity passenger = this.getFirstPassenger();
if (passenger != null) {
float diffY = Mth.wrapDegrees(passenger.getYHeadRot() - this.getYRot());
float diffX = Mth.wrapDegrees(passenger.getXRot() - this.getXRot());
turretTurnSound(diffX, diffY, 0.95f);
this.setYRot(this.getYRot() + Mth.clamp(0.9f * diffY, -20f, 20f));
this.setXRot(Mth.clamp(this.getXRot() + Mth.clamp(0.9f * diffX, -15f, 15f), -90, 32.5f));
}
}
protected void clampRotation(Entity entity) {
float f = Mth.wrapDegrees(entity.getXRot());
float f1 = Mth.clamp(f, -90.0F, 32.5F);
entity.xRotO += f1 - f;
entity.setXRot(entity.getXRot() + f1 - f);
}
@Override
public void onPassengerTurned(@NotNull Entity entity) {
this.clampRotation(entity);
}
@Override
public void registerControllers(AnimatableManager.ControllerRegistrar data) {
// data.add(new AnimationController<>(this, "movement", 0, this::movementPredicate));
}
@Override
public AnimatableInstanceCache getAnimatableInstanceCache() {
return this.cache;
}
@Override
public float getMaxHealth() {
return VehicleConfig.MK42_HP.get();
}
@Override
public int mainGunRpm(Player player) {
return 1200;
}
@Override
public boolean canShoot(Player player) {
return true;
}
@Override
public int getAmmoCount(Player player) {
var ammo = ModItems.SMALL_SHELL.get();
return InventoryTool.countItem(player.getInventory().items, ammo);
}
@Override
public boolean hidePassenger(Entity entity) {
return true;
}
@Override
public int zoomFov() {
return 2;
}
@Override
public Vec3 getBarrelVector(float pPartialTicks) {
if (getFirstPassenger() != null) {
return getFirstPassenger().getViewVector(pPartialTicks);
}
return super.getBarrelVector(pPartialTicks);
}
@Override
public ResourceLocation getVehicleIcon() {
return Mod.loc("textures/vehicle_icon/sherman_icon.png");
}
}

View file

@ -138,6 +138,10 @@ public class ClientMouseHandler {
return 0;
}
if (player.getVehicle() instanceof Hpj11Entity) {
return ClientEventHandler.zoomVehicle ? 0.25 : 0.3;
}
if (player.getVehicle() instanceof CannonEntity) {
return ClientEventHandler.zoomVehicle ? 0.15 : 0.3;
}

View file

@ -82,6 +82,8 @@ public class ModEntities {
// Vehicles
public static final DeferredHolder<EntityType<?>, EntityType<Mk42Entity>> MK_42 = register("mk_42",
EntityType.Builder.of(Mk42Entity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).fireImmune().sized(3.4f, 3.5f));
public static final DeferredHolder<EntityType<?>, EntityType<Hpj11Entity>> HPJ_11 = register("hpj_11",
EntityType.Builder.of(Hpj11Entity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).fireImmune().sized(2.8f, 2.4f));
public static final DeferredHolder<EntityType<?>, EntityType<Mle1934Entity>> MLE_1934 = register("mle_1934",
EntityType.Builder.of(Mle1934Entity::new, MobCategory.MISC).setTrackingRange(64).setUpdateInterval(3).fireImmune().sized(4.5f, 2.8f));
public static final DeferredHolder<EntityType<?>, EntityType<AnnihilatorEntity>> ANNIHILATOR = register("annihilator",

View file

@ -48,5 +48,6 @@ public class ModEntityRenderers {
event.registerEntityRenderer(ModEntities.WATER_MASK.get(), WaterMaskEntityRenderer::new);
event.registerEntityRenderer(ModEntities.PRISM_TANK.get(), PrismTankRenderer::new);
event.registerEntityRenderer(ModEntities.SWARM_DRONE.get(), SwarmDroneRenderer::new);
event.registerEntityRenderer(ModEntities.HPJ_11.get(), Hpj11Renderer::new);
}
}

View file

@ -49,6 +49,7 @@ public class ContainerBlockItem extends BlockItem implements GeoItem {
public static final List<Supplier<ItemStack>> CONTAINER_ENTITIES = List.of(
() -> ContainerBlockItem.createInstance(ModEntities.MK_42.get()),
() -> ContainerBlockItem.createInstance(ModEntities.MLE_1934.get()),
() -> ContainerBlockItem.createInstance(ModEntities.HPJ_11.get()),
() -> ContainerBlockItem.createInstance(ModEntities.ANNIHILATOR.get()),
() -> ContainerBlockItem.createInstance(ModEntities.LASER_TOWER.get()),
() -> ContainerBlockItem.createInstance(ModEntities.SPEEDBOAT.get(), true),

View file

@ -141,6 +141,17 @@ public abstract class CameraMixin {
return;
}
if (player.getVehicle() instanceof Hpj11Entity vehicle && (Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON || ClientEventHandler.zoomVehicle)) {
setRotation(Mth.lerp(partialTicks, player.yRotO, player.getYRot()), Mth.lerp(partialTicks, player.xRotO, player.getXRot()));
if (ClientEventHandler.zoomVehicle) {
setPosition(vehicle.driverZoomPos(partialTicks).x, vehicle.driverZoomPos(partialTicks).y, vehicle.driverZoomPos(partialTicks).z);
} else {
setPosition(vehicle.driverPos(partialTicks).x, vehicle.driverPos(partialTicks).y, vehicle.driverPos(partialTicks).z);
}
info.cancel();
return;
}
if (player.getVehicle() instanceof VehicleEntity vehicle && vehicle instanceof CannonEntity cannon && (Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON || ClientEventHandler.zoomVehicle)) {
setRotation(Mth.lerp(partialTicks, player.yRotO, player.getYRot()), Mth.lerp(partialTicks, player.xRotO, player.getXRot()));
if (!(cannon instanceof AnnihilatorEntity) && ClientEventHandler.zoomVehicle) {

File diff suppressed because it is too large Load diff

View file

@ -443,6 +443,7 @@
"entity.superbwarfare.prism_tank": "Prism Tank",
"entity.superbwarfare.swarm_drone": "Swarm Drone",
"entity.superbwarfare.smoke_decoy": "Smoke",
"entity.superbwarfare.hpj_11": "H/PJ-11 CIWS",
"key.categories.superbwarfare": "Superb Warfare",
"key.superbwarfare.hold_zoom": "Zoom (Hold)",

View file

@ -442,6 +442,7 @@
"entity.superbwarfare.prism_tank": "光棱坦克",
"entity.superbwarfare.swarm_drone": "蜂群无人机",
"entity.superbwarfare.smoke_decoy": "烟雾",
"entity.superbwarfare.hpj_11": "H/PJ-11近防炮",
"key.categories.superbwarfare": "卓越前线",
"key.superbwarfare.hold_zoom": "瞄准(按住)",

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB