Switch repo to English, add i18n with EN/DE language files and first-start language selection
- in-game texts moved to lang/en.lang and lang/de.lang (key = text, placeholders) - game logic emits message keys + args, translated at display time - localStorage access via own miniquad JS plugin (www/dc_plugin.js) - code comments, DESIGN.md, CREDITS.md translated; README.md added Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a101f6ddc4
commit
fbf6f223fc
18 files changed
+1072
-362
No files matched your search
+30
-30
@@ -1,4 +1,4 @@
|
||||
// Prozedural erzeugte Pixelart: Kachel-Atlas und Figuren-Sprites.
|
||||
// Procedurally generated pixel art: tile atlas, unit sprites and the bitmap font.
|
||||
|
||||
use crate::game::EK;
|
||||
use crate::map::Kind;
|
||||
@@ -8,7 +8,7 @@ pub const CELL: f32 = 16.0;
|
||||
const ATLAS_COLS: u32 = 16;
|
||||
const ATLAS_ROWS: u32 = 5;
|
||||
|
||||
// Atlas-Indizes (jeweils 4 Varianten)
|
||||
// atlas indices (4 variants each)
|
||||
pub const T_ROCK: u32 = 0;
|
||||
pub const T_EARTH: u32 = 4;
|
||||
pub const T_GOLD: u32 = 8;
|
||||
@@ -23,7 +23,7 @@ pub const T_LIBRARY: u32 = 40;
|
||||
pub const T_COREFLOOR: u32 = 44;
|
||||
pub const T_PORTALFLOOR: u32 = 48;
|
||||
pub const T_GATEFLOOR: u32 = 52;
|
||||
// Einzelzellen
|
||||
// single cells
|
||||
pub const T_FACE_EARTH: u32 = 56;
|
||||
pub const T_FACE_ROCK: u32 = 57;
|
||||
pub const T_FACE_GOLD: u32 = 58;
|
||||
@@ -44,19 +44,19 @@ pub const I_SUMMON: u32 = 71;
|
||||
pub struct Gfx {
|
||||
pub atlas: Texture2D,
|
||||
pub sprites: Texture2D,
|
||||
pub font: Texture2D, // DINOBYTE, CP437, 16x16 Zeichen à 6x8 px
|
||||
pub font: Texture2D, // DINOBYTE, CP437, 16x16 glyphs of 6x8 px
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------ Bitmap-Schrift (CP437)
|
||||
// ------------------------------------------------------------------ bitmap font (CP437)
|
||||
|
||||
pub const GW: f32 = 6.0; // Glyphbreite
|
||||
pub const GH: f32 = 8.0; // Glyphhöhe
|
||||
pub const GW: f32 = 6.0; // glyph width
|
||||
pub const GH: f32 = 8.0; // glyph height
|
||||
|
||||
const CP437_LOW: &str = " ☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼";
|
||||
const CP437_HIGH: &str = "ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■\u{a0}";
|
||||
|
||||
pub fn cp437(ch: char) -> u8 {
|
||||
// In DINOBYTE sind ö (0x94) und ò (0x95) vertauscht
|
||||
// DINOBYTE has ö (0x94) and ò (0x95) swapped
|
||||
match ch {
|
||||
'ö' => return 0x95,
|
||||
'ò' => return 0x94,
|
||||
@@ -88,7 +88,7 @@ pub fn cp437(ch: char) -> u8 {
|
||||
}
|
||||
}
|
||||
|
||||
// Rahmenzeichen: [oben-links, oben-rechts, unten-links, unten-rechts, waagrecht, senkrecht]
|
||||
// frame glyphs: [top-left, top-right, bottom-left, bottom-right, horizontal, vertical]
|
||||
pub const BOX_SINGLE: [u8; 6] = [0xDA, 0xBF, 0xC0, 0xD9, 0xC4, 0xB3];
|
||||
pub const BOX_DOUBLE: [u8; 6] = [0xC9, 0xBB, 0xC8, 0xBC, 0xCD, 0xBA];
|
||||
|
||||
@@ -126,7 +126,7 @@ impl Canvas {
|
||||
}
|
||||
}
|
||||
|
||||
// Pflasterstein-Muster mit Fugen
|
||||
// flagstone pattern with grout
|
||||
fn stones(x: i32, y: i32, v: u32, base: (i32, i32, i32), grout: (i32, i32, i32), var: i32) -> Color {
|
||||
let row = y / 8;
|
||||
let off = if row % 2 == 1 { 4 } else { 0 };
|
||||
@@ -136,7 +136,7 @@ fn stones(x: i32, y: i32, v: u32, base: (i32, i32, i32), grout: (i32, i32, i32),
|
||||
}
|
||||
let stone = hash((x + off) / 8, row, v + 3) % 5;
|
||||
let d = (rnd(x, y, v) * var as f32) as i32 - var / 2 + stone as i32 * 3 - 6;
|
||||
// Lichtkante oben/links, Schatten unten/rechts
|
||||
// highlight top/left, shadow bottom/right
|
||||
let edge = if y % 8 == 1 || sx % 8 == 1 {
|
||||
10
|
||||
} else if y % 8 == 7 || sx % 8 == 7 {
|
||||
@@ -163,7 +163,7 @@ fn earth_px(x: i32, y: i32, v: u32) -> Color {
|
||||
fn gen_atlas() -> Image {
|
||||
let mut cv = Canvas { img: Image::gen_image_color((ATLAS_COLS * 16) as u16, (ATLAS_ROWS * 16) as u16, Color::new(0.0, 0.0, 0.0, 0.0)) };
|
||||
for v in 0..4u32 {
|
||||
// Fels
|
||||
// rock
|
||||
cv.cell(T_ROCK + v, |x, y| {
|
||||
let blk = rnd(x / 4 + (y / 4) % 2, y / 4, v + 21) * 20.0 - 10.0;
|
||||
let fine = rnd(x, y, v + 5) * 10.0 - 5.0;
|
||||
@@ -174,9 +174,9 @@ fn gen_atlas() -> Image {
|
||||
Some(shade((80, 80, 92), (blk + fine) as i32))
|
||||
}
|
||||
});
|
||||
// Erde
|
||||
// earth
|
||||
cv.cell(T_EARTH + v, |x, y| Some(earth_px(x, y, v)));
|
||||
// Gold
|
||||
// gold
|
||||
cv.cell(T_GOLD + v, |x, y| {
|
||||
let mut best = 99.0f32;
|
||||
for k in 0..6 {
|
||||
@@ -198,7 +198,7 @@ fn gen_atlas() -> Image {
|
||||
cv.cell(T_FLOOR + v, |x, y| Some(stones(x, y, v, (64, 56, 50), (34, 30, 28), 10)));
|
||||
cv.cell(T_CLAIM + v, |x, y| {
|
||||
let col = stones(x, y, v + 10, (78, 44, 58), (36, 20, 28), 10);
|
||||
// kleines Hoheitszeichen in der Mitte jedes zweiten Steins
|
||||
// small emblem in the middle of every other stone
|
||||
if (x % 8 == 4 && y % 8 == 4) && hash(x / 8, y / 8, v) % 2 == 0 {
|
||||
Some(c(150, 60, 80))
|
||||
} else {
|
||||
@@ -268,7 +268,7 @@ fn gen_atlas() -> Image {
|
||||
}
|
||||
});
|
||||
}
|
||||
// Wandfronten (Pseudo-3D)
|
||||
// wall faces
|
||||
cv.cell(T_FACE_EARTH, |x, y| {
|
||||
let streak = (hash(x, 0, 70) % 3) as i32 * 5;
|
||||
Some(shade((62, 42, 28), (rnd(x, y, 71) * 10.0) as i32 - streak - y / 2))
|
||||
@@ -284,7 +284,7 @@ fn gen_atlas() -> Image {
|
||||
Some(shade((62, 42, 28), (rnd(x, y, 75) * 10.0) as i32 - y / 2))
|
||||
}
|
||||
});
|
||||
// Grab-Markierung: diagonale Streifen
|
||||
// dig marker: diagonal stripes
|
||||
cv.cell(T_MARK, |x, y| {
|
||||
if (x + y) % 6 < 2 {
|
||||
Some(Color::from_rgba(255, 220, 60, 150))
|
||||
@@ -294,7 +294,7 @@ fn gen_atlas() -> Image {
|
||||
None
|
||||
}
|
||||
});
|
||||
// Bett
|
||||
// bed
|
||||
cv.cell(D_BED, |x, y| {
|
||||
let dx = (x as f32 - 7.5) / 6.5;
|
||||
let dy = (y as f32 - 8.0) / 5.5;
|
||||
@@ -307,7 +307,7 @@ fn gen_atlas() -> Image {
|
||||
None
|
||||
}
|
||||
});
|
||||
// Pilze
|
||||
// mushrooms
|
||||
cv.cell(D_MUSHROOM, |x, y| {
|
||||
let caps = [(4, 6, 3), (11, 5, 2), (8, 11, 3)];
|
||||
for &(cx, cy, r) in &caps {
|
||||
@@ -322,7 +322,7 @@ fn gen_atlas() -> Image {
|
||||
}
|
||||
None
|
||||
});
|
||||
// Trainingspuppe
|
||||
// training dummy
|
||||
cv.cell(D_DUMMY, |x, y| {
|
||||
if (x == 7 || x == 8) && y >= 4 {
|
||||
Some(c(90, 60, 36))
|
||||
@@ -336,7 +336,7 @@ fn gen_atlas() -> Image {
|
||||
None
|
||||
}
|
||||
});
|
||||
// Goldhaufen
|
||||
// gold pile
|
||||
cv.cell(D_COINS, |x, y| {
|
||||
let dx = (x as f32 - 7.5) / 7.0;
|
||||
let dy = (y as f32 - 11.0) / 5.0;
|
||||
@@ -348,7 +348,7 @@ fn gen_atlas() -> Image {
|
||||
None
|
||||
}
|
||||
});
|
||||
// Bücherregal
|
||||
// bookshelf
|
||||
cv.cell(D_SHELF, |x, y| {
|
||||
if y > 9 || x == 0 || x == 15 {
|
||||
return if y <= 10 { Some(c(60, 36, 22)) } else { None };
|
||||
@@ -365,7 +365,7 @@ fn gen_atlas() -> Image {
|
||||
_ => c(100, 60, 120),
|
||||
})
|
||||
});
|
||||
// Werkzeug-Icons
|
||||
// tool icons
|
||||
cv.cell(I_PICK, |x, y| {
|
||||
let handle = (x + y == 16 || x + y == 17) && x >= 3;
|
||||
let head = (y == 3 || y == 4) && (2..=13).contains(&x) && (x - 8).abs() + (y - 2) * 2 < 9;
|
||||
@@ -599,7 +599,7 @@ pub fn sprite_index(k: EK) -> u32 {
|
||||
SPRITE_KINDS.iter().position(|&s| s == k).unwrap_or(0) as u32
|
||||
}
|
||||
|
||||
// Zeile 0: normale Sprites, Zeile 1: weiße Silhouetten (Treffer-Blitz)
|
||||
// row 0: normal sprites, row 1: white silhouettes (hit flash)
|
||||
fn gen_sprites() -> Image {
|
||||
let n = SPRITE_KINDS.len() as u32;
|
||||
let mut img = Image::gen_image_color((n * SPR_CELL) as u16, (2 * SPR_CELL) as u16, Color::new(0.0, 0.0, 0.0, 0.0));
|
||||
@@ -625,7 +625,7 @@ impl Gfx {
|
||||
atlas.set_filter(FilterMode::Nearest);
|
||||
let sprites = Texture2D::from_image(&gen_sprites());
|
||||
sprites.set_filter(FilterMode::Nearest);
|
||||
// Schrift laden; Hintergrund transparent machen, Glyphen weiß (zum Einfärben)
|
||||
// load the font; transparent background, white glyphs (for tinting)
|
||||
let mut img = Image::from_file_with_format(include_bytes!("../assets/dbyte_1x.png"), Some(ImageFormat::Png)).expect("Schrift");
|
||||
for px in img.get_image_data_mut().iter_mut() {
|
||||
let on = px[3] > 128 && px[0] > 128;
|
||||
@@ -681,7 +681,7 @@ impl Gfx {
|
||||
);
|
||||
}
|
||||
|
||||
// Einzelnes CP437-Zeichen zeichnen (x, y = linke obere Ecke)
|
||||
// draw a single CP437 glyph (x, y = top-left corner)
|
||||
pub fn glyph(&self, code: u8, x: f32, y: f32, scale: f32, color: Color) {
|
||||
let src = Rect::new((code % 16) as f32 * GW, (code / 16) as f32 * GH, GW, GH);
|
||||
draw_texture_ex(
|
||||
@@ -693,7 +693,7 @@ impl Gfx {
|
||||
);
|
||||
}
|
||||
|
||||
// Text zeichnen (x, y = linke obere Ecke); scale sollte ganzzahlig sein
|
||||
// draw text (x, y = top-left corner); scale should be an integer
|
||||
pub fn text(&self, s: &str, x: f32, y: f32, scale: f32, color: Color) {
|
||||
let mut cx = x;
|
||||
for ch in s.chars() {
|
||||
@@ -708,13 +708,13 @@ impl Gfx {
|
||||
s.chars().count() as f32 * GW * scale
|
||||
}
|
||||
|
||||
// Text mit dunklem Schatten
|
||||
// text with a dark shadow
|
||||
pub fn text_sh(&self, s: &str, x: f32, y: f32, scale: f32, color: Color) {
|
||||
self.text(s, x + scale, y + scale, scale, Color::new(0.0, 0.0, 0.0, color.a * 0.85));
|
||||
self.text(s, x, y, scale, color);
|
||||
}
|
||||
|
||||
// Fenster mit CP437-Rahmen; Größe in Zeichen (cols x rows inkl. Rahmen)
|
||||
// window with a CP437 frame; size in characters (cols x rows incl. frame)
|
||||
pub fn window(&self, x: f32, y: f32, cols: i32, rows: i32, scale: f32, double: bool, frame: Color, bg: Color) {
|
||||
let cw = GW * scale;
|
||||
let ch = GH * scale;
|
||||
@@ -740,7 +740,7 @@ impl Gfx {
|
||||
}
|
||||
}
|
||||
|
||||
// Fenster mit Titel in der oberen Rahmenlinie
|
||||
// window with a title in the top frame line
|
||||
pub fn window_titled(&self, x: f32, y: f32, cols: i32, rows: i32, scale: f32, double: bool, frame: Color, bg: Color, title: &str, tcol: Color) {
|
||||
self.window(x, y, cols, rows, scale, double, frame, bg);
|
||||
if !title.is_empty() {
|
||||
|
||||
Reference in new issue
Block a user