diff --git a/src/main/java/noppes/npcs/CustomNpcsPermissions.java b/src/main/java/noppes/npcs/CustomNpcsPermissions.java index 47ec8d0e7..a41e4a7d8 100644 --- a/src/main/java/noppes/npcs/CustomNpcsPermissions.java +++ b/src/main/java/noppes/npcs/CustomNpcsPermissions.java @@ -50,7 +50,6 @@ public class CustomNpcsPermissions { public static final Permission NPC_ADVANCED_MAGIC = new Permission("customnpcs.npc.advanced.linked"); public static final Permission NPC_ADVANCED_TAGS = new Permission("customnpcs.npc.advanced.tags"); - public static final Permission GLOBAL_REMOTE = new Permission("customnpcs.global.remote"); // Save Global Preferences diff --git a/src/main/java/noppes/npcs/client/gui/GuiMagicCycleMap.java b/src/main/java/noppes/npcs/client/gui/GuiMagicCycleMap.java index d58b890df..a2322283c 100644 --- a/src/main/java/noppes/npcs/client/gui/GuiMagicCycleMap.java +++ b/src/main/java/noppes/npcs/client/gui/GuiMagicCycleMap.java @@ -109,7 +109,10 @@ public class GuiMagicCycleMap extends GuiDiagram { int targetId = entry.getKey(); if (!orderMap.containsKey(targetId)) continue; float percent = entry.getValue(); - String hover = "+" + (int) (percent * 100) + "%"; + String modifier = ""; + if(percent > 0.0) + modifier += "+"; + String hover = modifier + (int) (percent * 100) + "%"; conns.add(new DiagramConnection(m.id, targetId, percent, hover)); } } diff --git a/src/main/java/noppes/npcs/client/gui/util/GuiDiagram.java b/src/main/java/noppes/npcs/client/gui/util/GuiDiagram.java index 2f6aacb08..6d86a3609 100644 --- a/src/main/java/noppes/npcs/client/gui/util/GuiDiagram.java +++ b/src/main/java/noppes/npcs/client/gui/util/GuiDiagram.java @@ -649,69 +649,133 @@ public abstract class GuiDiagram extends Gui { // --- Arrow Drawing Methods --- protected void drawConnectionLine(int x1, int y1, int x2, int y2, DiagramConnection conn, boolean dim) { - int color = getConnectionColor(conn); - if (!useColorScaling) color = 0xFFFFFFFF; + // Look up the reverse connection. + DiagramConnection reverse = getConnectionByIds(conn.idTo, conn.idFrom); + boolean twoWay = (reverse != null); + // Only draw the arrow once (for example, when conn.idFrom is less than conn.idTo). + if (twoWay && conn.idFrom > conn.idTo) { + return; + } + if (!curvedArrows) { - GL11.glPushAttrib(GL11.GL_ENABLE_BIT); - GL11.glDisable(GL11.GL_TEXTURE_2D); - GL11.glLineWidth(2.0F); - float r = ((color >> 16) & 0xFF) / 255f; - float g = ((color >> 8) & 0xFF) / 255f; - float b = (color & 0xFF) / 255f; - if (dim) { - r *= 0.4f; - g *= 0.4f; - b *= 0.4f; + if (twoWay) { + int midX = (x1 + x2) / 2; + int midY = (y1 + y2) / 2; + int color1 = getConnectionColor(conn); + int color2 = getConnectionColor(reverse); + if (!useColorScaling) { + color1 = color2 = 0xFFFFFFFF; + } + drawColoredLine(x1, y1, midX, midY, color1, dim); + drawColoredLine(midX, midY, x2, y2, color2, dim); + } else { + int color = getConnectionColor(conn); + if (!useColorScaling) { + color = 0xFFFFFFFF; + } + drawColoredLine(x1, y1, x2, y2, color, dim); } - GL11.glColor4f(r, g, b, 1f); - GL11.glBegin(GL11.GL_LINES); - GL11.glVertex2i(x1, y1); - GL11.glVertex2i(x2, y2); - GL11.glEnd(); - GL11.glEnable(GL11.GL_TEXTURE_2D); - GL11.glPopAttrib(); } else { - // Compute two potential control points and choose the one farther from nearby icons. + // For curved arrows, compute the control point as before. Point cp1 = computeControlPoint(x1, y1, x2, y2, curveAngle); Point cp2 = computeControlPoint(x1, y1, x2, y2, -curveAngle); double d1 = getMinDistanceToIcon(cp1, conn); double d2 = getMinDistanceToIcon(cp2, conn); Point control = (d1 >= d2) ? cp1 : cp2; int segments = 400; - - GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_HINT_BIT); - GL11.glEnable(GL11.GL_BLEND); - GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); - GL11.glEnable(GL11.GL_LINE_SMOOTH); - GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST); - GL11.glDisable(GL11.GL_TEXTURE_2D); - GL11.glLineWidth(2.0F); - float rr = ((color >> 16) & 0xFF) / 255f; - float gg = ((color >> 8) & 0xFF) / 255f; - float bb = (color & 0xFF) / 255f; - if (dim) { - rr *= 0.4f; - gg *= 0.4f; - bb *= 0.4f; + if (twoWay) { + int color1 = getConnectionColor(conn); + int color2 = getConnectionColor(reverse); + if (!useColorScaling) { + color1 = color2 = 0xFFFFFFFF; + } + int halfSegments = segments / 2; + GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_HINT_BIT); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GL11.glEnable(GL11.GL_LINE_SMOOTH); + GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glLineWidth(2.0F); + setColor(color1, dim); + GL11.glBegin(GL11.GL_LINE_STRIP); + for (int i = 0; i <= halfSegments; i++) { + double t = (double) i / halfSegments; + int bx = (int) ((1 - t) * (1 - t) * x1 + 2 * (1 - t) * t * control.x + t * t * x2); + int by = (int) ((1 - t) * (1 - t) * y1 + 2 * (1 - t) * t * control.y + t * t * y2); + GL11.glVertex2i(bx, by); + } + GL11.glEnd(); + setColor(color2, dim); + GL11.glBegin(GL11.GL_LINE_STRIP); + for (int i = halfSegments; i <= segments; i++) { + double t = (double) i / segments; + int bx = (int) ((1 - t) * (1 - t) * x1 + 2 * (1 - t) * t * control.x + t * t * x2); + int by = (int) ((1 - t) * (1 - t) * y1 + 2 * (1 - t) * t * control.y + t * t * y2); + GL11.glVertex2i(bx, by); + } + GL11.glEnd(); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glDisable(GL11.GL_LINE_SMOOTH); + GL11.glDisable(GL11.GL_BLEND); + GL11.glPopAttrib(); + } else { + int color = getConnectionColor(conn); + if (!useColorScaling) { + color = 0xFFFFFFFF; + } + GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_HINT_BIT); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GL11.glEnable(GL11.GL_LINE_SMOOTH); + GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glLineWidth(2.0F); + setColor(color, dim); + GL11.glBegin(GL11.GL_LINE_STRIP); + for (int i = 0; i <= segments; i++) { + double t = (double) i / segments; + int bx = (int) ((1 - t) * (1 - t) * x1 + 2 * (1 - t) * t * control.x + t * t * x2); + int by = (int) ((1 - t) * (1 - t) * y1 + 2 * (1 - t) * t * control.y + t * t * y2); + GL11.glVertex2i(bx, by); + } + GL11.glEnd(); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glDisable(GL11.GL_LINE_SMOOTH); + GL11.glDisable(GL11.GL_BLEND); + GL11.glPopAttrib(); } - GL11.glColor4f(rr, gg, bb, 1f); - - GL11.glBegin(GL11.GL_LINE_STRIP); - for (int i = 0; i <= segments; i++) { - double t = (double) i / segments; - int bx = (int) ((1 - t) * (1 - t) * x1 + 2 * (1 - t) * t * control.x + t * t * x2); - int by = (int) ((1 - t) * (1 - t) * y1 + 2 * (1 - t) * t * control.y + t * t * y2); - GL11.glVertex2i(bx, by); - } - GL11.glEnd(); - - GL11.glEnable(GL11.GL_TEXTURE_2D); - GL11.glDisable(GL11.GL_LINE_SMOOTH); - GL11.glDisable(GL11.GL_BLEND); - GL11.glPopAttrib(); } } + // Helper method to draw a straight colored line. + private void drawColoredLine ( int x1, int y1, int x2, int y2, int color, boolean dim){ + GL11.glPushAttrib(GL11.GL_ENABLE_BIT); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glLineWidth(2.0F); + setColor(color, dim); + GL11.glBegin(GL11.GL_LINES); + GL11.glVertex2i(x1, y1); + GL11.glVertex2i(x2, y2); + GL11.glEnd(); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glPopAttrib(); + } + + // Helper to set color with dimming applied. + private void setColor ( int color, boolean dim){ + float r = ((color >> 16) & 0xFF) / 255f; + float g = ((color >> 8) & 0xFF) / 255f; + float b = (color & 0xFF) / 255f; + if (dim) { + r *= 0.4f; + g *= 0.4f; + b *= 0.4f; + } + GL11.glColor4f(r, g, b, 1f); + } + + protected void drawArrowHead(int x1, int y1, int x2, int y2, DiagramConnection conn, boolean dim) { int color = getConnectionColor(conn); if (!useColorScaling) color = 0xFFFFFFFF; @@ -993,20 +1057,43 @@ public abstract class GuiDiagram extends Gui { } protected int getConnectionColor(DiagramConnection conn) { - float percent = conn.percent; - if (percent <= 0.10f) return 0xFF80FF80; - else if (percent <= 0.40f) return 0xFFCCFF66; - else if (percent <= 0.50f) return 0xFFFFA500; - else { - float ratio = (percent - 0.50f) / 0.50f; - ratio = Math.min(1f, Math.max(0f, ratio)); - int r1 = 0xFF, g1 = 0xA5, b1 = 0x00; - int r2 = 0xFF, g2 = 0x00, b2 = 0x00; - int r = r1 + (int) ((r2 - r1) * ratio); - int g = g1 + (int) ((g2 - g1) * ratio); - int b = b1 + (int) ((b2 - b1) * ratio); - return (0xFF << 24) | (r << 16) | (g << 8) | b; + // Clamp to [-1, 1] + float value = Math.max(-1f, Math.min(1f, conn.percent)); + int r, g, b; + if (value >= 0f) { + // For positive values: + // 0.0: YELLOW (255,255,0) + // 0.5: LIGHT GREEN (173,255,47) + // 1.0: GREEN (0,255,0) + if (value <= 0.5f) { + float t = value / 0.5f; // 0 at 0.0, 1 at 0.5 + r = (int)(255 + (173 - 255) * t); + g = 255; + b = (int)(0 + (47 - 0) * t); + } else { + float t = (value - 0.5f) / 0.5f; // 0 at 0.5, 1 at 1.0 + r = (int)(173 + (0 - 173) * t); + g = 255; + b = (int)(47 + (0 - 47) * t); + } + } else { + // For negative values: + // 0.0: YELLOW (255,255,0) + // -0.5: ORANGE (255,165,0) + // -1.0: RED (255,0,0) + if (value >= -0.5f) { + float t = (-value) / 0.5f; // 0 at 0, 1 at -0.5 + r = 255; + g = (int)(255 + (165 - 255) * t); + b = 0; + } else { + float t = (-value - 0.5f) / 0.5f; // 0 at -0.5, 1 at -1.0 + r = 255; + g = (int)(165 + (0 - 165) * t); + b = 0; + } } + return (0xFF << 24) | (r << 16) | (g << 8) | b; } private double pointLineDistance(int px, int py, int x1, int y1, int x2, int y2) { diff --git a/src/main/java/noppes/npcs/controllers/MagicController.java b/src/main/java/noppes/npcs/controllers/MagicController.java index 02dac4690..8e94689ff 100644 --- a/src/main/java/noppes/npcs/controllers/MagicController.java +++ b/src/main/java/noppes/npcs/controllers/MagicController.java @@ -10,6 +10,7 @@ import noppes.npcs.CustomItems; import noppes.npcs.CustomNpcs; import noppes.npcs.LogWriter; import noppes.npcs.api.handler.IMagicHandler; +import noppes.npcs.constants.EnumDiagramLayout; import noppes.npcs.controllers.data.Magic; import noppes.npcs.controllers.data.MagicAssociation; import noppes.npcs.controllers.data.MagicCycle; @@ -99,26 +100,55 @@ public class MagicController implements IMagicHandler { arcane.setItem(new ItemStack(CustomItems.spellArcane)); // Insiders - earth.interactions.put(air.id, 0.60f); - water.interactions.put(earth.id, 0.60f); - fire.interactions.put(water.id, 0.60f); - air.interactions.put(fire.id, 0.60f); + earth.interactions.put(air.id, -0.50f); + air.interactions.put(earth.id, 0.50f); + + water.interactions.put(earth.id, -0.50f); + earth.interactions.put(water.id, 0.50f); + + fire.interactions.put(water.id, -0.50f); + water.interactions.put(fire.id, 0.50f); + + air.interactions.put(fire.id, -0.50f); + fire.interactions.put(air.id, 0.50f); // Outsiders - dark.interactions.put(nature.id, 0.60f); - nature.interactions.put(holy.id, 0.60f); - holy.interactions.put(arcane.id, 0.60f); - arcane.interactions.put(dark.id, 0.60f); + dark.interactions.put(nature.id, -0.50f); + nature.interactions.put(dark.id, 0.50f); + + nature.interactions.put(holy.id, -0.50f); + holy.interactions.put(nature.id, 0.50f); + + holy.interactions.put(arcane.id, -0.50f); + arcane.interactions.put(holy.id, 0.50f); + + arcane.interactions.put(dark.id, -0.50f); + dark.interactions.put(arcane.id, 0.50f); // Cross Interactions - earth.interactions.put(nature.id, 0.30f); - water.interactions.put(holy.id, 0.30f); - fire.interactions.put(arcane.id, 0.30f); - air.interactions.put(dark.id, 0.30f); - dark.interactions.put(fire.id, 0.30f); - nature.interactions.put(air.id, 0.30f); - holy.interactions.put(earth.id, 0.30f); - arcane.interactions.put(water.id, 0.30f); + earth.interactions.put(nature.id, -0.25f); + nature.interactions.put(earth.id, 0.25f); + + water.interactions.put(holy.id, -0.25f); + holy.interactions.put(water.id, 0.25f); + + fire.interactions.put(arcane.id, -0.25f); + arcane.interactions.put(fire.id, 0.25f); + + air.interactions.put(dark.id, -0.25f); + dark.interactions.put(air.id, 0.25f); + + dark.interactions.put(fire.id, -0.25f); + fire.interactions.put(dark.id, 0.25f); + + nature.interactions.put(air.id, -0.25f); + air.interactions.put(nature.id, 0.25f); + + holy.interactions.put(earth.id, -0.25f); + earth.interactions.put(holy.id, 0.25f); + + arcane.interactions.put(water.id, -0.25f); + water.interactions.put(arcane.id, 0.25f); // Add them to the registry magics.put(earth.id, earth); @@ -133,6 +163,7 @@ public class MagicController implements IMagicHandler { MagicCycle defaultCycle = new MagicCycle(); defaultCycle.id = getUnusedCycleId(); defaultCycle.name = "Universal"; + defaultCycle.layout = EnumDiagramLayout.CIRCULAR_MANUAL; defaultCycle.displayName = "Elementa Cycle"; cycles.put(defaultCycle.id, defaultCycle);