From 2afb878053f4233df64546c80cef779724263654 Mon Sep 17 00:00:00 2001 From: MCTBL Date: Sun, 17 May 2026 13:28:05 +0800 Subject: [PATCH] format modifier define --- .../client/pages/TiCMaterialPage.java | 33 +++----- .../library/modifier/ItemModifier.java | 2 + .../tconstruct/library/tools/ToolCore.java | 7 +- .../tconstruct/library/util/TiCBookData.java | 80 +++++++++++++++++++ .../modifiers/accessory/GloveSpeed.java | 1 - .../modifiers/armor/AModBoolean.java | 1 - .../modifiers/armor/AModInteger.java | 1 - .../modifiers/tools/ModAntiSpider.java | 1 - .../tconstruct/modifiers/tools/ModAttack.java | 1 - .../tconstruct/modifiers/tools/ModBlaze.java | 1 - .../modifiers/tools/ModBoolean.java | 1 - .../modifiers/tools/ModDurability.java | 12 ++- .../modifiers/tools/ModInteger.java | 1 - .../tconstruct/modifiers/tools/ModLapis.java | 11 +-- .../tconstruct/modifiers/tools/ModPiston.java | 1 - .../modifiers/tools/ModRedstone.java | 1 - .../tconstruct/modifiers/tools/ModSmite.java | 1 - .../java/tconstruct/tools/TinkerTools.java | 20 ++--- .../resources/assets/tinker/lang/en_US.lang | 9 +++ .../resources/assets/tinker/lang/zh_CN.lang | 1 + .../assets/tinker/manuals/materialsandyou.xml | 2 + 21 files changed, 126 insertions(+), 62 deletions(-) diff --git a/src/main/java/tconstruct/client/pages/TiCMaterialPage.java b/src/main/java/tconstruct/client/pages/TiCMaterialPage.java index 8ed1230c..6d51afca 100644 --- a/src/main/java/tconstruct/client/pages/TiCMaterialPage.java +++ b/src/main/java/tconstruct/client/pages/TiCMaterialPage.java @@ -156,37 +156,23 @@ public class TiCMaterialPage extends TiCBookPage { stringStartY += (lineHeight * 1.2); } + String abilityStr = null; + String abilityDesc = null; if (tm.shoddy() != 0) { - String abilityStr = McTextFormatter.addUnderLine(tm.ability() + ": " + Math.abs(tm.shoddy())); + abilityStr = McTextFormatter.addUnderLine(tm.ability() + ": " + Math.abs(tm.shoddy())); if (tm.shoddy() > 0) { abilityStr = McTextFormatter.addDarkRed(abilityStr); } else { abilityStr = McTextFormatter.addDarkGreen(abilityStr); } - drawStrAt(abilityStr, stringStartX, stringStartY, realScale); - - String abilityDesc = tm.abilityDesc(); - if (abilityDesc.length() != 0) { - addNewTooltipsString( - abilityDesc, - stringStartX, - stringStartY, - manual.fonts.getStringWidth(abilityStr) * realScale, - lineHeight); - } else { - addNewTooltipsString( - StatCollector.translateToLocalFormatted("tool.nodesc", tm.ability()), - stringStartX, - stringStartY, - manual.fonts.getStringWidth(abilityStr) * realScale, - lineHeight); - } - stringStartY += (lineHeight * 1.2); + abilityDesc = tm.abilityDesc(); } else if (tm.ability().length() != 0) { - String abilityStr = tm.style() + McTextFormatter.addUnderLine(tm.ability()); - drawStrAt(abilityStr, stringStartX, stringStartY, realScale); + abilityStr = tm.style() + McTextFormatter.addUnderLine(tm.ability()); + abilityDesc = tm.abilityDesc(); + } - String abilityDesc = tm.abilityDesc(); + if (abilityStr != null) { + drawStrAt(abilityStr, stringStartX, stringStartY, realScale); if (abilityDesc.length() != 0) { addNewTooltipsString( abilityDesc, @@ -203,6 +189,7 @@ public class TiCMaterialPage extends TiCBookPage { lineHeight); } stringStartY += (lineHeight * 1.2); + } GL11.glPopMatrix(); diff --git a/src/main/java/tconstruct/library/modifier/ItemModifier.java b/src/main/java/tconstruct/library/modifier/ItemModifier.java index d3253e2c..9dd5de72 100644 --- a/src/main/java/tconstruct/library/modifier/ItemModifier.java +++ b/src/main/java/tconstruct/library/modifier/ItemModifier.java @@ -15,6 +15,8 @@ public abstract class ItemModifier { public final List stacks; public final int effectIndex; public static Random random = new Random(); + public String tooltipName; + public String color; /** * Default constructor diff --git a/src/main/java/tconstruct/library/tools/ToolCore.java b/src/main/java/tconstruct/library/tools/ToolCore.java index 78c676de..ad516f51 100644 --- a/src/main/java/tconstruct/library/tools/ToolCore.java +++ b/src/main/java/tconstruct/library/tools/ToolCore.java @@ -363,28 +363,23 @@ public abstract class ToolCore extends Item implements IEnergyContainerItem, IEq tconstruct.library.tools.ToolMaterial extraMat = TConstructRegistry.getMaterial(extra); int reinforced = 0; - String style = ""; int current = headMat.reinforced(); if (current > 0) { - style = headMat.style(); reinforced = current; } current = handleMat.reinforced(); if (current > 0 && current > reinforced) { - style = handleMat.style(); reinforced = current; } if (getPartAmount() >= 3) { current = accessoryMat.reinforced(); if (current > 0 && current > reinforced) { - style = accessoryMat.style(); reinforced = current; } } if (getPartAmount() >= 4) { current = extraMat.reinforced(); if (current > 0 && current > reinforced) { - style = extraMat.style(); reinforced = current; } } @@ -392,7 +387,7 @@ public abstract class ToolCore extends Item implements IEnergyContainerItem, IEq reinforced += unbreaking - reinforced; if (reinforced > 0) { - return style + ModReinforced.getReinforcedString(reinforced); + return "\u00a75" + ModReinforced.getReinforcedString(reinforced); } return ""; } diff --git a/src/main/java/tconstruct/library/util/TiCBookData.java b/src/main/java/tconstruct/library/util/TiCBookData.java index 84516d7a..e6d09aeb 100644 --- a/src/main/java/tconstruct/library/util/TiCBookData.java +++ b/src/main/java/tconstruct/library/util/TiCBookData.java @@ -1,6 +1,7 @@ package tconstruct.library.util; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -9,7 +10,9 @@ import java.util.Set; import java.util.stream.Collectors; import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.StatCollector; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -22,11 +25,13 @@ import tconstruct.items.tools.Cutlass; import tconstruct.library.TConstructRegistry; import tconstruct.library.client.TConstructClientRegistry; import tconstruct.library.crafting.CastingRecipe; +import tconstruct.library.crafting.ModifyBuilder; import tconstruct.library.crafting.PatternBuilder; import tconstruct.library.crafting.PatternBuilder.ItemKey; import tconstruct.library.crafting.PatternBuilder.MaterialSet; import tconstruct.library.crafting.ToolBuilder; import tconstruct.library.crafting.ToolRecipe; +import tconstruct.library.modifier.ItemModifier; import tconstruct.library.tools.DualMaterialToolPart; import tconstruct.library.tools.ToolMaterial; import tconstruct.library.weaponry.AmmoItem; @@ -42,6 +47,7 @@ public class TiCBookData extends BookData { private static final String ToolPagesButtonTag = "tictoolbuttons"; private static final String MaterialsPagesButtonTag = "ticmaterialsbuttons"; + private static final String ModifiesPagesButtonTag = "ticmodifiesbuttons"; public boolean isInit = false; @@ -147,6 +153,8 @@ public class TiCBookData extends BookData { replaceMap.put(e, generateTools(e)); } else if (e.getAttribute("type").equals(MaterialsPagesButtonTag)) { replaceMap.put(e, generateMaterials(e)); + } else if (e.getAttribute("type").equals(ModifiesPagesButtonTag)) { + replaceMap.put(e, generateModifes(e)); } } replaceMap.entrySet().forEach((e) -> replaceElementWithMultiple(e.getKey(), e.getValue())); @@ -395,4 +403,76 @@ public class TiCBookData extends BookData { return navigationPages; } + + private List generateModifes(Element parent) { + List navigationPages = new ArrayList<>(); + List newPages = new ArrayList<>(); + parent.setAttribute("type", "navigation"); + + String sizeStr = parent.getAttribute("capacity"); + int size = 5 * 5; + int counter = 0; + if (sizeStr.length() != 0) { + size = Integer.parseInt(sizeStr); + size *= size; + } + + Element target = (Element) parent.cloneNode(false); + + for (ItemModifier im : ModifyBuilder.instance.itemModifiers) { + + if (im.tooltipName != null) { + String locString = "modifier.tooltip." + + EnumChatFormatting.getTextWithoutFormattingCodes(im.tooltipName).replace(" ", ""); + TConstruct.logger.info( + im.effectIndex + ": " + + im.key + + "=================================================" + + StatCollector.translateToLocal(locString)); + } else { + TConstruct.logger + .info(im.effectIndex + ": " + im.key + "================================================="); + } + List collect = im.stacks.stream().map(ItemStack::getDisplayName).collect(Collectors.toList()); + TConstruct.logger.info(Arrays.toString(collect.toArray(new String[0]))); + + // Element newB = this.doc.createElement("button"); + // newB.setAttribute("to", toolUnlocalizedName); + // + // Element itemStack = this.doc.createElement("icon"); + // itemStack.setTextContent(toolUnlocalizedName); + // + // Element desc = this.doc.createElement("text"); + // desc.setTextContent(output.getDisplayName()); + // + // newB.appendChild(itemStack); + // newB.appendChild(desc); + // target.appendChild(newB); + // + // counter++; + // if (counter >= size) { + // navigationPages.add(target); + // target = (Element) parent.cloneNode(false); + // counter = 0; + // } + // + // Element newP = this.doc.createElement("page"); + // newP.setAttribute("type", "ticcrafting"); + // newP.setAttribute("name", toolUnlocalizedName); + // + // itemStack = this.doc.createElement("icon"); + // itemStack.setTextContent(toolUnlocalizedName); + // newP.appendChild(itemStack); + // newPages.add(newP); + + } + // if (counter != 0) { + // navigationPages.add(target); + // } + + navigationPages.addAll(newPages); + + return navigationPages; + } + } diff --git a/src/main/java/tconstruct/modifiers/accessory/GloveSpeed.java b/src/main/java/tconstruct/modifiers/accessory/GloveSpeed.java index a9adf96b..f2a8a515 100644 --- a/src/main/java/tconstruct/modifiers/accessory/GloveSpeed.java +++ b/src/main/java/tconstruct/modifiers/accessory/GloveSpeed.java @@ -12,7 +12,6 @@ import tconstruct.modifiers.tools.ItemModTypeFilter; public class GloveSpeed extends ItemModTypeFilter { - String tooltipName; int max = 100; public GloveSpeed(int effect, ItemStack[] items, int[] values) { diff --git a/src/main/java/tconstruct/modifiers/armor/AModBoolean.java b/src/main/java/tconstruct/modifiers/armor/AModBoolean.java index 5a3dee06..08e1188d 100644 --- a/src/main/java/tconstruct/modifiers/armor/AModBoolean.java +++ b/src/main/java/tconstruct/modifiers/armor/AModBoolean.java @@ -15,7 +15,6 @@ import tconstruct.library.armor.ArmorPart; public class AModBoolean extends ArmorMod { String color; - String tooltipName; public AModBoolean(int effect, String tag, EnumSet armorTypes, ItemStack[] items, String c, String tip) { super(effect, tag, armorTypes, items); diff --git a/src/main/java/tconstruct/modifiers/armor/AModInteger.java b/src/main/java/tconstruct/modifiers/armor/AModInteger.java index dc209800..3f325d87 100644 --- a/src/main/java/tconstruct/modifiers/armor/AModInteger.java +++ b/src/main/java/tconstruct/modifiers/armor/AModInteger.java @@ -13,7 +13,6 @@ import tconstruct.library.armor.ArmorPart; public class AModInteger extends ArmorMod { String color; - String tooltipName; int initialIncrease; int secondaryIncrease; diff --git a/src/main/java/tconstruct/modifiers/tools/ModAntiSpider.java b/src/main/java/tconstruct/modifiers/tools/ModAntiSpider.java index 36f987b2..215b054f 100644 --- a/src/main/java/tconstruct/modifiers/tools/ModAntiSpider.java +++ b/src/main/java/tconstruct/modifiers/tools/ModAntiSpider.java @@ -5,7 +5,6 @@ import net.minecraft.nbt.NBTTagCompound; public class ModAntiSpider extends ItemModTypeFilter { - String tooltipName; int max = 4; String guiType; diff --git a/src/main/java/tconstruct/modifiers/tools/ModAttack.java b/src/main/java/tconstruct/modifiers/tools/ModAttack.java index 657eec9f..fc888168 100644 --- a/src/main/java/tconstruct/modifiers/tools/ModAttack.java +++ b/src/main/java/tconstruct/modifiers/tools/ModAttack.java @@ -10,7 +10,6 @@ import tconstruct.library.tools.ToolCore; public class ModAttack extends ItemModTypeFilter { - String tooltipName; int max; int threshold; String guiType; diff --git a/src/main/java/tconstruct/modifiers/tools/ModBlaze.java b/src/main/java/tconstruct/modifiers/tools/ModBlaze.java index ac4d588b..38e3cd1a 100644 --- a/src/main/java/tconstruct/modifiers/tools/ModBlaze.java +++ b/src/main/java/tconstruct/modifiers/tools/ModBlaze.java @@ -10,7 +10,6 @@ import tconstruct.library.tools.ToolCore; public class ModBlaze extends ItemModTypeFilter { - String tooltipName; int max; public ModBlaze(int effect, ItemStack[] items, int[] values) { diff --git a/src/main/java/tconstruct/modifiers/tools/ModBoolean.java b/src/main/java/tconstruct/modifiers/tools/ModBoolean.java index c7717937..fcfdd553 100644 --- a/src/main/java/tconstruct/modifiers/tools/ModBoolean.java +++ b/src/main/java/tconstruct/modifiers/tools/ModBoolean.java @@ -10,7 +10,6 @@ import tconstruct.library.modifier.ItemModifier; public class ModBoolean extends ItemModifier { String color; - String tooltipName; public ModBoolean(ItemStack[] items, int effect, String tag, String c, String tip) { super(items, effect, tag); diff --git a/src/main/java/tconstruct/modifiers/tools/ModDurability.java b/src/main/java/tconstruct/modifiers/tools/ModDurability.java index a30952dd..f5ca64fc 100644 --- a/src/main/java/tconstruct/modifiers/tools/ModDurability.java +++ b/src/main/java/tconstruct/modifiers/tools/ModDurability.java @@ -10,7 +10,6 @@ import tconstruct.util.config.PHConstruct; public class ModDurability extends ItemModifier { - String tooltipName; String color; int durability; float modifier; @@ -21,7 +20,16 @@ public class ModDurability extends ItemModifier { durability = dur; modifier = mod; miningLevel = level; - tooltipName = tip; + tooltipName = c + k; + color = c; + } + + public ModDurability(ItemStack[] items, int effect, int dur, float mod, int level, String k, String c) { + super(items, effect, k); + durability = dur; + modifier = mod; + miningLevel = level; + tooltipName = c + k; color = c; } diff --git a/src/main/java/tconstruct/modifiers/tools/ModInteger.java b/src/main/java/tconstruct/modifiers/tools/ModInteger.java index cf74378a..210a2ea3 100644 --- a/src/main/java/tconstruct/modifiers/tools/ModInteger.java +++ b/src/main/java/tconstruct/modifiers/tools/ModInteger.java @@ -10,7 +10,6 @@ import tconstruct.library.modifier.ItemModifier; public class ModInteger extends ItemModifier { String color; - String tooltipName; int initialIncrease; int secondaryIncrease; diff --git a/src/main/java/tconstruct/modifiers/tools/ModLapis.java b/src/main/java/tconstruct/modifiers/tools/ModLapis.java index 7752ac33..febbf421 100644 --- a/src/main/java/tconstruct/modifiers/tools/ModLapis.java +++ b/src/main/java/tconstruct/modifiers/tools/ModLapis.java @@ -10,17 +10,18 @@ import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; +import net.minecraft.util.EnumChatFormatting; import tconstruct.library.tools.ToolCore; public class ModLapis extends ItemModTypeFilter { - String tooltipName; int max = 450; public ModLapis(int effect, ItemStack[] items, int[] values) { super(effect, "Lapis", items, values); - tooltipName = "\u00a79Luck"; + this.color = EnumChatFormatting.BLUE.toString(); + this.tooltipName = color + "Luck"; } @Override @@ -49,8 +50,8 @@ public class ModLapis extends ItemModTypeFilter { if (!tags.hasKey(key)) { tags.setBoolean(key, true); - String modName = "\u00a79Lapis (0/450)"; - int tooltipIndex = addToolTip(tool, "\u00a79Luck", modName); + String modName = this.color + "Lapis (0/450)"; + int tooltipIndex = addToolTip(tool, this.color + "Luck", modName); int[] keyPair = new int[] { 0, tooltipIndex }; tags.setIntArray(key, keyPair); @@ -164,7 +165,7 @@ public class ModLapis extends ItemModTypeFilter { void updateModTag(ItemStack tool, int[] keys) { NBTTagCompound tags = tool.getTagCompound().getCompoundTag("InfiTool"); String tip = "ModifierTip" + keys[1]; - String modName = "\u00a79Lapis (" + keys[0] + "/" + max + ")"; + String modName = this.color + "Lapis (" + keys[0] + "/" + max + ")"; tags.setString(tip, modName); } diff --git a/src/main/java/tconstruct/modifiers/tools/ModPiston.java b/src/main/java/tconstruct/modifiers/tools/ModPiston.java index 5f4c005e..5363e5c2 100644 --- a/src/main/java/tconstruct/modifiers/tools/ModPiston.java +++ b/src/main/java/tconstruct/modifiers/tools/ModPiston.java @@ -10,7 +10,6 @@ import tconstruct.library.tools.ToolCore; public class ModPiston extends ItemModTypeFilter { - String tooltipName; int max = 10; public ModPiston(int effect, ItemStack[] items, int[] values) { diff --git a/src/main/java/tconstruct/modifiers/tools/ModRedstone.java b/src/main/java/tconstruct/modifiers/tools/ModRedstone.java index 54055dfc..fb899e3b 100644 --- a/src/main/java/tconstruct/modifiers/tools/ModRedstone.java +++ b/src/main/java/tconstruct/modifiers/tools/ModRedstone.java @@ -12,7 +12,6 @@ import tconstruct.library.tools.ToolCore; public class ModRedstone extends ItemModTypeFilter { - public String tooltipName; public int max = 50; public ModRedstone(int effect, ItemStack[] items, int[] values) { diff --git a/src/main/java/tconstruct/modifiers/tools/ModSmite.java b/src/main/java/tconstruct/modifiers/tools/ModSmite.java index 35027830..4f1cb3c8 100644 --- a/src/main/java/tconstruct/modifiers/tools/ModSmite.java +++ b/src/main/java/tconstruct/modifiers/tools/ModSmite.java @@ -5,7 +5,6 @@ import net.minecraft.nbt.NBTTagCompound; public class ModSmite extends ItemModTypeFilter { - String tooltipName; int max = 36; String tagName; diff --git a/src/main/java/tconstruct/tools/TinkerTools.java b/src/main/java/tconstruct/tools/TinkerTools.java index 079f17fa..76254241 100644 --- a/src/main/java/tconstruct/tools/TinkerTools.java +++ b/src/main/java/tconstruct/tools/TinkerTools.java @@ -22,7 +22,6 @@ import net.minecraft.init.Items; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.StatCollector; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.oredict.OreDictionary; import net.minecraftforge.oredict.ShapedOreRecipe; @@ -673,16 +672,8 @@ public class TinkerTools { ItemStack diamond = new ItemStack(Items.diamond); ModifyBuilder.registerModifier(new ModToolRepair()); - ModifyBuilder.registerModifier( - new ModDurability( - new ItemStack[] { diamond }, - 0, - 500, - 0f, - 3, - "Diamond", - "\u00a7b" + StatCollector.translateToLocal("modifier.tool.diamond"), - "\u00a7b")); + ModifyBuilder + .registerModifier(new ModDurability(new ItemStack[] { diamond }, 0, 500, 0f, 3, "Diamond", "\u00a7b")); ModifyBuilder.registerModifier( new ModDurability( new ItemStack[] { new ItemStack(Items.emerald) }, @@ -691,7 +682,6 @@ public class TinkerTools { 0.5f, 2, "Emerald", - "\u00a72" + StatCollector.translateToLocal("modifier.tool.emerald"), "\u00a72")); ItemStack redstoneItem = new ItemStack(Items.redstone); @@ -706,7 +696,7 @@ public class TinkerTools { "Moss", 3, "\u00a72", - StatCollector.translateToLocal("modifier.tool.moss"))); + "moss")); ItemStack blazePowder = new ItemStack(Items.blaze_powder); ModifyBuilder.registerModifier(new ModBlaze(7, new ItemStack[] { blazePowder }, new int[] { 1 })); ModifyBuilder.registerModifier( @@ -715,7 +705,7 @@ public class TinkerTools { 6, "Lava", "\u00a74", - StatCollector.translateToLocal("modifier.tool.lava"))); + "lava")); ModifyBuilder.registerModifier( new ModInteger( new ItemStack[] { new ItemStack(TinkerTools.materials, 1, 8) }, @@ -723,7 +713,7 @@ public class TinkerTools { "Necrotic", 1, "\u00a78", - StatCollector.translateToLocal("modifier.tool.necro"))); + "necro")); ModifyBuilder.registerModifier( new ModExtraModifier(new ItemStack[] { diamond, new ItemStack(Blocks.gold_block) }, "Tier1Free")); diff --git a/src/main/resources/assets/tinker/lang/en_US.lang b/src/main/resources/assets/tinker/lang/en_US.lang index f7cdb39a..b2c2bd0e 100644 --- a/src/main/resources/assets/tinker/lang/en_US.lang +++ b/src/main/resources/assets/tinker/lang/en_US.lang @@ -1198,6 +1198,15 @@ modifier.tooltip.ThaumicSenses=Thaumic Senses modifier.tooltip.Triple-Jump=Triple-Jump modifier.tooltip.ThaumicVision=Thaumic Vision modifier.tooltip.Water-Walking=Water-Walking +modifier.tooltip.Auto-Repair=Auto-Repair +modifier.tooltip.Diamond=Durability +500 +modifier.tooltip.Emerald=Durability +50% +modifier.tooltip.haste=Haste +modifier.tooltip.lava=Auto-Smelt +modifier.tooltip.moss=Auto-Repair +modifier.tooltip.necro=Life Steal +modifier.tooltip.blaze=Fiery +modifier.tooltip.Reinforced=Reinforced tile.LavaTank.name=Seared Tank option.tcon.searedtank=Seared Tank diff --git a/src/main/resources/assets/tinker/lang/zh_CN.lang b/src/main/resources/assets/tinker/lang/zh_CN.lang index e129c93a..58b397b5 100644 --- a/src/main/resources/assets/tinker/lang/zh_CN.lang +++ b/src/main/resources/assets/tinker/lang/zh_CN.lang @@ -1121,6 +1121,7 @@ modifier.tooltip.ThaumicSenses=神秘感知 modifier.tooltip.Triple-Jump=三重跳 modifier.tooltip.ThaumicVision=神秘视觉 modifier.tooltip.Water-Walking=水上行走 +modifier.tooltip.Auto-Repair=自动修复 option.tcon.searedtank=焦黑储罐 option.tcon.castingchannel=浇注道 diff --git a/src/main/resources/assets/tinker/manuals/materialsandyou.xml b/src/main/resources/assets/tinker/manuals/materialsandyou.xml index 66eaab64..32cb907c 100644 --- a/src/main/resources/assets/tinker/manuals/materialsandyou.xml +++ b/src/main/resources/assets/tinker/manuals/materialsandyou.xml @@ -153,4 +153,6 @@ + + \ No newline at end of file