Персонажи в игре

https://external-content.duckduckgo.com/iu/?u=https://i.imgur.com/N39Cozd.png

  • Список мы собираем руками на основе анкет, но генерируется он динамически.

  • Возраст считается по дате рождения, зависит от последнего числа текущего игрового периода.

  • Если что-то не нравится или хотите/надо поменять — пишите в связь с администрацией, поправим.

  • Здесь еще и фильтры будут, мамой клянусь.


[html]<style>
:root {
  --dynamic-font-size: 1.2rem;
}
.hehe-charlist.grid-col-3 {
  gap: var(--size-xs);

  .char {
    position: relative;
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-rows: min-content min-content auto;
    gap: var(--size-xs);
    padding: var(--size-xs);
    border: 1px solid var(--color-neutral-300);
    border-radius: var(--size-xs);
    background-color: var(--color-white);

   &:has(.npc) {
      background-color: var(--color-neutral-100);
    }
  }

  .npc sup {
    position: absolute;
    top: var(--size-xs);
    right: var(--size-2xs);
    font-family: var(--font-accent);
    text-transform: uppercase;
    color: var(--color-neutral-500);
  }

  .who {
    grid-column: 1 / -1;
    grid-row: 2;
    margin-block-start: calc(-1 * var(--size-xs));
  }

  .desc {
    grid-column: 1 / -1;
    grid-row: 3;
  }
}
</style>

<div id="hehe-target" class="hehe-charlist grid-col-3"></div>

<script>
const charTemplate = (id, name) => id
  ? `<a href="/profile.php?id=${id}"target=_blank>${name}</a>`
  : `<span class="npc">${name} <sup>npc</sup></span>`;

const GAME_LATEST_DATE = new Date('2025-10-31');
const handleAgeFromDOB = (dob) => {
  if (!dob) {
    return '';
  }

  const [charDay, charMonth, charYear] = dob.split('.');
  const birthDate = new Date(`${charYear}-${charMonth}-${charDay}`);

  let age = GAME_LATEST_DATE.getFullYear() - birthDate.getFullYear();
  const mm = GAME_LATEST_DATE.getMonth() - birthDate.getMonth();
  if (mm < 0 || (mm === 0 && GAME_LATEST_DATE.getDate() < birthDate.getDate())) {
    age--;
  }
  return `, ${age}`;
}

const handleWhoDis = (who, gender) => {
  if (Array.isArray(who)) {
    return who.map(whoDis => { // todo: икон очки
      switch (whoDis) {
        case 'magician':
          return gender === 'f' ? 'волшебница' : 'волшебник';
        case 'hedgewitch':
          return 'хедж-ведьма';
        case 'hybrid':
          return 'полукровка';
        case 'creature':
          return 'существо';
        case 'human':
          return 'человек';
        case 'other':
          return '???';
        default:
          return whoDis;
      }
    }).join(', ');
  }
}

const handleCursed = (cursed, gender) => {
  if (!cursed) {
    return '';
  }

  let marker = '';
  if (gender === 'f') {
    marker = 'а';
  }

  return `; проклят${marker}`;
}

const generateFCList = (characters) => {
  const chars = Object.keys(characters).map(key => ({
    ...characters[key],
    name: key,
  }));

  const container = document.getElementById("hehe-target");
  chars.sort((a, b) => a.ru.localeCompare(b.ru)).forEach(({ ru, id, who, dob, cursed, gender, desc }) => {
    container.innerHTML += `
     <div class="char">
       <strong>${charTemplate(id, ru)}${handleAgeFromDOB(dob)}</strong>
       <small class="who"><em>${handleWhoDis(who, gender)}${handleCursed(cursed, gender)}</em></small>
       ${desc ? `<small class="desc">${desc}</small>` : ''}
     </div>
    `;
  });
}

const vHash = +new Date();

const script = document.createElement('script');
script.charset = 'windows-1251';
script.src = `https://forumstatic.ru/files/001c/ab/7e/10010.js?v=${vHash}`;

script.addEventListener('load', () => {
  generateFCList(window.characters);
});

script.addEventListener('error', () => {
  console.error('Script failed to load.');
});

document.body.appendChild(script);
</script>[/html]