reworked book lore's clientside

This commit is contained in:
Vaern 2023-06-17 18:24:29 -07:00
parent febeafe459
commit 0a8ec4a389
8 changed files with 193 additions and 354 deletions

View File

@ -7,132 +7,160 @@ import org.lwjgl.opengl.GL11;
import com.hbm.items.special.ItemBookLore.*;
import com.hbm.lib.RefStrings;
import com.hbm.util.I18nUtil;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ResourceLocation;
// and you may ask yourself: vaer, why do this? this is basically just a copy of GUIScreenGuide.
// and I would answer, shut the fuck up nerd, the guide book system is too involved for my small
// brain to use for god knows how many tidbits of lore. i'll settle for a text box and cool textures, thanks
public class GUIBookLore extends GuiScreen {
protected int xSize;
protected int ySize;
private static ResourceLocation texture = new ResourceLocation(RefStrings.MODID + ":textures/gui/book/book_lore.png");
protected int guiLeft;
protected int guiTop;
protected static int sizeX = 272;
protected static int sizeY = 182;
private NBTTagCompound tag; //Used for save-dependent information, like the MKU recipe
private BookLoreType type;
protected BookLoreType type;
protected NBTTagCompound tag;
public int itemTexture;
//judgement
protected int color;
protected GUIPage mainPage;
protected GUIPage auxPage;
protected GUIPageButton button;
int page = 0;
int maxPage;
protected int page;
protected int maxPage;
public GUIBookLore(EntityPlayer player) {
ItemStack stack = player.getHeldItem();
if(!stack.hasTagCompound()) return;
this.type = BookLoreType.getTypeFromStack(stack);
type = BookLoreType.getTypeFromStack(player.getHeldItem());
tag = player.getHeldItem().getTagCompound(); //compound is created or gotten in method above
GUIAppearance setup = type.appearance;
mainPage = setup.mainPage;
auxPage = setup.auxPage;
button = setup.button;
itemTexture = setup.itemTexture;
if(type.pages <= 1) {
xSize = auxPage.sizeX;
ySize = auxPage.sizeY;
} else {
xSize = mainPage.sizeX;
ySize = mainPage.sizeY;
}
maxPage = mainPage.isTwoPages ? (int)Math.ceil(type.pages / 2D) - 1 : type.pages - 1;
if(type == null) return;
this.tag = stack.getTagCompound();
this.color = tag.getInteger("cov_col");
if(color <= 0)
color = 0x303030;
this.maxPage = (int)Math.ceil(type.pages / 2D) - 1;
}
@Override
public void initGui() {
super.initGui();
this.guiLeft = (this.width - this.xSize) / 2;
this.guiTop = (this.height - this.ySize) / 2;
if(type == null) this.mc.thePlayer.closeScreen();
this.guiLeft = (this.width - this.sizeX) / 2;
this.guiTop = (this.height - this.sizeY) / 2;
}
@Override
public void drawScreen(int mouseX, int mouseY, float f) {
public void drawScreen(int i, int j, float f) {
this.drawDefaultBackground();
this.drawGuiContainerBackgroundLayer(f, mouseX, mouseY);
this.drawGuiContainerBackgroundLayer(f, i, j);
GL11.glDisable(GL11.GL_LIGHTING);
this.drawGuiContainerForegroundLayer(mouseX, mouseY);
this.drawGuiContainerForegroundLayer(i, j);
GL11.glEnable(GL11.GL_LIGHTING);
}
protected void drawGuiContainerBackgroundLayer(float f, int i, int j) {
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
Minecraft.getMinecraft().getTextureManager().bindTexture(texture);
if(page == maxPage && (page + 1) * 2 > type.pages) { //odd numbered pages
Minecraft.getMinecraft().getTextureManager().bindTexture(auxPage.texture);
func_146110_a(guiLeft, guiTop, auxPage.u, auxPage.v, auxPage.sizeX, auxPage.sizeY, 512, 512);
} else {
Minecraft.getMinecraft().getTextureManager().bindTexture(mainPage.texture);
func_146110_a(guiLeft, guiTop, mainPage.u, mainPage.v, mainPage.sizeX, mainPage.sizeY, 512, 512);
float r = (float)(color >> 16 & 255) / 255F;
float g = (float)(color >> 8 & 255) / 255F;
float b = (float)(color & 255) / 255F;
GL11.glColor4f(r, g, b, 1.0F);
func_146110_a(guiLeft, guiTop, 0, 0, sizeX, sizeY, 512, 512);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
func_146110_a(guiLeft + 7, guiTop + 7, 0, 182, 258, 165, 512, 512);
final boolean overY = j >= guiTop + 155 && j < guiTop + 165;
if(page > 0) {
if(overY && i >= guiLeft + 24 && i <= guiLeft + 42)
func_146110_a(guiLeft + 24, guiTop + 155, 295, 13, 18, 10, 512, 512);
else
func_146110_a(guiLeft + 24, guiTop + 155, 272, 13, 18, 10, 512, 512);
}
int width = page == maxPage && (page + 1) * 2 > type.pages ? auxPage.sizeX : mainPage.sizeX;
if(page > 0)
button.renderButton(this, width, guiLeft, guiTop, false, i, j);
if(page < maxPage)
button.renderButton(this, width, guiLeft, guiTop, true, i, j);
if(page < maxPage) {
if(overY && i >= guiLeft + 230 && i <= guiLeft + 248)
func_146110_a(guiLeft + 230, guiTop + 155, 295, 0, 18, 10, 512, 512);
else
func_146110_a(guiLeft + 230, guiTop + 155, 272, 0, 18, 10, 512, 512);
}
}
protected void drawGuiContainerForegroundLayer(int x, int y) {
String key = "book_lore." + type.keyI18n + ".page.";
if(mainPage.isTwoPages) {
int defacto = page * 2 + 1;
String text = type.resolveKey(key + defacto, tag);
for(int i = 0; i < 2; i++) {
int defacto = this.page * 2 + i; //TODO: force i18n to index from 0 instead of 1
if((page + 1) * 2 <= type.pages) { //Checks if text should be rendered as an aux or a main page
mainPage.renderText(text, fontRendererObj, guiLeft, guiTop, false);
if(defacto < this.type.pages) {
String text = I18nUtil.resolveKey(key + defacto); //TODO tag-based argument formatting
text = type.resolveKey(key + (defacto + 1), tag); //kinda awkward, but no way around it
mainPage.renderText(text, fontRendererObj, guiLeft, guiTop, true);
} else
auxPage.renderText(text, fontRendererObj, guiLeft, guiTop, false);
} else {
String text = type.resolveKey(key + (page + 1), tag);
if(page < maxPage)
mainPage.renderText(text, fontRendererObj, guiLeft, guiTop, false);
else
auxPage.renderText(text, fontRendererObj, guiLeft, guiTop, false);
float scale = 1;
int width = 100;
int widthScaled = (int) (width * scale);
List<String> lines = new ArrayList();
String[] words = text.split(" ");
lines.add(words[0]);
int indent = this.fontRendererObj.getStringWidth(words[0]);
for(int w = 1; w < words.length; w++) {
if(words[w].equals("$")) {
if(w + 1 < words.length && !words[w + 1].equals("$")) {
lines.add(words[++w]);
indent = this.fontRendererObj.getStringWidth(words[w]);
} else
lines.add("");
continue;
}
indent += this.fontRendererObj.getStringWidth(" " + words[w]);
if(indent <= widthScaled) {
String last = lines.get(lines.size() - 1);
lines.set(lines.size() - 1, last += (" " + words[w]));
} else {
lines.add(words[w]);
indent = this.fontRendererObj.getStringWidth(words[w]);
}
}
GL11.glPushMatrix();
GL11.glScalef(1F/scale, 1F/scale, 1F);
for(int l = 0; l < lines.size(); l++) {
this.fontRendererObj.drawString(lines.get(l),
(int)((guiLeft + 20 + i * 130) * scale),
(int)((guiTop + 20) * scale + (9 * l)),
0x0F0F0F);
}
GL11.glPopMatrix();
}
}
}
@Override
protected void mouseClicked(int i, int j, int k) {
int q = 0; //if both buttons are somehow simultaneously clicked then obviously something's wrong already
if(j < guiTop + 155 || j >= guiTop + 165) return;
if(page > 0)
q = button.handleInput(xSize, guiLeft, guiTop, false, i, j);
if(page < maxPage && q == 0)
q = button.handleInput(xSize, guiLeft, guiTop, true, i, j);
if(q != 0) {
if(page > 0 && i >= guiLeft + 24 && i <= guiLeft + 42) {
page--;
mc.getSoundHandler().playSound(PositionedSoundRecord.func_147674_a(new ResourceLocation("gui.button.press"), 1.0F));
}
if(page < maxPage && i >= guiLeft + 230 && i <= guiLeft + 248) {
page++;
mc.getSoundHandler().playSound(PositionedSoundRecord.func_147674_a(new ResourceLocation("gui.button.press"), 1.0F));
this.page += q;
}
}
@ -142,208 +170,4 @@ public class GUIBookLore extends GuiScreen {
this.mc.thePlayer.closeScreen();
}
}
// turn page buttons, one-page, both page textures, sizes, positions, etc.
public enum GUIAppearance {
GUIDEBOOK(new GUIPage(272, 182, new ResourceLocation(RefStrings.MODID + ":textures/gui/book/book.png")).setScale(2F).setMargins(20, 20, 20),
new GUIPageButton(18, 10, 17, 148, new ResourceLocation(RefStrings.MODID + ":textures/gui/book/notebook_and_papers.png")).setUV(263, 0, 512, 512),
0), //Guide Book
LOOSEPAPER(new GUIPage(130, 165, new ResourceLocation(RefStrings.MODID + ":textures/gui/book/notebook_and_papers.png"), false).setMargins(12, 10, 16).setUV(133, 0),
new GUIPageButton(18, 10, 17, 148, new ResourceLocation(RefStrings.MODID + ":textures/gui/book/notebook_and_papers.png")).setUV(263, 0, 512, 512),
1), //Singular loose page
LOOSEPAPERS(new GUIPage(133, 165, new ResourceLocation(RefStrings.MODID + ":textures/gui/book/notebook_and_papers.png"), false).setMargins(12, 10, 16),
new GUIPageButton(18, 10, 17, 148, new ResourceLocation(RefStrings.MODID + ":textures/gui/book/notebook_and_papers.png")).setUV(263, 0, 512, 512),
2), //Collection of loose pages
NOTEBOOK(new GUIPage(133, 165, new ResourceLocation(RefStrings.MODID + ":textures/gui/book/notebook_and_papers.png"), false).setMargins(10, 10, 16).setUV(0, 165),
new GUIPage(133, 165, new ResourceLocation(RefStrings.MODID + ":textures/gui/book/notebook_and_papers.png"), false).setMargins(10, 10, 16).setUV(133, 165),
new GUIPageButton(18, 10, 17, 148, new ResourceLocation(RefStrings.MODID + ":textures/gui/book/notebook_and_papers.png")).setUV(263, 0, 512, 512),
3);
public int itemTexture;
protected GUIPage mainPage; //"Main" page, usually two pages. GUI accounts for one-paged main pages.
protected GUIPage auxPage; //"Aux" page, AKA the final page if the max pages is oddly numbered.
//If two-sided, text will be positioned on the left page.
protected GUIPageButton button;
private GUIAppearance(GUIPage main, GUIPage aux, GUIPageButton button, int texture) {
this.mainPage = main;
this.auxPage = aux;
this.button = button;
this.itemTexture = texture;
}
private GUIAppearance(GUIPage main, GUIPageButton button, int texture) {
this.mainPage = main;
this.auxPage = main;
this.button = button;
this.itemTexture = texture;
}
}
private static class GUIPage {
protected ResourceLocation texture;
//UV positioning
protected int u = 0; //X/U pos in texture
protected int v = 0; //Y/V pos in texture
protected int sizeX; //X size of the page
protected int sizeY; //Y size of the page
//Text positioning
protected int marginInner = 10; //Margin from inner edge of page
protected int marginOuter = 10; //Margin from outer edge of page
protected int marginY = 20; //Margin from upper edge of page
protected boolean isTwoPages = true; //Has two pages to display text
protected float scale = 1.0F; //Scale of the text; larger values are smaller
protected int spacing = 9; //12 is a more comfortable spacing
protected GUIPage(int x, int y, ResourceLocation texture, boolean twoPages) {
this.sizeX = x;
this.sizeY = y;
this.texture = texture;
this.isTwoPages = twoPages;
}
protected GUIPage(int x, int y, ResourceLocation texture) {
this.sizeX = x;
this.sizeY = y;
this.texture = texture;
}
protected GUIPage setUV(int u, int v) {
this.u = u;
this.v = v;
return this;
}
protected GUIPage setScale(float scale) {
this.scale = scale;
return this;
}
protected GUIPage setMargins(int inner, int outer, int upper) {
this.marginInner = inner;
this.marginOuter = outer;
this.marginY = upper;
return this;
}
protected GUIPage setSpacing(int spacing) {
this.spacing = spacing;
return this;
}
protected void renderText(String text, FontRenderer renderer, int left, int top, boolean secondPage) {
int width = (isTwoPages ? sizeX / 2 : sizeX) - marginInner - marginOuter;
int widthScaled = (int) (width * scale);
List<String> lines = new ArrayList();
String[] words = text.split(" ");
lines.add(words[0]);
int indent = renderer.getStringWidth(words[0]);
for(int w = 1; w < words.length; w++) {
if(words[w].equals("$")) {
if(w + 1 < words.length && !words[w + 1].equals("$")) {
lines.add(words[++w]);
indent = renderer.getStringWidth(words[w]);
} else
lines.add("");
continue;
}
indent += renderer.getStringWidth(" " + words[w]);
if(indent <= widthScaled) {
String last = lines.get(lines.size() - 1);
lines.set(lines.size() - 1, last += (" " + words[w]));
} else {
lines.add(words[w]);
indent = renderer.getStringWidth(words[w]);
}
}
GL11.glPushMatrix();
GL11.glScalef(1F/scale, 1F/scale, 1F);
int sideOffset = secondPage ? sizeX / 2 + marginInner : marginOuter;
for(int l = 0; l < lines.size(); l++) {
renderer.drawString(lines.get(l), (int)((left + sideOffset) * scale), (int)((top + marginY) * scale + (spacing * l)), 4210752);
}
GL11.glPopMatrix();
}
}
private static class GUIPageButton {
protected ResourceLocation texture;
protected int sizeX; //size of a single button; full texture is 2*sizeX : 2*sizeZ
protected int sizeY;
protected int x; //x position on page, relative to edge of the page it is on.
protected int y; //y position on page, relative to the top edge of the page.
/* Left, Unsel | Right, Unsel
* Left, Sel | Right, Sel
*/
protected int u = 0; //upper lefthand corner where the button textures lie.
protected int v = 0; //assumes uniform size for each.
protected int sizeU = sizeX * 2; //Size of UV texture
protected int sizeV = sizeY * 2;
protected GUIPageButton(int sizeX, int sizeY, int x, int y, ResourceLocation tex) {
this.sizeX = sizeX;
this.sizeY = sizeY;
this.x = x;
this.y = y;
this.texture = tex;
}
protected GUIPageButton setUV(int u, int v, int sizeU, int sizeV) {
this.u = u;
this.v = v;
this.sizeU = sizeU;
this.sizeV = sizeV;
return this;
}
protected void renderButton(GuiScreen screen, int width, int left, int top, boolean rightPage, int i, int j) {
Minecraft.getMinecraft().getTextureManager().bindTexture(texture);
boolean overY = j >= top + y && j < top + y + sizeY;
if(!rightPage) {
if(i >= left + x && i < left + x + sizeX && overY) {
func_146110_a(left + x, top + y, u, v + sizeY, sizeX, sizeY, sizeU, sizeV);
} else {
func_146110_a(left + x, top + y, u, v, sizeX, sizeY, sizeU, sizeV);
}
} else {
if(i >= left + width - x - sizeX && i < left + width - x && overY) {
func_146110_a(left + width - x - sizeX, top + y, u + sizeX, v + sizeY, sizeX, sizeY, sizeU, sizeV);
} else {
func_146110_a(left + width - x - sizeX, top + y, u + sizeX, v, sizeX, sizeY, sizeU, sizeV);
}
}
}
protected int handleInput(int width, int left, int top, boolean rightPage, int i, int j) {
boolean overY = j >= top + y && j < top + y + sizeY;
if(!rightPage) {
if(i >= left + x && i < left + x + sizeX && overY)
return -1;
} else {
if(i >= left + width - x - sizeX && i < left + width - x && overY)
return 1;
}
return 0;
}
}
}

View File

@ -5355,7 +5355,7 @@ public class ModItems {
record_glass = new ItemModRecord("glass").setUnlocalizedName("record_glass").setCreativeTab(null).setTextureName(RefStrings.MODID + ":record_glass");
book_guide = new ItemGuideBook().setUnlocalizedName("book_guide").setCreativeTab(MainRegistry.consumableTab).setTextureName(RefStrings.MODID + ":book_guide");
book_lore = new ItemBookLore().setUnlocalizedName("book_lore").setCreativeTab(null).setTextureName(RefStrings.MODID + ":holotape");
book_lore = new ItemBookLore().setUnlocalizedName("book_lore").setCreativeTab(null).setTextureName(RefStrings.MODID + ":book_pages");
holotape_image = new ItemHolotapeImage().setUnlocalizedName("holotape_image").setCreativeTab(null).setTextureName(RefStrings.MODID + ":holotape");
holotape_damaged = new Item().setUnlocalizedName("holotape_damaged").setCreativeTab(null).setTextureName(RefStrings.MODID + ":holotape_damaged");

View File

@ -3,7 +3,6 @@ package com.hbm.items.special;
import java.util.List;
import com.hbm.inventory.gui.GUIBookLore;
import com.hbm.inventory.gui.GUIBookLore.GUIAppearance;
import com.hbm.lib.RefStrings;
import com.hbm.main.MainRegistry;
import com.hbm.tileentity.IGUIProvider;
@ -58,31 +57,53 @@ public class ItemBookLore extends Item implements IGUIProvider {
return "book_lore." + type.keyI18n;
}
protected IIcon[] icons;
//Textures
public final static String[] itemTextures = new String[] { ":book_guide", ":paper_loose", ":papers_loose", ":notebook" };
@SideOnly(Side.CLIENT) protected IIcon[] overlays;
@Override
@SideOnly(Side.CLIENT)
public void registerIcons(IIconRegister reg) {
String[] iconStrings = itemTextures;
this.icons = new IIcon[itemTextures.length];
super.registerIcons(reg);
for(int i = 0; i < icons.length; i++) {
this.icons[i] = reg.registerIcon(RefStrings.MODID + itemTextures[i]);
this.overlays = new IIcon[2];
this.overlays[0] = reg.registerIcon(RefStrings.MODID + ":book_cover");
this.overlays[1] = reg.registerIcon(RefStrings.MODID + ":book_title");
}
@Override
@SideOnly(Side.CLIENT)
public boolean requiresMultipleRenderPasses() { return true; }
@Override
public int getRenderPasses(int metadata) { return 3; }
@Override
@SideOnly(Side.CLIENT)
public IIcon getIconFromDamageForRenderPass(int meta, int pass) {
if(pass == 0) return this.itemIcon;
return overlays[pass - 1];
}
@Override
@SideOnly(Side.CLIENT)
public int getColorFromItemStack(ItemStack stack, int pass) {
switch(pass) {
default: return 0xFFFFFF;
case 1: //book cover
if(stack.hasTagCompound()) {
int color = stack.stackTagCompound.getInteger("cov_col");
if(color > 0) return color;
}
return 0x303030;
case 2: //title color
if(stack.hasTagCompound()) {
int color = stack.stackTagCompound.getInteger("tit_col");
if(color > 0) return color;
}
return 0xFFFFFF;
}
}
@Override
public IIcon getIconIndex(ItemStack stack) {
return this.getIcon(stack, 1);
}
@Override
public IIcon getIcon(ItemStack stack, int pass) {
BookLoreType type = BookLoreType.getTypeFromStack(stack);
return this.icons[type.appearance.itemTexture];
}
@Override
public Container provideContainer(int ID, EntityPlayer player, World world, int x, int y, int z) {
@ -96,57 +117,51 @@ public class ItemBookLore extends Item implements IGUIProvider {
}
public enum BookLoreType {
TEST(true, "test", 5, GUIAppearance.NOTEBOOK),
BOOK_IODINE(true, "book_iodine", 3, GUIAppearance.LOOSEPAPERS) {
TEST(true, "test", 5),
BOOK_IODINE(true, "book_iodine", 3) {
public String resolveKey(String key, NBTTagCompound tag) {
return I18nUtil.resolveKey(key, tag.getInteger("mku_slot"));
}},
BOOK_PHOSPHOROUS(true, "book_phosphorous", 2, GUIAppearance.LOOSEPAPERS) {
BOOK_PHOSPHOROUS(true, "book_phosphorous", 2) {
public String resolveKey(String key, NBTTagCompound tag) {
return I18nUtil.resolveKey(key, tag.getInteger("mku_slot"));
}},
BOOK_DUST(true, "book_dust", 3, GUIAppearance.LOOSEPAPERS) {
BOOK_DUST(true, "book_dust", 3) {
public String resolveKey(String key, NBTTagCompound tag) {
return I18nUtil.resolveKey(key, tag.getInteger("mku_slot"));
}},
BOOK_MERCURY(true, "book_mercury", 2, GUIAppearance.LOOSEPAPERS) {
BOOK_MERCURY(true, "book_mercury", 2) {
public String resolveKey(String key, NBTTagCompound tag) {
return I18nUtil.resolveKey(key, tag.getInteger("mku_slot"));
}},
BOOK_FLOWER(true, "book_flower", 2, GUIAppearance.LOOSEPAPERS) {
BOOK_FLOWER(true, "book_flower", 2) {
public String resolveKey(String key, NBTTagCompound tag) {
return I18nUtil.resolveKey(key, tag.getInteger("mku_slot"));
}},
BOOK_SYRINGE(true, "book_syringe", 2, GUIAppearance.LOOSEPAPERS) {
BOOK_SYRINGE(true, "book_syringe", 2) {
public String resolveKey(String key, NBTTagCompound tag) {
return I18nUtil.resolveKey(key, tag.getInteger("mku_slot"));
}},
RESIGNATION_NOTE(true, "resignation_note", 3, GUIAppearance.NOTEBOOK),
MEMO_STOCKS(false, "memo_stocks", 1, GUIAppearance.LOOSEPAPER),
MEMO_SCHRAB_GSA(false, "memo_schrab_gsa", 2, GUIAppearance.LOOSEPAPERS),
MEMO_SCHRAB_RD(false, "memo_schrab_rd", 4, GUIAppearance.LOOSEPAPERS),
MEMO_SCHRAB_NUKE(true, "memo_schrab_nuke", 3, GUIAppearance.LOOSEPAPERS),
RESIGNATION_NOTE(true, "resignation_note", 3),
MEMO_STOCKS(false, "memo_stocks", 1),
MEMO_SCHRAB_GSA(false, "memo_schrab_gsa", 2),
MEMO_SCHRAB_RD(false, "memo_schrab_rd", 4),
MEMO_SCHRAB_NUKE(true, "memo_schrab_nuke", 3),
;
//Why? it's quite simple; i am too burnt out and also doing it the other way
//is too inflexible for my taste
public final GUIAppearance appearance; //gui and item texture appearance
public boolean hasAuthor = false;
public final String keyI18n;
public final int pages;
private BookLoreType(Boolean author, String key, int max, GUIAppearance appearance) {
private BookLoreType(Boolean author, String key, int max) {
this.hasAuthor = author;
this.keyI18n = key;
this.pages = max;
this.appearance = appearance;
}
private BookLoreType(String key, int max, GUIAppearance appearance) {
private BookLoreType(String key, int max) {
this.keyI18n = key;
this.pages = max;
this.appearance = appearance;
}
/** Function to resolve I18n keys using potential save-dependent information, a la format specifiers. */

View File

@ -323,68 +323,68 @@ book.starter.page18=vær is just a guy who has been trapped in the grey void fea
book_lore.author=By %s
book_lore.test.name=Test
book_lore.test.author=the dude
book_lore.test.page.1=>hello anons before i begin let me clarify that i'm not gay. >Be me >This night >18 > At hanging out with my best friend with my parents gone for a few days >We've been best friends for a year now >Been drinking a bit and playing lots of video games and ordered a pizza >We were having a blast >At a certain point in the night like around 9:00 he makes a really funny joke that I don't remember but I know that it made us both laugh really hard > With out thinking I brush my right hand through his semi-curly black hair and call him a funny boy >He blushes >I realize I'm feeling flustered >We're kinda close >All of the sudden he kisses me and for some reason I kiss him back >We make love >Cuddle together and fall asleep >Wake up in the middle of the night with his head snuggled up on my chest and neck area >It feels nice but I'm not a homosexual
book_lore.test.page.2=I'm typing this as he's asleep in my arms. How do I let my best friend down nicely? I don't want to be a [redacted] /b/
book_lore.test.page.3=3
book_lore.test.page.4=4
book_lore.test.page.5=5
book_lore.test.page.0=>hello anons before i begin let me clarify that i'm not gay. >Be me >This night >18 > At hanging out with my best friend with my parents gone for a few days >We've been best friends for a year now >Been drinking a bit and playing lots of video games and ordered a pizza >We were having a blast >At a certain point in the night like around 9:00 he makes a really funny joke that I don't remember but I know that it made us both laugh really hard > With out thinking I brush my right hand through his semi-curly black hair and call him a funny boy >He blushes >I realize I'm feeling flustered >We're kinda close >All of the sudden he kisses me and for some reason I kiss him back >We make love >Cuddle together and fall asleep >Wake up in the middle of the night with his head snuggled up on my chest and neck area >It feels nice but I'm not a homosexual
book_lore.test.page.1=I'm typing this as he's asleep in my arms. How do I let my best friend down nicely? I don't want to be a [redacted] /b/
book_lore.test.page.2=3
book_lore.test.page.3=4
book_lore.test.page.4=5
book_lore.book_iodine.name=Note
book_lore.book_iodine.author=Dave
book_lore.book_iodine.page.1=alright you will not believe this, but old man weathervane finally managed to show up again since he left two weeks ago and what's more surprising is the fact that he actually decided to spill the beans on what they were doing in the canyon:
book_lore.book_iodine.page.2=apparently the morons from R&D discovered a compound that is mostly inorganic, pretty much like a toxin in nature, but get this: the dying cells will reproduce said toxin and excrete it through the skin, creating an aerosol that is highly contagious.
book_lore.book_iodine.page.3=it's just like a virus, but not a virus. the composition is weird, you can mix it in any household bottle but you do have to get the order right. the doc told me that the first ingredient which is just powdered iodine crystals goes into slot %d
book_lore.book_iodine.page.0=alright you will not believe this, but old man weathervane finally managed to show up again since he left two weeks ago and what's more surprising is the fact that he actually decided to spill the beans on what they were doing in the canyon:
book_lore.book_iodine.page.1=apparently the morons from R&D discovered a compound that is mostly inorganic, pretty much like a toxin in nature, but get this: the dying cells will reproduce said toxin and excrete it through the skin, creating an aerosol that is highly contagious.
book_lore.book_iodine.page.2=it's just like a virus, but not a virus. the composition is weird, you can mix it in any household bottle but you do have to get the order right. the doc told me that the first ingredient which is just powdered iodine crystals goes into slot %d
book_lore.book_phosphorous.name=Note
book_lore.book_phosphorous.author=Dave
book_lore.book_phosphorous.page.1=heyo, it's me again. i assume you got my last memo, the doc wasn't too happy about it. i'll have to do this quick, the dunderheads from R&D are currently moaning again, probably over money. again. anyway, doc weathervane found that the second
book_lore.book_phosphorous.page.2=ingredient is red phosphorous, whihc has to be mixed into slot %d
book_lore.book_phosphorous.page.0=heyo, it's me again. i assume you got my last memo, the doc wasn't too happy about it. i'll have to do this quick, the dunderheads from R&D are currently moaning again, probably over money. again. anyway, doc weathervane found that the second
book_lore.book_phosphorous.page.1=ingredient is red phosphorous, whihc has to be mixed into slot %d
book_lore.book_dust.name=Note
book_lore.book_dust.author=Dave
book_lore.book_dust.page.1=the doc was furious when he found out that the R&D dorks kept the one remaining sample, ranting about gross negligence this and a doomsday scenario that. i told him to chill for a minute, getting all worked up isn't good for his blood pressure, not
book_lore.book_dust.page.2=that he has much blood left to begin with. one of the R&D morons slipped some more info into last week's circular, they call their little concoction \"MKU\" whatever that means, and that it contains actual household lint. can you believe that? one of the most
book_lore.book_dust.page.3=dangerous inventions of theirs and it contains dust. strangely they also mentioned that it goes into slot %d
book_lore.book_dust.page.0=the doc was furious when he found out that the R&D dorks kept the one remaining sample, ranting about gross negligence this and a doomsday scenario that. i told him to chill for a minute, getting all worked up isn't good for his blood pressure, not
book_lore.book_dust.page.1=that he has much blood left to begin with. one of the R&D morons slipped some more info into last week's circular, they call their little concoction \"MKU\" whatever that means, and that it contains actual household lint. can you believe that? one of the most
book_lore.book_dust.page.2=dangerous inventions of theirs and it contains dust. strangely they also mentioned that it goes into slot %d
book_lore.book_mercury.name=Note
book_lore.book_mercury.author=Dave
book_lore.book_mercury.page.1=well that settles that. not counting the vomitting blood part, the toxicological report mostly resembles that of mercury poisoning. why? because our little mix also contains mercury! i just wonder where all that stuff comes from when being
book_lore.book_mercury.page.2=replicated by the body? whatever, the mercury goes into slot %d
book_lore.book_mercury.page.0=well that settles that. not counting the vomitting blood part, the toxicological report mostly resembles that of mercury poisoning. why? because our little mix also contains mercury! i just wonder where all that stuff comes from when being
book_lore.book_mercury.page.1=replicated by the body? whatever, the mercury goes into slot %d
book_lore.book_flower.name=Note
book_lore.book_flower.author=Dave
book_lore.book_flower.page.1=remember when i mentioned in my first memo that the compound is mostly anorganic? well guess what, the old man shared the fourth ingredient: ipomoea nil, a genus of flower. morning glory! it might be due to its low sulfur content, whatever might be the case,
book_lore.book_flower.page.2=it does not work with other flowers. the morning glory goes into slot %d
book_lore.book_flower.page.0=remember when i mentioned in my first memo that the compound is mostly anorganic? well guess what, the old man shared the fourth ingredient: ipomoea nil, a genus of flower. morning glory! it might be due to its low sulfur content, whatever might be the case,
book_lore.book_flower.page.1=it does not work with other flowers. the morning glory goes into slot %d
book_lore.book_syringe.name=Note
book_lore.book_syringe.author=Dave
book_lore.book_syringe.page.1=a little addendum to my fifth message, obviously you have to store this MKU stuff in a container. the R&D nuts used regular metal syringes that they got from medical. surplus ware i presume, they got thousands of needles just lying around. the metal
book_lore.book_syringe.page.2=syringe goes into slot %d
book_lore.book_syringe.page.0=a little addendum to my fifth message, obviously you have to store this MKU stuff in a container. the R&D nuts used regular metal syringes that they got from medical. surplus ware i presume, they got thousands of needles just lying around. the metal
book_lore.book_syringe.page.1=syringe goes into slot %d
book_lore.resignation_note.name=Letter of Resignation
book_lore.resignation_note.author=Kosma
book_lore.resignation_note.page.1=Management downsized our department again yesterday. Those idiots only have themselves to blame, I don't know what they were expecting after that fiasco. Who the hell leaks that sort of information? We're losing millions and
book_lore.resignation_note.page.2=it's ME who's the one out of a job now. I'M the one being asked to resign. I hope you asshats finally learn from your overabundance of mistakes and take that stick out of your ass.
book_lore.resignation_note.page.3=I'm not coming back on Friday. Just send the paycheck.
book_lore.resignation_note.page.0=Management downsized our department again yesterday. Those idiots only have themselves to blame, I don't know what they were expecting after that fiasco. Who the hell leaks that sort of information? We're losing millions and
book_lore.resignation_note.page.1=it's ME who's the one out of a job now. I'M the one being asked to resign. I hope you asshats finally learn from your overabundance of mistakes and take that stick out of your ass.
book_lore.resignation_note.page.2=I'm not coming back on Friday. Just send the paycheck.
book_lore.memo_stocks.name=Intracorporate Memorandum
book_lore.memo_stocks.page.1=Investor Relations - $ $ There's been some glaring discrepancies in the figures provided for the latest quarterly report. It would be prudent for the financial department to make some adjustments, so there won't be any concern.
book_lore.memo_stocks.page.0=Investor Relations - $ $ There's been some glaring discrepancies in the figures provided for the latest quarterly report. It would be prudent for the financial department to make some adjustments, so there won't be any concern.
book_lore.memo_schrab_gsa.name=Internal Memorandum
book_lore.memo_schrab_gsa.page.1=Contract Management - $ $ Legal has made a breakthrough with the DLA. They've awarded us with a 45 BILLION GSA Schedule for further procurement and research of saralloy. At current estimates, that would be at minimum
book_lore.memo_schrab_gsa.page.2=a 40%% profit on related operations, let alone the possibility of future contracts. Due to the confidential nature, all fiscal evidence is to remain private.
book_lore.memo_schrab_gsa.page.0=Contract Management - $ $ Legal has made a breakthrough with the DLA. They've awarded us with a 45 BILLION GSA Schedule for further procurement and research of saralloy. At current estimates, that would be at minimum
book_lore.memo_schrab_gsa.page.1=a 40%% profit on related operations, let alone the possibility of future contracts. Due to the confidential nature, all fiscal evidence is to remain private.
book_lore.memo_schrab_rd.name=Internal Memorandum
book_lore.memo_schrab_rd.page.1=Research & Development - $ $ Our main production method of saralloy has been through the new particle accelerator. However, the energy costs are exorbitantly high compared to the amount of output.
book_lore.memo_schrab_rd.page.2=Doctor Schrabauer, however, has discovered a new interaction - called "Strange Lepton Oscillation" - that could significantly reduce costs. Through a not entirely understood process, supplied electrons are transmuted into extremely
book_lore.memo_schrab_rd.page.3=high-energy photons, through a strange charm. This is an extreme exception to many established particle conversion laws, but preliminary experiments have proved that these protons transmute into up and down quarks, eventually creating saralloy.
book_lore.memo_schrab_rd.page.4=Strangely, the prototype requires Tungsten alloyed with small amounts of saralloy. In addition, a special capacitor is required to negate the leftover positive charge.
book_lore.memo_schrab_rd.page.0=Research & Development - $ $ Our main production method of saralloy has been through the new particle accelerator. However, the energy costs are exorbitantly high compared to the amount of output.
book_lore.memo_schrab_rd.page.1=Doctor Schrabauer, however, has discovered a new interaction - called "Strange Lepton Oscillation" - that could significantly reduce costs. Through a not entirely understood process, supplied electrons are transmuted into extremely
book_lore.memo_schrab_rd.page.2=high-energy photons, through a strange charm. This is an extreme exception to many established particle conversion laws, but preliminary experiments have proved that these protons transmute into up and down quarks, eventually creating saralloy.
book_lore.memo_schrab_rd.page.3=Strangely, the prototype requires Tungsten alloyed with small amounts of saralloy. In addition, a special capacitor is required to negate the leftover positive charge.
book_lore.memo_schrab_nuke.name=Research Report
book_lore.memo_schrab_nuke.author=Doctor Schrabauer
book_lore.memo_schrab_nuke.page.1=Our most recent investigation led us to the effects of nuclear explosions on materials. Thanks to our grant money, we *accidentally* tested our theory on direct saralloy synthesis from uranium.
book_lore.memo_schrab_nuke.page.2=Only our cyclotron has actually created saralloy previously. However, at our underground shot at Everwerpen, miniscule traces of saralloy were found in uranium ore at the site. All pure, metallic uranium nearby had fissioned.
book_lore.memo_schrab_nuke.page.3=As such, given enough uranium ore concentrated around an explosive, or perhaps even a dirty bomb rich in waste containing fissionable material, one could hypothetically create enough saralloy to collect manually.
book_lore.memo_schrab_nuke.page.0=Our most recent investigation led us to the effects of nuclear explosions on materials. Thanks to our grant money, we *accidentally* tested our theory on direct saralloy synthesis from uranium.
book_lore.memo_schrab_nuke.page.1=Only our cyclotron has actually created saralloy previously. However, at our underground shot at Everwerpen, miniscule traces of saralloy were found in uranium ore at the site. All pure, metallic uranium nearby had fissioned.
book_lore.memo_schrab_nuke.page.2=As such, given enough uranium ore concentrated around an explosive, or perhaps even a dirty bomb rich in waste containing fissionable material, one could hypothetically create enough saralloy to collect manually.
cannery.f1=[ Press F1 for help ]

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B