X5ihoSLd~SHYP9X;sTtT+!
zYEg|@nB*1t*!m&168MTGhzKNx)sxnB2@FrRJL_1*8u7wcRlq-wa1u}b$>&oa-0?xn
zQn3kkGTGPf%qu
zSpix|GRGFOF8J&}W>+$=YBoY}F(}Uk?vKU!{?N2tja^;`RK**sWE;7wexnmgJcLIn
zD(FKHAw+oHUGrtNN7p<*X#w5&R~7b8CH6lH=Cl>#9KyW8uxVOR(!N
ztoLTPKJ(-%-s#1e@n<(;LYKAgUCgYPSQC6IQ;EQ%YZV6sDId#4Nxe|X2YuNN3{%+6h;kB`J_7+d$O
zWV0h0C(t4|eB<+m`XPw?+W^AbhUJ6_DCZ~++PjwNs~K>^g;di??Qpc-usgeb>0Dyt
ztZwhjthc6PHILIhip_lLur0!{94;F`_{$m%`?ghH_r@c&i=PNEoXFW`8bj#}NF!kd
z)G%4OKB1i~Slv_?zvH3Ca~ONEAkB-c=FElUX=H2w<8Zq6?!4O@{G8^QkLE!S#V0Hs
z1BTgO)W1(2=pvW2A>$5{Mc1wZ*`JI^HS>e$5o-EVT3>T9zX$u*cOwnri
zJlm_fL9@cP9lhJDqjj3fV*Q1>M;J4NcSC|<>>49x|2fn^!sga$z%cAp50G61;Uo3PveQ=f-qac}uTvd4FWstJ4cSAb$G6LgK==8%JR}4z
zGE4nT_C_bW96)J5N9l)xeZrYk9AFEIYHPg$~tgaZ`;+-b8djj{4R;PwgB-)+^(08`omksWS<@f8
zvO^vfd2jFk&b8;O8fJKGn#I`UFA$a+g3$as)u`dN1>$|A`v=###P19)L&+FsQd?;cM@K12MJUk%ZSRXEi6BYWDZ$c
za>XgBQ_7rL_>jCc?T0BA+-T#!2l*n0y!5N%`$aEC+pL-2J+pqu*IZiWL>b>9|Il9R
zmW$*30yblz(%-cpKq~$C_fzIhdA}xSKtXq8Naov7f%!N|n$gV7JF@C{%3D@D>}6X$
zxzhu9^Os>#37VoLgMgCoLFCp_1TIn*dd3LFvvRo#sxIwl&75$>xxM)9+VZ^sysEI9
zA=RFqu^#i2Nv@E9G|W*;1c((
z3C%+%%%MjR!r!taZtPPzWiI;2gQg}8E#6x{2(gTDDG7VUlynmW8%6^-BuP!>
zN{09Esex73cQ+;d04W2#<@m^Sd5%T~MyOqb+bhWwfi2Eggx5vd%kiu@71Z^GoMmm#
z@q5nHe;mH`nXifbg?M9IOa#nLVzav6!oQngvL4s{N^Dg99*-e^Mflk)q~--Nim{<}
z%7rTI_*N!~5o(3hyic^(hxc%|OB~sUA|^K>V=V~xrfhR&NwV(!g5*se?&)$7Fe*M;
zQD;RYgQ2~~T1INfj$GB;}@Ed*%O;D}VSOIV)QhMvKx-qP-HZfP6O{tyob6~7{
z5FaLfnUuBWwVk~!7T0_~&kFWFY+IO@iZ42YJqUHKuD7?eU{&2|{c~E9SJ;zYmOFul
zsvOHj;v`VATDAWDE{wF(H(cyk-nvcg+o^-S4tT%D{
z311{70j6mW@ks1^>sjJ1sJN(+FRJ$
z(w)gT?pOgT5qOE+XtL025o5z|zx;TIZjA;B`J~J&tUhh5mTf?${{{DYejB2o@m@Y*
z7F}{q;Kt-Q+42|89Hkf;@|Yszdbu=ctM4cyjs}cJmeue-#N1ll?7s&FR1NJ~4uPX!
zbkZx^hL*=V+lvKXcxa#ae9|;3#7~YQYavqM7@JkccozHG8xB@M^KZc(pXzSrY)$RC
z(Yy9&C9W{UGlabk@7IZRmNCouIud+WW>EHq{1+ec*^|{E+SnG+Nn@WY^r3_X6WdRo
zw1*grs=4W@2l?)f_ivbf2y#k5eUMu{G{);D_UM?+Yn|bhsIcqCA)&2J^DrzngVT};
zlUnphTnwjmZ_~BT?BY*j;3w4?6}s_EHdIY>u1}?+)M`fQ@#l)U?^mcVo8oTkJwsE%
zsuzzkeRc^S)1ZfuDjoF@Rt8qgFT(F*2#tlQjvbXroPa|8Ra>6Qp-nK2Tk)Jop|89Gq8$+;M1l+#JFwiy15==K%`q1
zt2Ca;G$~ptniBYnw+;G(h{-q%dD+o#Hu>uftz~4L3-U#@Zzz^4hT(ha({_h
zsWS>Ly}dAr6-`~8+bWBQsjM&`GFmu1+Vi#q)sF8=bJ)r3em#I+y}qdfns@n{5J&lr
zJ~>~Nc}2^7)a}4uKmMMPKS?ASJpYe99`N@7gCn|h9M6l9)$7nJuU{m&%hP`)0(L>U
zaUIRvQHu%c4x;>TE=A8owDJmOLKnt6e0iep-Plb({*!^^JJvE
zJV{=ze*8!Ci`aG$*jiAQ6)6vB!!F03A=V=U^-j5Vp&cMvID|2&q2+qPc2Ab1>ctvp
zPaLfn=s0((M5%jpkX~b|(}1|K9&h5l(^C)Q;7T{l{w}mD-p<`kc`w7Oz)*v5FDN>9
zW=meF<=d-oR>2SAO_ZiC69+7RL}4y8`|6dZ&lsbk^vy`BNQmyATS1AFdX;@0bEIl_
z0!jFQ-iL=dEe+6*bvl)|+w~VVHl_t2MD%+mUomkdiGG!|5UBxPXCwW#O&Md@rGUmZurlRqf
zmeF5yy4;=)hDkyFjf#h>F5mF5ANai1sRuP)M8N<3JZ8VkkN;aa#uTX$eJN`&=Cqe^
zt?T8;mH791l)D3viBl&PiwZ|k(+ROx)){3}*bq6&IWQNAkE}ZgUU=lJI{`Mt0X^j;
zz<-rRlssW7uBmsaDOyC|_i!AA$ya{~m|RpV!*Wt~L0CPa_vOb1yc|->@V)dxC9DM^I&gCX?ltr;Yy4jaD_+tZS`nk3nd(
zz-c+Q>QskT@8}@wjEn!)^_JsH?J76FV@;)!Cv}xF%%-D7T;CMlkIxHB6o`&0x-5Zl
zP)AZ{OnhSk6fb(9$cj=P>Uw}mt*QGg2S9IF{1O;1;tkZx_wx!~zRrrcsf!gYsZ_+RI58#^_{v~Vx{MU?E{F-?XsJ1YNV?Of!t
z7hjH!<EW6An&BH}{X&Iev#6a*ud_l}djsXaxQRqyrCGy(Ei4l|bh_a{-n9?5zTv}EN&lPeNcNqU@OaDcs$l5SMW{rE;&WL`yGS5MTu@*O@WHy
zqECoYsT@tEL+|l)pMa;G#c0!+Neg=LBTVHFhuWL74r!xeH=h*OiiTNbO3pK3Lod>s
zR~BzzbRpO0`HKRrd}43C3*&pq^^MbsoR{-_-vmtr$T0q$U((PVH^dlTF29Zos#_xb
zH7Qfjen>O>jQ5L3$!B^m9TiejIxbjCvfW)cI$c>CQXi+^eca%ZV(FsS%ti#RI>C63
z2qkh9R_Vq!oH_&jx(c!0qnS4r5Wo-QXlZ;oVyI#R3b>mY#{M4&(CLG$W7`Qx#*3^c8OT1b}I0`=3zTC48&N&~)&
z?e@H>UFn^PF&anC@73;W#~__@arch88R>b3}Ot(LT$eRrI9vtfT`Hub}MUm3VLCJI%e``!A?IBhHGAsX!$?s1tDaBWsgnRQm~
z1nmPlK5G4#q=vrMCRBVV=va1F1x>1iwthoCJ*c(3fl07k>DPFcGA3WOL)N|_Z
z#b#-pHs5N;3PiXFG>nSU-O_D*V=Ypn=02Rb02jYk2ItTeb;*ufp}xi~$0V86(I^lf
zF`4nAq^m?`&Fv|fN^!A)*B5WSKfPlCF3ST3U1Hf2`*%%l+ij*tCIp
zf4V>aHOdO@YfRzaW_C;}&D-z>#=Y1}kYAOm^o;itdzrVs;*rWU>UVr`65i|Ftv2<%
zFdPLozDLFMgbRW&9SnVcXTsxRzfZw9YTf+u{u1F@OJVNqUCTkxLzt#%&@nFPq^I-E
zsc<7=9vU$huuT&BVFVteR`1#3^jQzVbUq|6-ew2-_|URyIX;}7HR85_&tQ&UQ{(|~
wNAFT-IH+KuQCNgd*Y*=Ef3J}z;DK30PFeY71<4HgqeLQqLE!(hASX`$7lnHy3jhEB
literal 0
HcmV?d00001
diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx
index dd64748..ecd967a 100644
--- a/src/app/[locale]/page.tsx
+++ b/src/app/[locale]/page.tsx
@@ -206,7 +206,16 @@ export default async function Home({
>
+
+
+
Date: Thu, 21 Aug 2025 16:22:08 +0300
Subject: [PATCH 16/22] make pathname naming more clear
---
src/i18n/routing.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/i18n/routing.ts b/src/i18n/routing.ts
index 07d8c6f..9e833ed 100644
--- a/src/i18n/routing.ts
+++ b/src/i18n/routing.ts
@@ -24,7 +24,7 @@ export const routing = defineRouting({
},
"/kodukord": {
et: "/kodukord",
- en: "/rules",
+ en: "/houserules",
},
"/messiala": {
et: "/messiala",
@@ -36,7 +36,7 @@ export const routing = defineRouting({
},
"/reeglid": {
et: "/reeglid",
- en: "/regulations",
+ en: "/gamerules",
},
"/striim": {
et: "/striim",
From 9906671cc0f11bf1e95f325e9116698bcccf14c4 Mon Sep 17 00:00:00 2001
From: SwagMuffin88
Date: Thu, 21 Aug 2025 17:38:12 +0300
Subject: [PATCH 17/22] fix variables in translation files
---
src/app/[locale]/reeglid/page.tsx | 9 +++++----
translations/en.json | 6 +++---
translations/et.json | 3 ++-
3 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/src/app/[locale]/reeglid/page.tsx b/src/app/[locale]/reeglid/page.tsx
index ba27e02..0886779 100644
--- a/src/app/[locale]/reeglid/page.tsx
+++ b/src/app/[locale]/reeglid/page.tsx
@@ -9,16 +9,17 @@ export default async function RulesMenu({
params: Promise<{ locale: string }>;
}) {
const { locale } = await params;
+
setRequestLocale(locale);
+
const t = await getTranslations({ locale });
+
const headingStyle = `text-4xl md:text-5xl lg:text-6xl ${vipnagorgialla.className} font-bold italic text-[#2A2C3F] dark:text-[#EEE5E5] uppercase`;
const boxStyle = `-skew-x-2 md:-skew-x-5 text-white md:px-12 hover:scale-103 transition-all duration-150 w-full md:w-xl lg:w-[400px]`;
const boxTextStyle = `text-3xl ${vipnagorgialla.className} font-bold uppercase text-[#EEE5E5] pb-2`;
-
- // const SectionDivider = () =>
;
-
+
return (
@@ -49,7 +50,7 @@ export default async function RulesMenu({
{/*
*/}
- {t("tournaments.mini.titleSingular")} {t("rules.title")}
+ {t("rules.miniRules")}
{/**/}
diff --git a/translations/en.json b/translations/en.json
index 73ec36e..566f638 100644
--- a/translations/en.json
+++ b/translations/en.json
@@ -6,7 +6,7 @@
"houserules": "House rules",
"expo": "Expo",
"tickets": "Tickets",
- "rules": "Rules",
+ "rules": "Game rules",
"stream": "Stream",
"tournaments": "Tournaments"
},
@@ -116,7 +116,6 @@
"buyTicket": "BUY TICKETS"
},
"mini": {
- "titleSingular": "Mini-tournament",
"title": "Mini-tournaments",
"timing": "Timing to be announced",
"description1": "TipiLAN hosts various fun and competitive mini-tournaments. Mini-tournaments take place in the following games: SimRacing, Tekken, FIFA, Minecraft Bedwars, Buckshot Roulette, LostGamer and many more.",
@@ -185,7 +184,8 @@
"title": "Rules",
"houseRules": "House Rules",
"cs2Rules": "CS2 Rules",
- "lolRules": "LoL Rules"
+ "lolRules": "LoL Rules",
+ "miniRules": "Mini-tournament Rules"
},
"admin": {
"title": "Admin",
diff --git a/translations/et.json b/translations/et.json
index 40ba4f3..7c1818e 100644
--- a/translations/et.json
+++ b/translations/et.json
@@ -184,7 +184,8 @@
"title": "Reeglid",
"houseRules": "Kodukord",
"cs2Rules": "CS2 Reeglid",
- "lolRules": "LoL Reeglid"
+ "lolRules": "LoL Reeglid",
+ "miniRules": "Miniturniiride Reeglid"
},
"admin": {
"title": "Haldus",
From 1ef88c8b9aca4e4a900aa17f1dbcde4d44e2daea Mon Sep 17 00:00:00 2001
From: SwagMuffin88
Date: Fri, 22 Aug 2025 12:03:13 +0300
Subject: [PATCH 18/22] add more context in expo page buttons
---
package.json | 32 ++++++++++++++++----------------
translations/en.json | 4 ++--
translations/et.json | 4 ++--
3 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/package.json b/package.json
index ee82a4e..7ecec4f 100644
--- a/package.json
+++ b/package.json
@@ -15,20 +15,20 @@
"drizzle:studio": "drizzle-kit studio"
},
"dependencies": {
- "@libsql/client": "^0.15.9",
+ "@libsql/client": "^0.15.12",
"@paralleldrive/cuid2": "^2.2.2",
- "@radix-ui/react-alert-dialog": "^1.1.14",
- "@radix-ui/react-dropdown-menu": "^2.1.15",
- "@radix-ui/react-select": "^2.2.5",
+ "@radix-ui/react-alert-dialog": "^1.1.15",
+ "@radix-ui/react-dropdown-menu": "^2.1.16",
+ "@radix-ui/react-select": "^2.2.6",
"@radix-ui/react-slot": "^1.2.3",
- "@radix-ui/react-tooltip": "^1.2.7",
+ "@radix-ui/react-tooltip": "^1.2.8",
"@tanstack/react-table": "^8.21.3",
"@types/three": "^0.178.1",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
- "drizzle-orm": "^0.44.2",
+ "drizzle-orm": "^0.44.4",
"lucide-react": "^0.522.0",
- "material-symbols": "^0.31.8",
+ "material-symbols": "^0.31.9",
"next": "15.3.0",
"next-intl": "^4.3.4",
"next-themes": "^0.4.6",
@@ -38,23 +38,23 @@
"react-markdown": "^10.1.0",
"tailwind-merge": "^3.3.1",
"three": "^0.178.0",
- "tw-animate-css": "^1.3.4"
+ "tw-animate-css": "^1.3.7"
},
"devDependencies": {
"@eslint/eslintrc": "^3.3.1",
- "@tailwindcss/postcss": "^4.1.10",
- "@types/bun": "^1.2.18",
- "@types/node": "^20.19.1",
- "@types/react": "^19.1.9",
+ "@tailwindcss/postcss": "^4.1.12",
+ "@types/bun": "^1.2.20",
+ "@types/node": "^20.19.11",
+ "@types/react": "^19.1.10",
"@types/react-dom": "^19.1.7",
"autoprefixer": "^10.4.21",
- "dotenv": "^16.3.1",
+ "dotenv": "^16.6.1",
"drizzle-kit": "^0.31.4",
- "eslint": "^9.29.0",
+ "eslint": "^9.33.0",
"eslint-config-next": "15.3.0",
"postcss": "^8.5.6",
- "tailwindcss": "^4.1.10",
+ "tailwindcss": "^4.1.12",
"ts-node": "^10.9.2",
- "typescript": "^5.8.3"
+ "typescript": "^5.9.2"
}
}
diff --git a/translations/en.json b/translations/en.json
index 566f638..98e2422 100644
--- a/translations/en.json
+++ b/translations/en.json
@@ -177,8 +177,8 @@
"simRacing": "Red Bull Sim Racing",
"fighting": "Fighting Games Area"
},
- "hide": "Hide",
- "show": "Show"
+ "hide": "Hide walls",
+ "show": "Show walls"
},
"rules": {
"title": "Rules",
diff --git a/translations/et.json b/translations/et.json
index 7c1818e..e5c7d53 100644
--- a/translations/et.json
+++ b/translations/et.json
@@ -177,8 +177,8 @@
"simRacing": "Red Bull Sim Racing",
"fighting": "Võitlusmängu ala"
},
- "hide": "Peida",
- "show": "Näita"
+ "hide": "Peida seinad",
+ "show": "Näita seinu"
},
"rules": {
"title": "Reeglid",
From 4f9a5812b55b08a6ebaf0f9fbf0a77d9a1147424 Mon Sep 17 00:00:00 2001
From: v4ltages
Date: Mon, 25 Aug 2025 23:38:51 +0300
Subject: [PATCH 19/22] Add entrance hall to expo area (3d model made by
v4ltages)
---
public/spaces/fuajeeTalTech.glb | Bin 0 -> 11336 bytes
src/app/[locale]/messiala/page.tsx | 714 +++++++++++++++++++++++------
src/components/ui/skeleton.tsx | 13 +
translations/en.json | 13 +-
translations/et.json | 13 +-
5 files changed, 619 insertions(+), 134 deletions(-)
create mode 100644 public/spaces/fuajeeTalTech.glb
create mode 100644 src/components/ui/skeleton.tsx
diff --git a/public/spaces/fuajeeTalTech.glb b/public/spaces/fuajeeTalTech.glb
new file mode 100644
index 0000000000000000000000000000000000000000..04d3effb55120ddcf7e491061590b053aaa8dc1d
GIT binary patch
literal 11336
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
IC($?YA?Knn{r~^~
literal 0
HcmV?d00001
diff --git a/src/app/[locale]/messiala/page.tsx b/src/app/[locale]/messiala/page.tsx
index 782ac79..3000e55 100644
--- a/src/app/[locale]/messiala/page.tsx
+++ b/src/app/[locale]/messiala/page.tsx
@@ -2,6 +2,7 @@
import { vipnagorgialla } from "@/components/Vipnagorgialla";
import * as THREE from "three";
+import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
import { useEffect, useRef, useState, useMemo } from "react";
import { EyeClosed, Eye } from "lucide-react";
import SectionDivider from "@/components/SectionDivider";
@@ -10,6 +11,7 @@ import { useTranslations } from "next-intl";
// Define interface for the ref with toggle function
interface MountRefCurrent extends HTMLDivElement {
toggleDividers?: (show: boolean) => void;
+ switchView?: (view: "tudengimaja" | "fuajee") => void;
}
export default function Expo() {
@@ -17,6 +19,10 @@ export default function Expo() {
const [hoveredRoom, setHoveredRoom] = useState(null);
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
const [showDividers, setShowDividers] = useState(true);
+ const [currentView, setCurrentView] = useState<"tudengimaja" | "fuajee">(
+ "tudengimaja",
+ );
+ const currentViewRef = useRef<"tudengimaja" | "fuajee">("tudengimaja");
const t = useTranslations();
// Define room names with translations
@@ -29,6 +35,15 @@ export default function Expo() {
fighting: t("expo.areas.fighting"),
lvlup: "LVLup!",
redbull: "Red Bull",
+ // fuajee rooms
+ ityk: t("expo.areas.ityk"),
+ estoniagamedev: t("expo.areas.estoniagamedev"),
+ info: t("expo.areas.info"),
+ tartuyk: t("expo.areas.tartuyk"),
+ tly: t("expo.areas.tly"),
+ gameup: "GameUP!",
+ ittk: t("expo.areas.ittk"),
+ photobooth: t("expo.areas.photobooth"),
}),
[t],
);
@@ -39,6 +54,10 @@ export default function Expo() {
// Copy ref to variable to avoid stale closure in cleanup
const mountElement = mountRef.current;
let dividersRef: THREE.Mesh[] = [];
+ const fuajeeMeshes: THREE.Mesh[] = [];
+ let tudengimajaObjects: THREE.Object3D[] = [];
+ let fuajeeMesh: THREE.Group | null = null;
+ const fuajeeRooms: THREE.Mesh[] = [];
// Scene setup
const scene = new THREE.Scene();
@@ -62,7 +81,7 @@ export default function Expo() {
// Isometric camera setup with responsive sizing
const aspect = width / height;
const baseFrustumSize = 14;
- const frustumSize = width < 600 ? baseFrustumSize * 0.8 : baseFrustumSize; // Smaller frustum for mobile
+ const frustumSize = baseFrustumSize; // Keep consistent frustum size
const camera = new THREE.OrthographicCamera(
(frustumSize * aspect) / -2,
(frustumSize * aspect) / 2,
@@ -72,9 +91,21 @@ export default function Expo() {
1000,
);
- // Position camera for isometric view
- camera.position.set(10, 10, 14);
- camera.lookAt(-1.4, 0, 0);
+ // Camera positions for different views
+ const cameraPositions = {
+ tudengimaja: {
+ position: new THREE.Vector3(10, 10, 14),
+ lookAt: new THREE.Vector3(-1.4, 0, 0),
+ },
+ fuajee: {
+ position: new THREE.Vector3(30, 20, 15),
+ lookAt: new THREE.Vector3(0, 0, 0),
+ },
+ };
+
+ // Position camera for isometric view (default to tudengimaja)
+ camera.position.copy(cameraPositions.tudengimaja.position);
+ camera.lookAt(cameraPositions.tudengimaja.lookAt);
// Renderer
const renderer = new THREE.WebGLRenderer({ antialias: true });
@@ -118,6 +149,7 @@ export default function Expo() {
name: string;
originalColor: number;
originalScale: THREE.Vector3;
+ view: "tudengimaja" | "fuajee";
}> = [];
const dividers: THREE.Mesh[] = [];
@@ -229,6 +261,7 @@ export default function Expo() {
name: roomDef.name,
originalColor: roomDef.color,
originalScale: room.scale.clone(),
+ view: "tudengimaja",
});
});
@@ -283,14 +316,168 @@ export default function Expo() {
ground2.receiveShadow = true;
scene.add(ground2);
+ // Store tudengimaja objects (rooms, ground, dividers)
+ tudengimajaObjects = [...rooms, ground, ground2, ...dividers];
+
+ // Load fuajee GLTF model
+ const loader = new GLTFLoader();
+ loader.load(
+ "/spaces/fuajeeTalTech.glb",
+ (gltf) => {
+ fuajeeMesh = gltf.scene;
+ fuajeeMesh.position.set(-1.5, 1, 0);
+ fuajeeMesh.scale.set(0.3, 0.3, 0.3);
+ fuajeeMesh.visible = false; // Initially hidden
+
+ // Traverse the model to collect meshes
+ fuajeeMesh.traverse((child) => {
+ if (child instanceof THREE.Mesh) {
+ child.castShadow = true;
+ child.receiveShadow = true;
+ fuajeeMeshes.push(child);
+ }
+ });
+
+ scene.add(fuajeeMesh);
+
+ // Create example rooms for fuajee after the model loads
+ createfuajeeRooms();
+ },
+ (progress) => {
+ console.log(
+ "Loading progress:",
+ (progress.loaded / progress.total) * 100 + "%",
+ );
+ },
+ (error) => {
+ console.error("Error loading GLTF:", error);
+ },
+ );
+
+ // Function to create example rooms for fuajee
+ const createfuajeeRooms = () => {
+ const fuajeeRoomColors = [
+ 0x7b1642, // ITÜK - Cherry Red
+ 0x365591, // Light Blue - Tartu Ülikool
+ 0xa82838, // Red - Tallinna Ülikool
+ 0x183bbf, // Dark Blue - Eesti Gamedev
+ 0xd12e7d, // Purple - Taltech
+ 0x228b22, // Green - GameUP
+ 0xff6347, // Orange - Info
+ 0x20b2aa, // Light Sea Green - Photobooth
+ ];
+
+ const fuajeeRoomDefinitions = [
+ {
+ width: 5,
+ height: 0.5,
+ depth: 3.5,
+ x: -6,
+ z: 2.8,
+ color: fuajeeRoomColors[0],
+ name: roomNames.ityk,
+ },
+ {
+ width: 5,
+ height: 0.5,
+ depth: 2,
+ x: 2.2,
+ z: -1.5,
+ color: fuajeeRoomColors[1],
+ name: roomNames.tartuyk,
+ },
+ {
+ width: 6,
+ height: 0.5,
+ depth: 2,
+ x: -5.8,
+ z: -1.2,
+ color: fuajeeRoomColors[3],
+ name: roomNames.estoniagamedev,
+ },
+ {
+ width: 2,
+ height: 0.5,
+ depth: 2,
+ x: -1.5,
+ z: -1.5,
+ color: fuajeeRoomColors[6],
+ name: roomNames.info,
+ },
+ {
+ width: 2,
+ height: 0.5,
+ depth: 1.5,
+ x: 6,
+ z: -1.7,
+ color: fuajeeRoomColors[2],
+ name: roomNames.tly,
+ },
+ {
+ width: 2,
+ height: 0.5,
+ depth: 1.5,
+ x: 11,
+ z: -1.7,
+ color: fuajeeRoomColors[4],
+ name: roomNames.ittk,
+ },
+ {
+ width: 2,
+ height: 0.5,
+ depth: 1.5,
+ x: 13.5,
+ z: -1.7,
+ color: fuajeeRoomColors[7],
+ name: roomNames.photobooth,
+ },
+ {
+ width: 2,
+ height: 0.5,
+ depth: 1.5,
+ x: 8.5,
+ z: -1.7,
+ color: fuajeeRoomColors[5],
+ name: roomNames.gameup,
+ },
+ ];
+
+ fuajeeRoomDefinitions.forEach((roomDef) => {
+ const geometry = new THREE.BoxGeometry(
+ roomDef.width,
+ roomDef.height,
+ roomDef.depth,
+ );
+ const material = new THREE.MeshLambertMaterial({
+ color: roomDef.color,
+ });
+
+ const room = new THREE.Mesh(geometry, material);
+ room.position.set(roomDef.x, roomDef.height / 2 + 2, roomDef.z);
+ room.castShadow = true;
+ room.receiveShadow = true;
+ room.userData = { name: roomDef.name, originalColor: roomDef.color };
+ room.visible = false; // Initially hidden
+
+ scene.add(room);
+ fuajeeRooms.push(room);
+ roomData.push({
+ mesh: room,
+ name: roomDef.name,
+ originalColor: roomDef.color,
+ originalScale: room.scale.clone(),
+ view: "fuajee",
+ });
+ });
+ };
+
// Resize handler
const handleResize = () => {
const { width: newWidth, height: newHeight } = getResponsiveDimensions();
// Update camera
const newAspect = newWidth / newHeight;
- const newFrustumSize =
- newWidth < 600 ? baseFrustumSize * 0.8 : baseFrustumSize;
+ const newFrustumSize = baseFrustumSize;
camera.left = (newFrustumSize * newAspect) / -2;
camera.right = (newFrustumSize * newAspect) / 2;
@@ -314,11 +501,121 @@ export default function Expo() {
// Update mouse position for tooltip
setMousePosition({ x: event.clientX, y: event.clientY });
- // Update raycaster
- raycaster.setFromCamera(mouse, camera);
- const intersects = raycaster.intersectObjects(rooms);
+ // Handle mouse interactions based on current view
+ if (currentViewRef.current === "tudengimaja") {
+ // Update raycaster
+ raycaster.setFromCamera(mouse, camera);
+ const intersects = raycaster.intersectObjects(rooms);
+
+ // Reset all tudengimaja rooms to original state
+ roomData
+ .filter((r) => r.view === "tudengimaja")
+ .forEach(({ mesh, originalColor, originalScale }) => {
+ (mesh.material as THREE.MeshLambertMaterial).color.setHex(
+ originalColor,
+ );
+ mesh.scale.copy(originalScale);
+ });
+
+ if (intersects.length > 0) {
+ const hoveredMesh = intersects[0].object as THREE.Mesh;
+ const roomInfo = roomData.find((r) => r.mesh === hoveredMesh);
+
+ if (roomInfo) {
+ // Apply hover effects
+ (hoveredMesh.material as THREE.MeshLambertMaterial).color.setHex(
+ 0xffffff,
+ );
+ hoveredMesh.scale.multiplyScalar(1.02);
+ setHoveredRoom(roomInfo.name);
+ }
+ } else {
+ setHoveredRoom(null);
+ }
+ } else if (currentViewRef.current === "fuajee") {
+ // Update raycaster for fuajee rooms
+ raycaster.setFromCamera(mouse, camera);
+ const intersects = raycaster.intersectObjects(fuajeeRooms);
+
+ // Reset all fuajee rooms to original state
+ roomData
+ .filter((r) => r.view === "fuajee")
+ .forEach(({ mesh, originalColor, originalScale }) => {
+ (mesh.material as THREE.MeshLambertMaterial).color.setHex(
+ originalColor,
+ );
+
+ mesh.scale.copy(originalScale);
+ });
+
+ if (intersects.length > 0) {
+ const hoveredMesh = intersects[0].object as THREE.Mesh;
+ const roomInfo = roomData.find((r) => r.mesh === hoveredMesh);
+
+ if (roomInfo) {
+ // Apply hover effects with better visibility
+ (hoveredMesh.material as THREE.MeshLambertMaterial).color.setHex(
+ 0xffffff,
+ );
+
+ hoveredMesh.scale.multiplyScalar(1.1);
+ setHoveredRoom(roomInfo.name);
+ }
+ } else {
+ setHoveredRoom(null);
+ }
+ } else {
+ setHoveredRoom(null);
+ }
+ };
+
+ // Add mouse event listener
+ renderer.domElement.addEventListener("mousemove", onMouseMove);
+
+ // Function to switch camera views
+ const switchView = (view: "tudengimaja" | "fuajee") => {
+ const targetPosition = cameraPositions[view].position;
+ const targetLookAt = cameraPositions[view].lookAt;
+
+ // Animate camera transition
+ const startPosition = camera.position.clone();
+ const startLookAt = new THREE.Vector3();
+ camera.getWorldDirection(startLookAt);
+ startLookAt.multiplyScalar(-1).add(camera.position);
+
+ let progress = 0;
+ const animateCamera = () => {
+ progress += 0.05;
+ if (progress >= 1) {
+ progress = 1;
+ }
+
+ // Smooth interpolation
+ const easeProgress = 1 - Math.cos(progress * Math.PI * 0.5);
+
+ camera.position.lerpVectors(
+ startPosition,
+ targetPosition,
+ easeProgress,
+ );
+ const currentLookAt = new THREE.Vector3().lerpVectors(
+ startLookAt,
+ targetLookAt,
+ easeProgress,
+ );
+ camera.lookAt(currentLookAt);
+
+ if (progress < 1) {
+ requestAnimationFrame(animateCamera);
+ }
+ };
+
+ animateCamera();
- // Reset all rooms to original state
+ // Reset hover state when switching views
+ setHoveredRoom(null);
+
+ // Reset all room states to original
roomData.forEach(({ mesh, originalColor, originalScale }) => {
(mesh.material as THREE.MeshLambertMaterial).color.setHex(
originalColor,
@@ -326,38 +623,48 @@ export default function Expo() {
mesh.scale.copy(originalScale);
});
- if (intersects.length > 0) {
- const hoveredMesh = intersects[0].object as THREE.Mesh;
- const roomInfo = roomData.find((r) => r.mesh === hoveredMesh);
-
- if (roomInfo) {
- // Apply hover effects
- (hoveredMesh.material as THREE.MeshLambertMaterial).color.setHex(
- 0xffffff,
- );
- hoveredMesh.scale.multiplyScalar(1.02);
- setHoveredRoom(roomInfo.name);
+ // Toggle visibility of objects based on view
+ if (view === "fuajee") {
+ tudengimajaObjects.forEach((obj) => (obj.visible = false));
+ if (fuajeeMesh) {
+ fuajeeMesh.visible = true;
}
+ fuajeeRooms.forEach((room) => (room.visible = true));
} else {
- setHoveredRoom(null);
+ tudengimajaObjects.forEach((obj) => (obj.visible = true));
+ if (fuajeeMesh) {
+ fuajeeMesh.visible = false;
+ }
+ fuajeeRooms.forEach((room) => (room.visible = false));
+ // Re-apply divider visibility state
+ if (mountElement.toggleDividers) {
+ mountElement.toggleDividers(showDividers);
+ }
}
};
- // Add mouse event listener
- renderer.domElement.addEventListener("mousemove", onMouseMove);
-
// Animation loop
const animate = () => {
requestAnimationFrame(animate);
// Gentle floating animation for rooms
- rooms.forEach((room, index) => {
- const originalY = 0.25; // height / 2 for the room height of 0.5
- const baseY = originalY + Math.sin(Date.now() * 0.001 + index) * 0.05;
-
- // Maintain current scale while updating Y position
- room.position.y = baseY;
- });
+ if (currentViewRef.current === "tudengimaja") {
+ rooms.forEach((room, index) => {
+ const originalY = 0.25; // height / 2 for the room height of 0.5
+ const baseY = originalY + Math.sin(Date.now() * 0.001 + index) * 0.05;
+
+ // Maintain current scale while updating Y position
+ room.position.y = baseY;
+ });
+ } else if (currentViewRef.current === "fuajee") {
+ fuajeeRooms.forEach((room, index) => {
+ const originalY = 2.25; // height / 2 for the room height of 0.5 + 2 offset
+ const baseY = originalY + Math.sin(Date.now() * 0.001 + index) * 0.05;
+
+ // Maintain current scale while updating Y position
+ room.position.y = baseY;
+ });
+ }
renderer.render(scene, camera);
};
@@ -374,8 +681,9 @@ export default function Expo() {
});
};
- // Expose toggle function to parent scope
+ // Expose functions to parent scope
mountElement.toggleDividers = toggleDividers;
+ mountElement.switchView = switchView;
// Cleanup
return () => {
@@ -395,6 +703,16 @@ export default function Expo() {
}
}, [showDividers]);
+ // Handle view switching
+ const handleViewSwitch = (view: "tudengimaja" | "fuajee") => {
+ setCurrentView(view);
+ currentViewRef.current = view; // Update ref immediately
+ setHoveredRoom(null); // Clear any existing hover state
+ if (mountRef.current?.switchView) {
+ mountRef.current.switchView(view);
+ }
+ };
+
return (
@@ -405,112 +723,248 @@ export default function Expo() {
- {t("schedule.locations.studentHouse")}
+ {currentView === "tudengimaja"
+ ? t("schedule.locations.studentHouse")
+ : t("schedule.locations.entranceHall")}
-
-
-
-
- {t("expo.areas.bar")}
-
-
-
-
-
-
- {t("expo.areas.boardGames")}
-
-
-
-
-
-
-
- {t("expo.areas.simRacing")}
-
-
-
-
-
- Sony
-
+
+ {currentView === "tudengimaja" && (
+
+
+
+
+ {t("expo.areas.bar")}
+
+
+
+
+
+
+ {t("expo.areas.boardGames")}
+
+
+
+
+
+
+
+ {t("expo.areas.simRacing")}
+
+
+
+
+
+
+ {t("expo.areas.fighting")}
+
+
-
-
-
- {t("expo.areas.fighting")}
-
+ )}
+
+ {currentView === "fuajee" && (
+
+
+
+
+ {t("expo.areas.ityk")}
+
+
+
+
+
+ {t("expo.areas.tartuyk")}
+
+
+
+
+
+ {t("expo.areas.estoniagamedev")}
+
+
+
+
+
+ {t("expo.areas.tly")}
+
+
+
+
+
+ {t("expo.areas.ittk")}
+
+
+
+
+
+ {t("expo.areas.info")}
+
+
+
+
+
+ {t("expo.areas.gameup")}
+
+
+
+
+
+ {t("expo.areas.photobooth")}
+
+
-
+ )}
+
-
-
-
setShowDividers(!showDividers)}
- className={`absolute top-2 right-2 px-3 py-2 bg-[#1F5673] text-white hover:bg-[#2A7A9B] ${vipnagorgialla.className} uppercase italic text-sm font-semibold flex items-center transition-colors shadow-lg z-10`}
- >
- {showDividers ? (
-
- ) : (
-
+
+
+
+ {/* Left Arrow - Only show when on fuajee to go back to tudengimaja */}
+ {currentView === "fuajee" && (
+
handleViewSwitch("tudengimaja")}
+ className="group absolute left-4 bottom-4 p-4 md:p-6 transition-all duration-300 hover:scale-110 z-20 touch-manipulation min-h-[48px] min-w-[48px] flex items-center justify-center"
+ title="Switch to Tudengimaja"
+ aria-label="Switch to Tudengimaja view"
+ >
+
+ arrow_right_alt
+
+
)}
- {showDividers ? t("expo.hide") : t("expo.show")}
-
+ {/* Right Arrow - Only show when on tudengimaja to go to fuajee */}
+ {currentView === "tudengimaja" && (
+
handleViewSwitch("fuajee")}
+ className="group absolute right-4 bottom-4 p-4 md:p-6 transition-all duration-300 hover:scale-110 z-20 touch-manipulation min-h-[48px] min-w-[48px] flex items-center justify-center"
+ title="Switch to Fuajee"
+ aria-label="Switch to Fuajee view"
+ >
+
+ arrow_right_alt
+
+
+ )}
+
+ {currentView === "tudengimaja" && (
+
setShowDividers(!showDividers)}
+ className={`absolute top-2 right-2 px-3 py-2 bg-[#1F5673] text-white hover:bg-[#2A7A9B] ${vipnagorgialla.className} uppercase italic text-sm font-semibold flex items-center transition-colors shadow-lg z-10`}
+ >
+ {showDividers ? (
+
+ ) : (
+
+ )}
+
+ {showDividers ? t("expo.hide") : t("expo.show")}
+
+ )}
+
- {/* Tooltip */}
- {hoveredRoom && (
-
- {hoveredRoom}
-
- )}
+ {/* Tooltip - only show for current view */}
+ {hoveredRoom &&
+ ((currentView === "tudengimaja" &&
+ [
+ roomNames.boardGames,
+ roomNames.bar,
+ roomNames.eval,
+ roomNames.simRacing,
+ roomNames.fighting,
+ roomNames.lvlup,
+ roomNames.redbull,
+ ].includes(hoveredRoom)) ||
+ (currentView === "fuajee" &&
+ [
+ roomNames.ityk,
+ roomNames.tartuyk,
+ roomNames.estoniagamedev,
+ roomNames.info,
+ roomNames.tly,
+ roomNames.ittk,
+ roomNames.photobooth,
+ roomNames.gameup,
+ ].includes(hoveredRoom))) && (
+
+ {hoveredRoom}
+
+ )}
diff --git a/src/components/ui/skeleton.tsx b/src/components/ui/skeleton.tsx
new file mode 100644
index 0000000..32ea0ef
--- /dev/null
+++ b/src/components/ui/skeleton.tsx
@@ -0,0 +1,13 @@
+import { cn } from "@/lib/utils"
+
+function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
+ return (
+
+ )
+}
+
+export { Skeleton }
diff --git a/translations/en.json b/translations/en.json
index 98e2422..6b96725 100644
--- a/translations/en.json
+++ b/translations/en.json
@@ -146,7 +146,8 @@
"registrationSetup": "Registration and setup in auditorium",
"auditorium": "Auditorium",
"studentHouse": "Student House (Tudengimaja)",
- "auditoriumAndStudentHouse": "Auditorium and Student House"
+ "auditoriumAndStudentHouse": "Auditorium and Student House",
+ "entranceHall": "Entrance Hall"
}
},
"stream": {
@@ -175,7 +176,15 @@
"bar": "Bar Area",
"boardGames": "Board Games Area",
"simRacing": "Red Bull Sim Racing",
- "fighting": "Fighting Games Area"
+ "fighting": "Fighting Games Area",
+ "photobooth": "Photo booth",
+ "ityk": "TalTech IT Faculty Student Council",
+ "tartuyk": "Tartu University",
+ "estoniagamedev": "Estonia Gamedev",
+ "info": "Information booth",
+ "tly": "Tallinn University",
+ "ittk": "TalTech School of Information Technologies",
+ "gameup": "GameUP!"
},
"hide": "Hide walls",
"show": "Show walls"
diff --git a/translations/et.json b/translations/et.json
index e5c7d53..9269bb7 100644
--- a/translations/et.json
+++ b/translations/et.json
@@ -146,7 +146,8 @@
"registrationSetup": "Registreerimine ja setup aulas",
"auditorium": "Aula",
"studentHouse": "Tudengimaja",
- "auditoriumAndStudentHouse": "Aula ja Tudengimaja"
+ "auditoriumAndStudentHouse": "Aula ja Tudengimaja",
+ "entranceHall": "Fuajee"
}
},
"stream": {
@@ -175,7 +176,15 @@
"bar": "Baariala",
"boardGames": "Lauamängude ala",
"simRacing": "Red Bull Sim Racing",
- "fighting": "Võitlusmängu ala"
+ "fighting": "Võitlusmängu ala",
+ "photobooth": "Fotoboks",
+ "ityk": "IT-teaduskonna üliõpilaskogu",
+ "tartuyk": "Tartu Ülikool",
+ "estoniagamedev": "Eesti Gamedev",
+ "info": "Infoboks",
+ "tly": "Tallinna Ülikool",
+ "ittk": "TalTech IT-Teaduskond",
+ "gameup": "GameUP!"
},
"hide": "Peida seinad",
"show": "Näita seinu"
From 1b906d612bbf70b4d05ed21b628492c30f6c3956 Mon Sep 17 00:00:00 2001
From: Rene Arumetsa
Date: Tue, 26 Aug 2025 13:30:42 +0300
Subject: [PATCH 20/22] Fix alt for bfgl
---
src/app/[locale]/page.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx
index ecd967a..9a4fa55 100644
--- a/src/app/[locale]/page.tsx
+++ b/src/app/[locale]/page.tsx
@@ -206,7 +206,7 @@ export default async function Home({
>
Date: Thu, 28 Aug 2025 21:20:09 +0300
Subject: [PATCH 21/22] Added challangemode link and improved schedule scaling
for mobile
---
src/app/[locale]/ajakava/page.tsx | 14 +++----
src/data/rules/lol.md | 62 +++++++++++++++----------------
2 files changed, 36 insertions(+), 40 deletions(-)
diff --git a/src/app/[locale]/ajakava/page.tsx b/src/app/[locale]/ajakava/page.tsx
index 0615ffc..bc608ab 100644
--- a/src/app/[locale]/ajakava/page.tsx
+++ b/src/app/[locale]/ajakava/page.tsx
@@ -44,29 +44,25 @@ export default function Timetable() {
{schedule.map((item, idx) => (
{item.time}
-
+
{t(item.titleKey)}
{item.description && (
-
+
{item.description}
)}
-
diff --git a/src/data/rules/lol.md b/src/data/rules/lol.md
index 0e22056..22ff030 100644
--- a/src/data/rules/lol.md
+++ b/src/data/rules/lol.md
@@ -30,7 +30,7 @@ Korraldajal on õigus eemaldada võistleja turniirilt nende reeglite rikkumise k
## 3. Mängule eelnev
-1. **3.1** Turniiril osalemine, matchid ja turniiripuu toimib **challengermode.com** keskkonna kaudu:
+1. **3.1** Turniiril osalemine, matchid ja turniiripuu toimib **[challengermode.com](https://www.challengermode.com/s/TipiLAN/tournaments/4b7d832b-7cf3-406a-8425-08ddd311ac8a)** keskkonna kaudu:
1. **3.1.1** Turniirile peab olema registreeritud kogu meeskond, sh varumängija
2. **3.1.2** Turniir toimub **EU West** serveris
2. **3.2** Challengermode keskkonnas on match’id automaatsed. Uue match’i puhul on valmisolekuks aega **10 minutit**, seejärel lobby’sse jõudmiseks veel **10 minutit**.
@@ -42,12 +42,12 @@ Korraldajal on õigus eemaldada võistleja turniirilt nende reeglite rikkumise k
## 4. Mängusisesed protseduurid
1. **4.1** Mäng on ametlikult alanud (game of record (edaspidi GOR)) kui kõik 10 mängijat on kaardil ning mäng on jõudnud esimese reaalse interaktsioonini (vt. allpool).
-Hetkel kui mäng on jõudnud GOR staatuseni, ei või seda uuesti alustada. Mängu skoori hakatakse sellest hetkest ametlikult jälgima.
+Hetkel kui mäng on jõudnud GOR staatuseni, ei või seda uuesti alustada. Mängu skoori hakatakse sellest hetkest ametlikult jälgima.
Peale GOR staatuseni jõudmist on võimalik mängu restartida vaid juhtudel, kui käesoleva mängu lõpuni viimine ei osutu mõjuval põhjusel võimalikuks. GOR’i tingimused on järgnevad:
1. **4.1.1** Kummalgi tiimil õnnestub rünnak või oskuse (ability) kasutamine käsilaste, jungle creep’ide, ehitiste või vastaste vastu
2. **4.1.2** Vastased näevad teineteist (Clairvoyance ei loe)
3. **4.1.3** Sisenetakse vastase territooriumile
- 4. **4.1.4** Mäng on kestnud vähemalt 2 minutit
+ 4. **4.1.4** Mäng on kestnud vähemalt 2 minutit
Pärast GOR-i staatuseni jõudmist ei või mängu uuesti alustada, välja arvatud mõjuval põhjusel (bug, ühenduse probleemid jne).
2. **4.2** Mängu seiskamine:
1. **4.2.1** Mängu pausile panemise ajal ei tohi lahkuda matši alalt, v.a juhul kui see on ametlikult autoriseeritud
@@ -86,53 +86,53 @@ Peale GOR staatuseni jõudmist on võimalik mängu restartida vaid juhtudel, kui
2. **7.10.2 Ban’i kaotus:** tiim ei või karistusele järgneval mängul ban'ida kindel arv tegelasi. Sel juhul kohtunik jälgib, et tiim ei valiks karistusena määratud arvu ban'e ning laseks selle asemel taimeril nulli joosta.
3. **7.10.3 Mängu kaotus:** tiim saab automaatse kaotuse ühel mängul.
4. **7.10.4 Match’i kaotus:** tiim saab automaatse match’i kaotuse.
- 5. **7.10.5 Diskvalifitseerimine:** diskvalifikatsioon kehtib tervele tiimile. Sellel juhul loobub tiim kõigist võitudest. Kui diskvalifikatsioon on saadud eskaleeruvate eksimuste tulemusel, saab tiim selle osa võitudest, mis neil oli selleks hetkeks välja teenitud.
+ 5. **7.10.5 Diskvalifitseerimine:** diskvalifikatsioon kehtib tervele tiimile. Sellel juhul loobub tiim kõigist võitudest. Kui diskvalifikatsioon on saadud eskaleeruvate eksimuste tulemusel, saab tiim selle osa võitudest, mis neil oli selleks hetkeks välja teenitud.
- Mõningatel juhtudel on kohtunikul lubatud diskvalifitseerida ainult üks mängija tiimi asemel. See on sel juhul, kui mängija eksimus ei mõjuta mingil viisil vastasmeeskonda ning on tehtud kaasamata kedagi ka oma tiimist. Üldiselt on see võimalik juhul kui mängija eksimus kuulub kategooriasse *Mittesobilik käitumine – Raske eksimus*. Sel juhul võib ülejäänud tiim turniiril jätkata varumängija olemasolul. Vastasel korral peab ka kogu tiim turniirilt välja langema.
-11. **7.11** Karistuste eskaleerimine toimub järgmises järjekorras:
+11. **7.11** Karistuste eskaleerimine toimub järgmises järjekorras:
Hoiatus → hoiatus → ban’i valimise õiguse kaotus → mängu kaotus → match’i kaotus → diskvalifikatsioon.
12. **7.12** Turniiri eksimused jagunevad järgmiselt:
1. **7.12.1 Välise abi kasutamine:** eksimus läheb kirja, kui tiim suhtleb mängu ajal ükskõik kellega peale omaenda tiimi ning selle tagajärjel, kohtuniku otsustusel, saab mängus eelise. Eksimuse puhul eeldatakse, et tegu ei olnud tahtliku kavatsusega sohki teha. Tahtlikult ebaõiglase eelise otsimine läheb punkti *Mittesobilik käitumine – Sohk* alla. Karistuseks on hoiatus.
- 2. **7.12.2 Juhiste eiramine:** igal mängijal on kohustus järgida Korraldaja ja kohtunike juhiseid. Nende eiramine võib endaga kaasa tuua viivitusi ning vaidlusi. Karistuseks on esimese valiku tegemise kaotus.
+ 2. **7.12.2 Juhiste eiramine:** igal mängijal on kohustus järgida Korraldaja ja kohtunike juhiseid. Nende eiramine võib endaga kaasa tuua viivitusi ning vaidlusi. Karistuseks on esimese valiku tegemise kaotus.
- Spetsiifiliselt ühele tiimile või mängijale tehtud korralduse eiramine on eraldi eksimus ning kuulub *Mittesobilik käitumine – Keskmine eksimus* alla.
-13. **7.13** Mittesobilik käitumine.
- Mittesobilik käitumine on turniiri käiku häiriv ning võib negatiivselt mõjutada turvalisust, võistlushimu, mängurõõmu või turniiri ausameelsust ning terviklikkust. See ei ole sama, mis konkurentsihimuline käitumine.
+13. **7.13** Mittesobilik käitumine.
+ Mittesobilik käitumine on turniiri käiku häiriv ning võib negatiivselt mõjutada turvalisust, võistlushimu, mängurõõmu või turniiri ausameelsust ning terviklikkust. See ei ole sama, mis konkurentsihimuline käitumine.
Mittesobiliku käitumise eksimused jagunevad:
1. **7.13.1 Kerge eksimus:** käitumine, mis on ebameeldiv, ebaeetiline või häiriv, näiteks liigne ropendamine; nõudmine, et vastane saaks karistuse peale kohtuniku otsust; lõugamine; prügi maha loopimine jne. Karistuseks on hoiatus.
2. **7.13.2 Keskmine eksimus:** kolm tüüpi juhtumeid:
- - Eirab kohtuniku või Korraldaja juhiseid, mis on mõeldud spetsiaalselt ühele tiimile või ühele mängijale
- - Kasutab avalikult vihakõnet kellegi suunas
- - On agressiivne või vägivaldne, kuid see ei ole suunatud teise inimese vastu
+ - Eirab kohtuniku või Korraldaja juhiseid, mis on mõeldud spetsiaalselt ühele tiimile või ühele mängijale
+ - Kasutab avalikult vihakõnet kellegi suunas
+ - On agressiivne või vägivaldne, kuid see ei ole suunatud teise inimese vastu
Karistuseks on mängu kaotus.
3. **7.13.3 Raske eksimus:** käitumine, mis on selgelt vastuolus turniiri reeglite ja heade tavadega, näiteks tahtlikult turniiri vahendite lõhkumine või ruumi määrimine/lõhkumine. Karistuseks on diskvalifikatsioon, turniiri toimumiskohast eemaldamine või ekstreemsematel juhtudel politsei teavitamine.
4. **7.13.4 Kokkumäng:** kahe tiimi kokkulepe ebaausalt teiste tiimide vastu mängida ja püüda mõjutada turniiri tulemusi. Karistuseks on mõlema tiimi diskvalifitseerimine.
5. **7.13.5 Altkäemaks ja panustamine:** keelatud on meelehea (mitte ainult rahaline) nimel loobuda turniirist või püüda muuta match’ide tulemusi. Samuti on keelatud pakkuda kohtunikule stiimulit mängu tulemuse mõjutamiseks või teha panuseid mängude tulemustele. Karistuseks on diskvalifitseerimine.
6. **7.13.6 Agressiivne käitumine:** kõik inimeste vastu suunatud agressiooni ilmingud, kaasa arvatud ähvardamine ja reaalne vägivald. Karistuseks on diskvalifitseerimine ja toimumiskohast eemaldamine, ekstreemsematel juhtudel politsei teavitamine.
7. **7.13.7 Vargus:** kuigi igal osalejal on kohustus oma varal silma peal hoida, eeldatakse heade tavade järgimist. Karistuseks on diskvalifitseerimine ja toimumiskohast eemaldamine, vajadusel politsei teavitamine.
- 8. **7.13.8 Alkohol ja joove:** alkoholi tarbimine ürituse raames on keelatud. Liigse joobe korral on Korraldajal õigus osaleja toimumiskohast eemaldada.
+ 8. **7.13.8 Alkohol ja joove:** alkoholi tarbimine ürituse raames on keelatud. Liigse joobe korral on Korraldajal õigus osaleja toimumiskohast eemaldada.
- Kui joobes osaleja on alaealine, informeeritakse sellest tema vanemaid ning politseid.
- 9. **7.13.9 Sohk:** teadlik tegevus mängus eelise saavutamiseks, isegi kui see ei ole edukas.
+ 9. **7.13.9 Sohk:** teadlik tegevus mängus eelise saavutamiseks, isegi kui see ei ole edukas.
Sohki tegemise näited:
- - Püüab näha enda mängu spectator mode’s või saab infot kelleltki, kes saab mängu spectator mode’s vaadata
- - Mängu modifitseerimine või lisatarkvara kasutamine, mis ei ole tavapärane (nt löögiraadiuse või torni laskeraadiuse nähtavaks tegemine, spawn-taimerid jms; VOIP-programmide kasutamine ei kuulu siia alla)
- - Teise mängijana või vale nime all esinemine, konto jagamine
- - Varustuse tahtlik rikkumine või moonutamine, et tekitada viivitusi või mõjutada mängu kulgu
- - Mängusiseste vigade tahtlik ärakasutamine (glitchid) eelise saamiseks
+ - Püüab näha enda mängu spectator mode’s või saab infot kelleltki, kes saab mängu spectator mode’s vaadata
+ - Mängu modifitseerimine või lisatarkvara kasutamine, mis ei ole tavapärane (nt löögiraadiuse või torni laskeraadiuse nähtavaks tegemine, spawn-taimerid jms; VOIP-programmide kasutamine ei kuulu siia alla)
+ - Teise mängijana või vale nime all esinemine, konto jagamine
+ - Varustuse tahtlik rikkumine või moonutamine, et tekitada viivitusi või mõjutada mängu kulgu
+ - Mängusiseste vigade tahtlik ärakasutamine (glitchid) eelise saamiseks
Karistuseks on diskvalifikatsioon.
## 8. Double Elimination
-1. **8.1** Double Elimination on turniiri formaat, kus esimeses voorus mängivad kõik 16 tiimi.
-2. **8.2** Pärast avavooru jagunevad tiimid kaheks:
- 1. **8.2.1** Võitjate elimineerimispuu (*upper bracket*) – sinna liiguvad esimeses voorus võitnud tiimid.
- 2. **8.2.2** Kaotajate elimineerimispuu (*lower bracket*) – sinna liiguvad esimeses voorus kaotanud tiimid.
-3. **8.3** Väljalangemine:
- 1. **8.3.1** Iga järgmises voorus kaotav tiim langeb turniirilt välja.
-4. **8.4** Mänguformaat:
- 1. **8.4.1** Esimesed kolm vooru: *Best of 1* – võitja liigub edasi järgmisesse vooru.
- 2. **8.4.2** Upper- ja lower-finaalid: *Best of 3* – võidab see, kes võidab esimesena kaks mängu.
- 3. **8.4.3** Finaal: *Best of 5* – võidab see, kes võidab esimesena kolm mängu.
-5. **8.5** III koha määramine:
- 1. **8.5.1** Finaali kaotaja mängib kaotajate elimineerimispuu võitjaga.
- 2. **8.5.2** Selle kohtumise võitja saab turniiri **III koha**.
+1. **8.1** Double Elimination on turniiri formaat, kus esimeses voorus mängivad kõik 16 tiimi.
+2. **8.2** Pärast avavooru jagunevad tiimid kaheks:
+ 1. **8.2.1** Võitjate elimineerimispuu (*upper bracket*) – sinna liiguvad esimeses voorus võitnud tiimid.
+ 2. **8.2.2** Kaotajate elimineerimispuu (*lower bracket*) – sinna liiguvad esimeses voorus kaotanud tiimid.
+3. **8.3** Väljalangemine:
+ 1. **8.3.1** Iga järgmises voorus kaotav tiim langeb turniirilt välja.
+4. **8.4** Mänguformaat:
+ 1. **8.4.1** Esimesed kolm vooru: *Best of 1* – võitja liigub edasi järgmisesse vooru.
+ 2. **8.4.2** Upper- ja lower-finaalid: *Best of 3* – võidab see, kes võidab esimesena kaks mängu.
+ 3. **8.4.3** Finaal: *Best of 5* – võidab see, kes võidab esimesena kolm mängu.
+5. **8.5** III koha määramine:
+ 1. **8.5.1** Finaali kaotaja mängib kaotajate elimineerimispuu võitjaga.
+ 2. **8.5.2** Selle kohtumise võitja saab turniiri **III koha**.
From 51c34d53393812d0586732f0e6eae30a17777e1a Mon Sep 17 00:00:00 2001
From: v4ltages
Date: Fri, 29 Aug 2025 02:46:15 +0300
Subject: [PATCH 22/22] Minor polish around certain pages
---
src/app/[locale]/page.tsx | 2 +-
src/app/[locale]/piletid/page.tsx | 2 +-
src/app/[locale]/striim/page.tsx | 11 +++++++++-
src/components/Footer.tsx | 30 ++++++++++++++++++++------
src/components/SidebarLayoutClient.tsx | 2 +-
translations/en.json | 4 +++-
translations/et.json | 4 +++-
7 files changed, 42 insertions(+), 13 deletions(-)
diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx
index 9a4fa55..809bb26 100644
--- a/src/app/[locale]/page.tsx
+++ b/src/app/[locale]/page.tsx
@@ -142,7 +142,7 @@ export default async function Home({
{t("home.sections.poweredBy")}
-
+
{t("tickets.title")}
diff --git a/src/app/[locale]/striim/page.tsx b/src/app/[locale]/striim/page.tsx
index c2e68ab..04a8fe2 100644
--- a/src/app/[locale]/striim/page.tsx
+++ b/src/app/[locale]/striim/page.tsx
@@ -140,7 +140,7 @@ export default async function Home({
{t("home.sections.poweredBy")}
-
diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx
index b919d72..06cf81d 100644
--- a/src/components/Footer.tsx
+++ b/src/components/Footer.tsx
@@ -38,7 +38,7 @@ const Footer = () => {
{
{
@@ -98,18 +98,34 @@ const Footer = () => {
{t("footer.organization")}
-
+
{t("footer.registrationCode")}:{" "}
80391807
-
- ICO-210, Raja tn 4c, Tallinn, Harjumaa, 12616
-
+
ICO-210, Raja tn 4c, Tallinn, Harjumaa, 12616
+
);
diff --git a/src/components/SidebarLayoutClient.tsx b/src/components/SidebarLayoutClient.tsx
index 1fec6ce..470a2d0 100644
--- a/src/components/SidebarLayoutClient.tsx
+++ b/src/components/SidebarLayoutClient.tsx
@@ -72,7 +72,7 @@ export default function SidebarLayoutClient({
{item.label}
diff --git a/translations/en.json b/translations/en.json
index 6b96725..93fd1ae 100644
--- a/translations/en.json
+++ b/translations/en.json
@@ -163,7 +163,9 @@
"terms": "Terms",
"studentUnion": "IT Faculty Student Council",
"organization": "MTÜ For Tsükkel",
- "registrationCode": "Registration code"
+ "registrationCode": "Registration code",
+ "madeBy": "The TipiLAN website is made with love by",
+ "withHelpFrom": "with the help of"
},
"notFound": {
"title": "404",
diff --git a/translations/et.json b/translations/et.json
index 9269bb7..826307f 100644
--- a/translations/et.json
+++ b/translations/et.json
@@ -163,7 +163,9 @@
"terms": "Tingimused",
"studentUnion": "IT-teaduskonna üliõpilaskogu",
"organization": "MTÜ For Tsükkel",
- "registrationCode": "Registrikood"
+ "registrationCode": "Registrikood",
+ "madeBy": "TipiLANi veebileht on tehtud armastusega",
+ "withHelpFrom": "poolt, kellele oli abiks"
},
"notFound": {
"title": "404",