From 0c56b7db291fcb178ad794542ef84d5303b8de98 Mon Sep 17 00:00:00 2001 From: necropotame Date: Sat, 12 Nov 2016 20:07:12 +0100 Subject: [PATCH] a lot of small things --- data/languages/de.json | 2 +- data/languages/hr.json | 508 ++++++++++++++ data/languages/hu.json | 8 + data/languages/index.json | 29 +- data/languages/ja.json | 494 ++++++++++++++ data/languages/uk.json | 28 +- scripts/translation.py | 2 + src/engine/server.h | 6 + src/engine/server/mapconverter.cpp | 623 ++++++++++++------ src/engine/server/mapconverter.h | 23 +- src/engine/server/roundstatistics.cpp | 3 + src/engine/server/roundstatistics.h | 1 + src/engine/shared/config_variables.h | 6 +- src/game/server/entities/character.cpp | 231 +++++-- src/game/server/entities/character.h | 7 +- src/game/server/entities/engineer-wall.cpp | 4 +- src/game/server/entities/flyingpoint.cpp | 5 +- src/game/server/entities/flyingpoint.h | 3 +- src/game/server/entities/growingexplosion.cpp | 329 +++++++++ src/game/server/entities/growingexplosion.h | 257 +------- src/game/server/entities/merc-bomb.cpp | 51 +- src/game/server/entities/merc-bomb.h | 13 +- src/game/server/entities/merc-grenade.cpp | 2 +- src/game/server/entities/projectile.cpp | 2 +- src/game/server/entities/scientist-mine.cpp | 2 +- src/game/server/gamecontext.cpp | 284 +++++--- src/game/server/gamecontext.h | 18 + src/game/server/gamemodes/mod.cpp | 36 +- src/game/server/player.cpp | 28 +- src/game/server/player.h | 14 +- 30 files changed, 2335 insertions(+), 684 deletions(-) create mode 100644 data/languages/hr.json create mode 100644 data/languages/ja.json create mode 100644 src/game/server/entities/growingexplosion.cpp diff --git a/data/languages/de.json b/data/languages/de.json index 7f7ed50de..e12d89917 100644 --- a/data/languages/de.json +++ b/data/languages/de.json @@ -5,7 +5,7 @@ }, { "key": "Infected won the round in {sec:RoundDuration}", - "value": "Die Erkrankten haben die Runde in {sec:RoundDuration}" + "value": "Die Erkrankten haben die Runde in {sec:RoundDuration} gewonnen" }, { "key": "{int:NumHumans} humans won the round", diff --git a/data/languages/hr.json b/data/languages/hr.json new file mode 100644 index 000000000..6b2c90705 --- /dev/null +++ b/data/languages/hr.json @@ -0,0 +1,508 @@ +{"translation":[ + { + "key": "{str:VictimName} has been infected", + "value": "{str:VictimName} je zara\u017een" + }, + { + "key": "Infected won the round in {sec:RoundDuration}", + "value": "Zara\u017eeni su pobijedili ovu rundu u {sec:RoundDuration}" + }, + { + "key": "{int:NumHumans} humans won the round", + "one": "Jedan \u010dovjek je pobijedio ovu rundu", + "few": "{int:NumHumans} ljudi je pobijedilo ovu rundu", + "other": "{int:NumHumans} ljudi je pobijedilo ovu rundu", + }, + { + "key": "You have survived, +5 points", + "value": "Pre\u017eivio si, +5 bodova" + }, + { + "key": "You have infected {str:VictimName}, +3 points", + "value": "Zarazio si {str:VictimName}, +3 boda" + }, + { + "key": "You have killed a witch, +5 points", + "value": "Ubio si vje\u0161ticu, +5 bodova" + }, + { + "key": "The undead is coming!", + "value": "Undead dolazi!" + }, + { + "key": "The witch is coming!", + "value": "Vje\u0161tica dolazi!" + }, + { + "key": "Random choice", + "value": "Nasumi\u010dan izbor" + }, + { + "key": "Engineer", + "value": "In\u017eenjer" + }, + { + "key": "Soldier", + "value": "Vojnik" + }, + { + "key": "Scientist", + "value": "Znanstvenik" + }, + { + "key": "Medic", + "value": "Lije\u010dnik" + }, + { + "key": "Hero", + "value": "Heroj" + }, + { + "key": "Ninja", + "value": "Nind\u017ea" + }, + { + "key": "Mercenary", + "value": "Pla\u0107enik" + }, + { + "key": "Sniper", + "value": "Snajper" + }, + { + "key": "Choose your class", + "value": "Izaberi svoju klasu" + }, + { + "key": "{int:NumBombs} bombs left", + "one": "Jedna bomba preostala", + "few": "{int:NumBombs} bombi preostalo", + "other": "{int:NumBombs} bombi preostalo", + }, + { + "key": "{int:NumMines} mines are actives", + "one": "Jedna mina je aktivna", + "few": "{int:NumMines} mine su aktivne", + "other": "{int:NumMines} mine su aktivne", + }, + { + "key": "Next flag in {sec:RemainingTime}", + "value": "Idu\u0107a zastava u {sec:RemainingTime}" + }, + { + "key": "Laser wall: {sec:RemainingTime}", + "value": "Laserski zid: {sec:RemainingTime}" + }, + { + "key": "Position lock: {sec:RemainingTime}", + "value": "Pozicija zaklju\u010dana: {sec:RemainingTime}" + }, + { + "key": "Web mode enabled", + "value": "Mre\u017ea uklju\u010dena" + }, + { + "key": "The witch is dead", + "value": "Vje\u0161tica je mrtva" + }, + { + "key": "The undead is finally dead", + "value": "Undead je napokon mrtav" + }, + { + "key": "Type \"/help {str:ClassName}\" for more information about your class", + "value": "Napi\u0161i \"/help {str:ClassName}\" za vi\u0161e informacija o svojoj klasi" + }, + { + "key": "The Hero found the flag!", + "value": "Heroj je na\u0161ao zastavu!" + }, + { + "key": "Hook protection enabled", + "value": "Hook-za\u0161tita uklju\u010dena" + }, + { + "key": "Hook protection disabled", + "value": "Hook-za\u0161tita isklju\u010dena" + }, + { + "key": "{str:PlayerName} has been banned ({str:Reason})", + "value": "{str:PlayerName} je bannan sa servera ({str:Reason})" + }, + { + "key": "{str:PlayerName} has been kicked ({str:Reason})", + "value": "{str:PlayerName} je izba\u010den sa servera ({str:Reason})" + }, + { + "key": "{str:PlayerName} has left the game ({str:Reason})", + "value": "{str:PlayerName} je iza\u0161ao iz igre ({str:Reason})" + }, + { + "key": "{str:PlayerName} has left the game", + "value": "{str:PlayerName} je iza\u0161ao iz igre" + }, + { + "key": "{str:PlayerName} joined the spectators", + "value": "{str:PlayerName} gleda igru" + }, + { + "key": "{str:PlayerName} joined the game", + "value": "{str:PlayerName} se uklju\u010dio u igru" + }, + { + "key": "Smoker", + "value": "Pu\u0161a\u010d" + }, + { + "key": "Hunter", + "value": "Lovac" + }, + { + "key": "Boomer", + "value": "Bumer" + }, + { + "key": "Ghost", + "value": "Duh" + }, + { + "key": "Spider", + "value": "Pauk" + }, + { + "key": "Witch", + "value": "Vje\u0161tica" + }, + { + "key": "Undead", + "value": "Undead" + }, + { + "key": "Unknown class", + "value": "Nepoznata klasa" + }, + { + "key": "You are a human: {str:ClassName}", + "value": "Ti si \u010dovjek: {str:ClassName}" + }, + { + "key": "You are an infected: {str:ClassName}", + "value": "Ti si zara\u017een: {str:ClassName}" + }, + { + "key": "{str:PlayerName} entered and joined the game", + "value": "{str:PlayerName} je u\u0161ao i uklju\u010dio se u igru" + }, + { + "key": "You can't join the spectators right now", + "value": "Ne mo\u017ee\u0161 gledati igru sada" + }, + { + "key": "{str:PlayerName} changed their name to {str:NewName}", + "value": "{str:PlayerName} je promijenio svoje ime u {str:NewName}" + }, + { + "key": "Switch language to english ?", + "value": "Prebaciti jezik na engleski?" + }, + { + "key": "You can change the language of this mod using the command /language.", + "value": "Mo\u017ee\u0161 promijeniti jezik na ovom modu koriste\u0107i naredbu /language" + }, + { + "key": "If your language is not available, you can help with translation (/help translate).", + "value": "Ako tvoj jezik nije dostupan, mo\u017ee\u0161 nam pomo\u0107i sa prijevodom (/help translate)." + }, + { + "key": "InfectionClass, by necropotame (version {str:VersionCode})", + "value": "InfectionClass, napravio necropotame (verzija {str:VersionCode})" + }, + { + "key": "Based on Infection mod by Gravity", + "value": "Bazirano na Infection modu, napravio Gravity" + }, + { + "key": "Thanks to {str:ListOfContributors}", + "value": "Zahvaljuju\u0107i {str:ListOfContributors}" + }, + { + "key": "Rules of the game", + "value": "Pravila igre" + }, + { + "key": "InfectionClass is a team game between humans and infected.", + "value": "InfectionClass je timska igra izme\u0111u ljudi i zara\u017eenih." + }, + { + "key": "All players start as human.", + "value": "Svi igra\u010di zapo\u010dinju kao ljudi." + }, + { + "key": "10 seconds later, two players become infected.", + "value": "10 sekundi poslije, dva igra\u010da postanu zara\u017eena." + }, + { + "key": "The goal for humans is to survive until the army clean the map.", + "value": "Cilj za ljude je pre\u017eivjeti sve dok vojska ne o\u010disti mapu." + }, + { + "key": "The goal for infected is to infect all humans.", + "value": "Cilj za zara\u017eene je zaraziti sve ljude." + }, + { + "key": "How to translate the mod", + "value": "Kako prevesti mod" + }, + { + "key": "Create an account on Transifex and join a translation team:", + "value": "Napravi ra\u010dun na Transifex-u i pridru\u017ei se timu prevoditelja:" + }, + { + "key": "For any question about the translation process, please contact us on IRC ({str:IRCAddress})", + "value": "Za pitanja o procesu prevo\u0111enja, molimo da nas kontaktirate na IRC ({str:IRCAddress})" + }, + { + "key": "The Engineer can build walls with his hammer to block infected.", + "value": "In\u017eenjer mo\u017ee raditi zidove sa \u010deki\u0107em." + }, + { + "key": "When an infected touch the wall, he dies.", + "value": "Kada zara\u017eeni dotakne zid, on umre." + }, + { + "key": "The lifespan of a wall is {sec:LifeSpan}, and walls are limited to one per player at the same time.", + "value": "Zid radi {sec:LifeSpan}, a jedan igra\u010d mo\u017ee napraviti samo jedan zid u isto vrijeme." + }, + { + "key": "The Soldier can pose floating bombs with his hammer.", + "value": "Vojnik mo\u017ee postavljati lebde\u0107e bombe sa \u010deki\u0107em." + }, + { + "key": "Each bomb can explode {int:NumBombs} times.", + "one": "Svaka bomba mo\u017ee eksplodirati jedan put.", + "few": "Svaka bomba mo\u017ee eksplodirati {int:NumBombs} puta.", + "other": "Svaka bomba mo\u017ee eksplodirati {int:NumBombs} puta.", + }, + { + "key": "Use the hammer to place the bomb and explode it multiple times.", + "value": "Uzmi \u010deki\u0107 za postavljanje bombi i aktiviranje vi\u0161e puta." + }, + { + "key": "Bombs are limited to one per player at the same time.", + "value": "Bombe su ograni\u010dene na jednog igra\u010da u isto vrijeme." + }, + { + "key": "The Scientist can pose floating mines with his hammer.", + "value": "Znanstvenik mo\u017ee postaviti ledbe\u0107e mine sa \u010deki\u0107em." + }, + { + "key": "Mines are limited to {int:NumMines} per player at the same time.", + "one": "Mine su ograni\u010dene na jednog igra\u010da u isto vrijeme.", + "few": "Mine su ograni\u010dene na {int:NumMines} po igra\u010du u isto vrijeme.", + "other": "Mine su ograni\u010dene na {int:NumMines} po igra\u010du u isto vrijeme.", + }, + { + "key": "He has also grenades that teleport him.", + "value": "Ima i granate koje ga teleportiraju." + }, + { + "key": "The Medic can protect humans with his hammer by giving them armor.", + "value": "Lije\u010dnik mo\u017ee dati ljudima armor." + }, + { + "key": "He has also a powerful shotgun that can pullback infected.", + "value": "Ima i sna\u017ean shotgun koji odbacuje zara\u017eene." + }, + { + "key": "The Hero has a shotgun, a laser rifle and grenades.", + "value": "Heroj ima shotgun, lasersku pu\u0161ku i granate." + }, + { + "key": "The Hero must find a flag hidden in the map.", + "value": "Heroj mora na\u0107i zastavu skrivenu u mapi." + }, + { + "key": "Once taken, the flag gives 1 health point, 4 armor points, and full ammo to all humans, furthermore full health and armor to the hero.", + "value": "Kad ju uzme, zastava daje 1 health, 4 armor, i puni municiju svim ljudima, te cijeli health i armor za heroja." + }, + { + "key": "The hero cannot be healed by a medic, but he can withstand a thrust by an infected, an his health suffice.", + "value": "Heroja ne mo\u017ee izlije\u010diti lije\u010dnik, ali on mo\u017ee izdr\u017eati napad zara\u017eenog jer ima dovoljno healtha." + }, + { + "key": "The Ninja can throw flash grenades that can freeze infected during three seconds.", + "value": "Nind\u017ea mo\u017ee bacati flash granate koje zalede zara\u017eene na tri sekunde." + }, + { + "key": "His hammer is replaced by a katana, allowing him to jump {int:NinjaJump} times before touching the ground.", + "one": "Njegov \u010deki\u0107 je zamijenjen katanom, mo\u017ee sko\u010diti jedan put prije nego padne.", + "few": "Njegov \u010deki\u0107 je zamijenjen katanom, mo\u017ee sko\u010diti {int:NinjaJump} puta prije nego padne.", + "other": "Njegov \u010deki\u0107 je zamijenjen katanom, mo\u017ee sko\u010diti {int:NinjaJump} puta prije nego padne.", + }, + { + "key": "The Mercenary fly in air using his machine gun.", + "value": "Pla\u0107enik leti zrakom koriste\u0107i se machine gunom." + }, + { + "key": "He can also throw poison grenades that each deal {int:NumDamagePoints} damage points.", + "one": "Mo\u017ee bacati otrovne granate od kojih svaka dijeli jedan damage bod.", + "few": "Mo\u017ee bacati otrovne granate od kojih svaka dijeli {int:NumDamagePoints} damage bodova.", + "other": "Mo\u017ee bacati otrovne granate od kojih svaka dijeli {int:NumDamagePoints} damage bodova.", + }, + { + "key": "The Sniper can lock his position in air for 15 seconds with his hammer.", + "value": "Snajper mo\u017ee zaklju\u010dati svoju poziciju u zraku na 15 sekundi koriste\u0107i se \u010deki\u0107em." + }, + { + "key": "He can jump two times in air.", + "value": "Mo\u017ee sko\u010diti dva puta u zrak." + }, + { + "key": "He has also a powerful rifle that deals 20 damage points in locked position, and 9-10 otherwise.", + "value": "Ima i sna\u017enu pu\u0161ku koja dijeli 20 damage bodova u zaklju\u010danoj poziciji, a 9-10 bodova ina\u010de." + }, + { + "key": "The Smoker can infect humans and heal infected with his hammer.", + "value": "Pu\u0161a\u010d mo\u017ee zaraziti ljude i lije\u010diti zara\u017eene svojim \u010deki\u0107em." + }, + { + "key": "He can also inflict 4 damage points per second by hooking humans.", + "value": "Nanosi 4 damage boda po sekundi kad huka ljude." + }, + { + "key": "The Boomer explodes when he attack.", + "value": "Bumer eksplodira kada napadne." + }, + { + "key": "All humans affected by the explosion become infected.", + "value": "Svi ljudi zahva\u0107eni eksplozijom postanu zara\u017eeni." + }, + { + "key": "He can also inflict 1 damage point per second by hooking humans.", + "value": "Mo\u017ee nanijeniti 1 damage bod po sekundi kada huka ljude." + }, + { + "key": "The Hunter can infect humans and heal infected with his hammer.", + "value": "Lovac mo\u017ee zaraziti ljude i lije\u010diti zara\u017eene svojim \u010deki\u0107em." + }, + { + "key": "The Ghost can infect humans and heal infected with his hammer.", + "value": "Duh mo\u017ee zaraziti ljude i lije\u010diti zara\u017eene svojim \u010deki\u0107em." + }, + { + "key": "He is invisible, except if a human is near him, if he takes a damage or if he use his hammer.", + "value": "Nevidljiv je, osim ako je \u010dovjek blizu, ako primi udarac ili ako koristi \u010deki\u0107." + }, + { + "key": "The Spider can infect humans and heal infected with his hammer.", + "value": "Pauk mo\u017ee zaraziti ljude i lije\u010diti zara\u017eene svojim \u010deki\u0107em." + }, + { + "key": "When selecting any gun, his hook enter in web mode.", + "value": "Kada selektira\u0161 neko oru\u017eje, njegov huk prelazi u mre\u017eu." + }, + { + "key": "Any human that touch a hook in web mode is automatically grabbed.", + "value": "Kada \u010dovjek dotakne mre\u017eu, ona ga automatski dohvati." + }, + { + "key": "The hook of the spider (in both mode) deal 1 damage point per second and can grab a human during 2 seconds.", + "value": "Paukov huk (u oba moda) nanosi 1 damage bod po sekundi i mo\u017ee dr\u017eati \u010dovjeka 2 sekunde." + }, + { + "key": "The Undead can infect humans and heal infected with his hammer.", + "value": "Undead mo\u017ee zaraziti ljude i lije\u010diti zara\u017eene svojim \u010deki\u0107em." + }, + { + "key": "Instead of dying, he freezes during 10 seconds.", + "value": "Umjesto da umre, on se zaledi na 10 sekundi." + }, + { + "key": "If an infected heals him, the freeze effect disappear.", + "value": "Ako ga zara\u017eeni izlije\u010di, odledit \u0107e se." + }, + { + "key": "The Witch can infect humans and heal infected with his hammer.", + "value": "Vje\u0161tica mo\u017ee zaraziti ljude i lije\u010diti zara\u017eene svojim \u010deki\u0107em." + }, + { + "key": "When an infected dies, he may re-spawn near her.", + "value": "Kada zara\u017eeni umre, ponovo \u0107e se stvoriti kod nje." + }, + { + "key": "If the Witch dies, she disappear and is replaced by an another class of infected.", + "value": "Ako Vje\u0161tica umre, ona nestaje i zamijenjena je drugom klasom zara\u017eenih." + }, + { + "key": "She can also inflict 1 damage point per second by hooking humans.", + "value": "Mo\u017ee nanijeniti 1 damage bod po sekundi kada huka ljude." + }, + { + "key": "Available help pages: {str:PageList}", + "value": "Dostupne stranice za pomo\u0107: {str:PageList}" + }, + { + "key": "Choose a help page with /help ", + "value": "Izaberi stranicu za pomo\u0107 upisivanjem /help " + }, + { + "key": "A random class will be automatically attributed to you when rounds start", + "value": "Nasumi\u010dna klasa \u0107e ti biti dodijeljena kada zapo\u010dne runda" + }, + { + "key": "The class selector will be displayed when rounds start", + "value": "Selektor za klase \u0107e ti se prikazati kada runda zapo\u010dne" + }, + { + "key": "Unknown language", + "value": "Nepoznati jezik" + }, + { + "key": "Available languages: {str:ListOfLanguage}", + "value": "Dostupni jezici: {str:ListOfLanguage}" + }, + { + "key": "List of commands", + "value": "Lista komandi" + }, + { + "key": "Press or to enable or disable hook protection", + "value": "Pritisni ili da bi dopustio ili zabranio za\u0161titu protiv hukanja" + }, + { + "key": "No player was found with this name", + "value": "Nije na\u0111en igra\u010d sa tim imenom." + }, + { + "key": "Please wait 5 minutes before create an another account", + "value": "Molimo pri\u010dekajte 5 minuta prije nego napravite jo\u0161 jedan ra\u010dun" + }, + { + "key": "An error occured during the creation of your account.", + "value": "Dogodila se gre\u0161ka pri izradi Va\u0161eg ra\u010duna." + }, + { + "key": "This username is already taken by an existing account", + "value": "Korisni\u010dko ime je ve\u0107 zauzeto" + }, + { + "key": "Your account has been created and you are now logged.", + "value": "Va\u0161 ra\u010dun je napravljen i sada ste ulogirani." + }, + { + "key": "You must be logged to see your rank", + "value": "Morate biti ulogirani da bi vidjeli Va\u0161 rang" + }, + { + "key": "You must be logged to see your goal", + "value": "Morate biti ulogirani da bi vidjeli svoj cilj" + }, + { + "key": "You already notify that {str:PlayerName} must be banned", + "value": "Ve\u0107 ste obavjestili da {str:PlayerName} treba biti bannovan" + }, + { + "key": "{str:PlayerName} wants {str:VictimName} to be banned ({str:Reason})", + "value": "{str:PlayerName} \u017eeli da {str:VictimName} bude bannovan ({str:Reason})" + }, +]} diff --git a/data/languages/hu.json b/data/languages/hu.json index 96a0a1ba4..23d6e580f 100644 --- a/data/languages/hu.json +++ b/data/languages/hu.json @@ -422,4 +422,12 @@ "key": "Press or to enable or disable hook protection", "value": "Nyomd le az -at vagy -et, hogy enged\u00e9lyezd vagy letiltsd a horog-v\u00e9delmet" }, + { + "key": "No player was found with this name", + "value": "Nincs j\u00e1t\u00e9kos ilyen n\u00e9ven" + }, + { + "key": "Please wait 5 minutes before create an another account", + "value": "K\u00e9rj\u00fck v\u00e1rj 5 percet miel\u0151tt l\u00e9trehozol egy m\u00e1sik felhaszn\u00e1l\u00f3t" + }, ]} diff --git a/data/languages/index.json b/data/languages/index.json index ae0ef1ada..15c47826a 100644 --- a/data/languages/index.json +++ b/data/languages/index.json @@ -12,22 +12,27 @@ }, { "file": "cs", - "name": "czech", + "name": "Czech", "parent": "en" }, { "file": "de", - "name": "deutsch", + "name": "Deutsch", "parent": "en" }, { "file": "es", - "name": "español", + "name": "Español", "parent": "en" }, { "file": "fr", - "name": "français", + "name": "Français", + "parent": "en" + }, + { + "file": "hr", + "name": "Hrvatski", "parent": "en" }, { @@ -37,12 +42,17 @@ }, { "file": "it", - "name": "italiano", + "name": "Italiano", + "parent": "en" + }, + { + "file": "ja", + "name": "日本語", "parent": "en" }, { "file": "la", - "name": "latine", + "name": "Latine", "parent": "en" }, { @@ -52,7 +62,7 @@ }, { "file": "pl", - "name": "polszczyzna", + "name": "Polszczyzna", "parent": "en" }, { @@ -65,6 +75,11 @@ "name": "Русский", "parent": "en" }, + { + "file": "sk", + "name": "Slovenčina", + "parent": "cs" + }, { "file": "uk", "name": "Українська", diff --git a/data/languages/ja.json b/data/languages/ja.json new file mode 100644 index 000000000..2f45652de --- /dev/null +++ b/data/languages/ja.json @@ -0,0 +1,494 @@ +{"translation":[ + { + "key": "{str:VictimName} has been infected", + "value": "{str:VictimName} \u306f\u611f\u67d3\u3057\u305f" + }, + { + "key": "Infected won the round in {sec:RoundDuration}", + "value": "{sec:RoundDuration} \u3067\u5168\u54e1\u304c\u611f\u67d3\u3057\u305f\uff01" + }, + { + "key": "{int:NumHumans} humans won the round", + "other": "{int:NumHumans} \u4eba\u304c\u751f\u304d\u6b8b\u3063\u305f\uff01", + }, + { + "key": "You have survived, +5 points", + "value": "\u6700\u5f8c\u307e\u3067\u751f\u304d\u6b8b\u3063\u305f\uff01 +5\u30dd\u30a4\u30f3\u30c8" + }, + { + "key": "You have infected {str:VictimName}, +3 points", + "value": "{str:VictimName} \u3092\u611f\u67d3\u3055\u305b\u305f\uff01 +3\u30dd\u30a4\u30f3\u30c8" + }, + { + "key": "You have killed a witch, +5 points", + "value": "\u9b54\u5973\u3092\u5012\u3057\u305f\uff01 +5\u30dd\u30a4\u30f3\u30c8" + }, + { + "key": "The undead is coming!", + "value": "\u30a2\u30f3\u30c7\u30c3\u30c9\u304c\u73fe\u308c\u305f\uff01" + }, + { + "key": "The witch is coming!", + "value": "\u9b54\u5973\u304c\u73fe\u308c\u305f\uff01" + }, + { + "key": "Random choice", + "value": "\u8077\u696d\u62bd\u9078" + }, + { + "key": "Engineer", + "value": "\u30a8\u30f3\u30b8\u30cb\u30a2" + }, + { + "key": "Soldier", + "value": "\u5175\u58eb" + }, + { + "key": "Scientist", + "value": "\u79d1\u5b66\u8005" + }, + { + "key": "Medic", + "value": "\u533b\u8005" + }, + { + "key": "Hero", + "value": "\u30d2\u30fc\u30ed\u30fc" + }, + { + "key": "Ninja", + "value": "\u5fcd\u8005" + }, + { + "key": "Mercenary", + "value": "\u50ad\u5175" + }, + { + "key": "Sniper", + "value": "\u72d9\u6483\u5175" + }, + { + "key": "Choose your class", + "value": "\u597d\u304d\u306a\u8077\u696d\u3092\u9078\u3093\u3067\u4e0b\u3055\u3044" + }, + { + "key": "{int:NumBombs} bombs left", + "other": "{int:NumBombs} \u500b\u306e\u7206\u5f3e\u304c\u5c55\u958b\u4e2d", + }, + { + "key": "{int:NumMines} mines are actives", + "other": "{int:NumMines} \u500b\u306e\u5730\u96f7\u304c\u5c55\u958b\u4e2d", + }, + { + "key": "Next flag in {sec:RemainingTime}", + "value": "\u6b21\u306e\u30d5\u30e9\u30b0\u51fa\u73fe\u307e\u3067 \u6b8b\u308a {sec:RemainingTime}" + }, + { + "key": "Laser wall: {sec:RemainingTime}", + "value": "\u30d0\u30ea\u30a2\u5c55\u958b\u4e2d \u6b8b\u308a {sec:RemainingTime}" + }, + { + "key": "Position lock: {sec:RemainingTime}", + "value": "\u4f4d\u7f6e\u56fa\u5b9a \u6b8b\u308a {sec:RemainingTime}" + }, + { + "key": "Web mode enabled", + "value": "\u8718\u86db\u7cf8\u30e2\u30fc\u30c9\u4e2d" + }, + { + "key": "The witch is dead", + "value": "\u9b54\u5973\u306f\u5012\u308c\u305f" + }, + { + "key": "The undead is finally dead", + "value": "\u30a2\u30f3\u30c7\u30c3\u30c9\u306f\u5012\u308c\u305f" + }, + { + "key": "Type \"/help {str:ClassName}\" for more information about your class", + "value": "\"/help {str:ClassName}\" \u3067\u305d\u306e\u8077\u696d\u306e\u8a73\u7d30\u3092\u958b\u3051\u307e\u3059" + }, + { + "key": "The Hero found the flag!", + "value": "\u30d2\u30fc\u30ed\u30fc\u306f\u30d5\u30e9\u30b0\u3092\u898b\u3064\u3051\u305f\uff01" + }, + { + "key": "Hook protection enabled", + "value": "\u30d5\u30c3\u30af\u4fdd\u8b77\u4e2d" + }, + { + "key": "Hook protection disabled", + "value": "\u30d5\u30c3\u30af\u7121\u4fdd\u8b77\u4e2d" + }, + { + "key": "{str:PlayerName} has been banned ({str:Reason})", + "value": "{str:PlayerName} \u306fBAN\u3055\u308c\u305f({str:Reason})" + }, + { + "key": "{str:PlayerName} has been kicked ({str:Reason})", + "value": "{str:PlayerName} \u306f\u8ffd\u653e\u3055\u308c\u305f({str:Reason})" + }, + { + "key": "{str:PlayerName} has left the game ({str:Reason})", + "value": "{str:PlayerName} \u306f\u96e2\u8131\u3057\u305f ({str:Reason})" + }, + { + "key": "{str:PlayerName} has left the game", + "value": "{str:PlayerName} \u304c\u96e2\u8131\u3057\u307e\u3057\u305f" + }, + { + "key": "{str:PlayerName} joined the spectators", + "value": "{str:PlayerName} \u304c\u89b3\u6226\u30e2\u30fc\u30c9\u306b\u53c2\u52a0\u3057\u307e\u3057\u305f" + }, + { + "key": "{str:PlayerName} joined the game", + "value": "{str:PlayerName} \u304c\u53c2\u52a0\u3057\u307e\u3057\u305f" + }, + { + "key": "Smoker", + "value": "\u30be\u30f3\u30d3" + }, + { + "key": "Hunter", + "value": "\u30cf\u30f3\u30bf\u30fc" + }, + { + "key": "Boomer", + "value": "\u7206\u5f3e\u9b54" + }, + { + "key": "Ghost", + "value": "\u30b4\u30fc\u30b9\u30c8" + }, + { + "key": "Spider", + "value": "\u8718\u86db" + }, + { + "key": "Witch", + "value": "\u9b54\u5973" + }, + { + "key": "Undead", + "value": "\u30a2\u30f3\u30c7\u30c3\u30c9" + }, + { + "key": "Unknown class", + "value": "\u672a\u77e5\u306e\u30af\u30e9\u30b9" + }, + { + "key": "You are a human: {str:ClassName}", + "value": "\u3042\u306a\u305f\u306f\u751f\u5b58\u8005\u306b\u306a\u308a\u307e\u3057\u305f {str:ClassName}" + }, + { + "key": "You are an infected: {str:ClassName}", + "value": "\u3042\u306a\u305f\u306f\u611f\u67d3\u3057\u305f {str:ClassName}" + }, + { + "key": "{str:PlayerName} entered and joined the game", + "value": "{str:PlayerName}\u304c\u30b2\u30fc\u30e0\u306b\u5165\u308a\u3001\u53c2\u52a0\u3057\u307e\u3057\u305f" + }, + { + "key": "You can't join the spectators right now", + "value": "\u4eca\u306f\u89b3\u6226\u30e2\u30fc\u30c9\u306b\u79fb\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093" + }, + { + "key": "{str:PlayerName} changed their name to {str:NewName}", + "value": "{str:PlayerName} \u306f\u540d\u524d\u3092 {str:NewName} \u3078\u5909\u66f4\u3057\u307e\u3057\u305f" + }, + { + "key": "Switch language to english ?", + "value": "\u8a00\u8a9e\u306f\u82f1\u8a9e\u306b\u8a2d\u5b9a\u3057\u3066\u307e\u3059\u304b\uff1f" + }, + { + "key": "You can change the language of this mod using the command /language.", + "value": "\"/language\" \u3067\u3053\u306emod\u306e\u8a00\u8a9e\u3092\u5909\u66f4\u3067\u304d\u307e\u3059\u3002" + }, + { + "key": "If your language is not available, you can help with translation (/help translate).", + "value": "\u3082\u3057\u3042\u306a\u305f\u306e\u56fd\u306e\u8a00\u8a9e\u304c\u306a\u3044\u5834\u5408\u3001\u7ffb\u8a33\u3092\u3057\u3066\u4f5c\u308a\u307e\u3057\u3087\u3046\u3002(/help translate)" + }, + { + "key": "InfectionClass, by necropotame (version {str:VersionCode})", + "value": "InfectionClass, by necropotame (version {str:VersionCode})" + }, + { + "key": "Based on Infection mod by Gravity", + "value": "Infection mod\u3092\u5143\u306b\u3057\u307e\u3057\u305f\u3002 by Gravity" + }, + { + "key": "Thanks to {str:ListOfContributors}", + "value": "{str:ListOfContributors} \u306e\u304a\u304b\u3052\u3067" + }, + { + "key": "Rules of the game", + "value": "\u30b2\u30fc\u30e0\u30eb\u30fc\u30eb" + }, + { + "key": "InfectionClass is a team game between humans and infected.", + "value": "InfectionClass\u306f\u751f\u5b58\u8005\u3068\u611f\u67d3\u8005\u306b\u3088\u308b\u30c1\u30fc\u30e0\u30b2\u30fc\u30e0\u3067\u3059\u3002" + }, + { + "key": "All players start as human.", + "value": "\u958b\u59cb\u6642\u306f\u5168\u54e1\u751f\u5b58\u8005\u3067\u3059\u3002" + }, + { + "key": "10 seconds later, two players become infected.", + "value": "\u958b\u59cb10\u79d2\u5f8c\u3001\u30d7\u30ec\u30a4\u30e4\u30fc\u304c2\u4eba\u30e9\u30f3\u30c0\u30e0\u3067\u611f\u67d3\u3057\u307e\u3059\u3002" + }, + { + "key": "The goal for humans is to survive until the army clean the map.", + "value": "\u751f\u5b58\u8005\u5074\u306e\u52dd\u5229\u6761\u4ef6\u306f\u6700\u5f8c\u307e\u3067\u751f\u304d\u6b8b\u308b\u3053\u3068\u3067\u3059\u3002" + }, + { + "key": "The goal for infected is to infect all humans.", + "value": "\u611f\u67d3\u8005\u306e\u52dd\u5229\u6761\u4ef6\u306f\u5168\u3066\u306e\u751f\u5b58\u8005\u3092\u611f\u67d3\u3055\u305b\u308b\u3053\u3068\u3067\u3059\u3002" + }, + { + "key": "How to translate the mod", + "value": "\u3069\u306e\u3088\u3046\u306bmod\u3092\u7ffb\u8a33\u3057\u307e\u3059\u304b" + }, + { + "key": "Create an account on Transifex and join a translation team:", + "value": "Transifex\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u3092\u4f5c\u6210\u3057\u3066\u3001\u7ffb\u8a33\u306e\u30c1\u30fc\u30e0\u306b\u53c2\u52a0\u3057\u3066\u4e0b\u3055\u3044" + }, + { + "key": "For any question about the translation process, please contact us on IRC ({str:IRCAddress})", + "value": "\u7ffb\u8a33\u30d7\u30ed\u30bb\u30b9\u306b\u3064\u3044\u3066\u306e\u3069\u3093\u306a\u554f\u984c\u306e\u89e3\u6c7a\u306e\u70ba\u3001\u305c\u3072\u79c1\u305f\u3061IRC\u306b\u3054\u9023\u7d61\u4e0b\u3055\u3044 ({str:IRCAddress})" + }, + { + "key": "The Engineer can build walls with his hammer to block infected.", + "value": "\u30a8\u30f3\u30b8\u30cb\u30a2\u306f\u30cf\u30f3\u30de\u30fc\u3067\u30d0\u30ea\u30a2\u306e\u58c1\u3092\u69cb\u7bc9\u3067\u304d\u3001\u611f\u67d3\u8005\u3092\u59a8\u3052\u307e\u3059\u3002" + }, + { + "key": "When an infected touch the wall, he dies.", + "value": "\u5f7c\u304c\u5012\u308c\u308b\u3068\u3001\u305d\u306e\u30d0\u30ea\u30a2\u306f\u89e3\u304b\u308c\u307e\u3059\u3002" + }, + { + "key": "The lifespan of a wall is {sec:LifeSpan}, and walls are limited to one per player at the same time.", + "value": "\u30d0\u30ea\u30a2\u306f {sec:LifeSpan} \u307e\u3067\u6301\u3061\u3001\u307e\u305f1\u4eba\u306b\u3064\u304d1\u3064\u307e\u3067\u3057\u304b\u69cb\u7bc9\u3067\u304d\u307e\u305b\u3093\u3002" + }, + { + "key": "The Soldier can pose floating bombs with his hammer.", + "value": "\u5175\u58eb\u306f\u30cf\u30f3\u30de\u30fc\u3067\u7206\u5f3e\u3092\u4ed5\u639b\u3051\u3089\u308c\u307e\u3059\u3002" + }, + { + "key": "Each bomb can explode {int:NumBombs} times.", + "other": "\u7206\u5f3e\u306f {int:NumBombs} \u56de\u307e\u3067\u7206\u767a\u3055\u305b\u308c\u307e\u3059\u3002", + }, + { + "key": "Use the hammer to place the bomb and explode it multiple times.", + "value": "1\u5ea6\u30cf\u30f3\u30de\u30fc\u3092\u4f7f\u7528\u3059\u308b\u3068\u7206\u5f3e\u3092\u8a2d\u7f6e\u3057\u3001\u3082\u3046\u4e00\u5ea6\u4f7f\u7528\u3059\u308b\u3068\u7206\u5f3e\u3092\u7206\u767a\u3055\u305b\u308c\u307e\u3059\u3002" + }, + { + "key": "Bombs are limited to one per player at the same time.", + "value": "\u7206\u5f3e\u306f1\u4eba\u306b\u3064\u304d1\u3064\u69cb\u7bc9\u3067\u304d\u307e\u3059\u3002" + }, + { + "key": "The Scientist can pose floating mines with his hammer.", + "value": "\u79d1\u5b66\u8005\u306f\u30cf\u30f3\u30de\u30fc\u3067\u5730\u96f7\u3092\u4ed5\u639b\u3051\u3089\u308c\u307e\u3059\u3002" + }, + { + "key": "Mines are limited to {int:NumMines} per player at the same time.", + "other": "\u5730\u96f7\u306f1\u4eba\u306b\u3064\u304d{int:NumMines}\u3064\u307e\u3067\u69cb\u7bc9\u3067\u304d\u307e\u3059\u3002", + }, + { + "key": "He has also grenades that teleport him.", + "value": "\u307e\u305f\u3001\u30b0\u30ec\u30cd\u30fc\u30c9\u3092\u4f7f\u7528\u3057\u3066\u81ea\u8eab\u3092\u30c6\u30ec\u30dd\u30fc\u30c8\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002" + }, + { + "key": "The Medic can protect humans with his hammer by giving them armor.", + "value": "\u533b\u8005\u306f\u30cf\u30f3\u30de\u30fc\u3067\u4ed6\u306e\u751f\u5b58\u8005\u306e\u30a2\u30fc\u30de\u30fc\u3092\u56de\u5fa9\u3055\u305b\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002" + }, + { + "key": "He has also a powerful shotgun that can pullback infected.", + "value": "\u307e\u305f\u3001\u6240\u6301\u3057\u3066\u3044\u308b\u30b7\u30e7\u30c3\u30c8\u30ac\u30f3\u306f\u611f\u67d3\u8005\u3092\u8ffd\u3044\u6255\u3044\u3064\u3064\u30c0\u30e1\u30fc\u30b8\u3092\u4e0e\u3048\u3089\u308c\u307e\u3059\u3002" + }, + { + "key": "The Hero has a shotgun, a laser rifle and grenades.", + "value": "\u30d2\u30fc\u30ed\u30fc\u306f\u30b7\u30e7\u30c3\u30c8\u30ac\u30f3\u3001\u30ec\u30fc\u30b6\u30fc\u3001\u30b0\u30ec\u30cd\u30fc\u30c9\u30e9\u30f3\u30c1\u30e3\u30fc\u3092\u6240\u6301\u3057\u3066\u3044\u307e\u3059\u3002" + }, + { + "key": "The Hero must find a flag hidden in the map.", + "value": "\u30d2\u30fc\u30ed\u30fc\u306f\u30de\u30c3\u30d7\u306e\u6240\u3005\u306b\u3042\u308b\u30d5\u30e9\u30b0\u3092\u898b\u3064\u3051\u306a\u304b\u308c\u3070\u3044\u3051\u307e\u305b\u3093\u3002" + }, + { + "key": "Once taken, the flag gives 1 health point, 4 armor points, and full ammo to all humans, furthermore full health and armor to the hero.", + "value": "\u30d5\u30e9\u30b0\u30921\u672c\u53d6\u308b\u3054\u3068\u306b\u3001\u751f\u5b58\u8005\u5168\u54e1\u306e\u30cf\u30fc\u30c8\u30921\u56de\u5fa9\u3057\u3001\u30a2\u30fc\u30de\u30fc\u30924\u56de\u5fa9\u3055\u305b\u307e\u3059\u3002\u307e\u305f\u3001\u7372\u5f97\u3057\u305f\u30d2\u30fc\u30ed\u30fc\u306f\u30cf\u30fc\u30c8\u3068\u30a2\u30fc\u30de\u30fc\u304c\u305d\u308c\u305e\u308c\u5168\u56de\u5fa9\u3057\u307e\u3059\u3002" + }, + { + "key": "The hero cannot be healed by a medic, but he can withstand a thrust by an infected, an his health suffice.", + "value": "\u30d2\u30fc\u30ed\u30fc\u306f\u533b\u8005\u3067\u306e\u56de\u5fa9\u3092\u884c\u3046\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093\u304c\u3001\u611f\u67d3\u8005\u304b\u3089\u306e\u653b\u6483\u306b\u5c11\u3057\u8010\u6027\u304c\u4ed8\u304d\u307e\u3059\u3002" + }, + { + "key": "The Ninja can throw flash grenades that can freeze infected during three seconds.", + "value": "\u5fcd\u8005\u306f\u30d5\u30e9\u30c3\u30b7\u30e5\u30b0\u30ec\u30cd\u30fc\u30c9\u3092\u4f7f\u7528\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u3001\u30b0\u30ec\u30cd\u30fc\u30c9\u306e\u52b9\u679c\u7bc4\u56f2\u306b\u3044\u305f\u611f\u67d3\u8005\u306e\u52d5\u304d\u30923\u79d2\u9593\u5c01\u3058\u308c\u307e\u3059\u3002" + }, + { + "key": "His hammer is replaced by a katana, allowing him to jump {int:NinjaJump} times before touching the ground.", + "other": "\u307e\u305f\u3001\u5f7c\u306e\u30cf\u30f3\u30de\u30fc\u306f\u5200\u3068\u3057\u3066\u4f7f\u7528\u3067\u304d\u307e\u3059\u3002\u305d\u3057\u3066\u3001\u5f7c\u306f\u7a7a\u4e2d\u3067\u8df3\u3076\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002\u305f\u3060\u3057\u3001{int:NinjaJump}\u56de\u8df3\u3093\u3060\u5f8c\u306f\u7740\u5730\u3057\u306a\u3044\u3068\u518d\u4f7f\u7528\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093\u3002", + }, + { + "key": "The Mercenary fly in air using his machine gun.", + "value": "\u50ad\u5175\u306f\u30de\u30b7\u30f3\u30ac\u30f3\u3092\u4f7f\u7528\u3057\u3066\u98db\u3076\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002" + }, + { + "key": "He can also throw poison grenades that each deal {int:NumDamagePoints} damage points.", + "other": "\u307e\u305f\u3001\u30dd\u30a4\u30ba\u30f3\u30b0\u30ec\u30cd\u30fc\u30c9\u3092\u6295\u3052\u308b\u3053\u3068\u3082\u3067\u304d\u3001\u52b9\u679c\u7bc4\u56f2\u306b\u3044\u308b\u611f\u67d3\u8005\u306b{int:NumDamagePoints}\u30c0\u30e1\u30fc\u30b8\u3092\u4e0e\u3048\u307e\u3059\u3002", + }, + { + "key": "The Sniper can lock his position in air for 15 seconds with his hammer.", + "value": "\u72d9\u6483\u5175\u306f\u30cf\u30f3\u30de\u30fc\u3067\u73fe\u5728\u4f4d\u7f6e\u309215\u79d2\u9593\u56fa\u5b9a\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002" + }, + { + "key": "He can jump two times in air.", + "value": "\u307e\u305f\u3001\u7a7a\u4e2d\u30672\u56de\u30b8\u30e3\u30f3\u30d7\u3092\u884c\u3046\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002" + }, + { + "key": "He has also a powerful rifle that deals 20 damage points in locked position, and 9-10 otherwise.", + "value": "\u5f7c\u306f\u5f37\u529b\u306a\u30e9\u30a4\u30d5\u30eb\u3092\u6240\u6301\u3057\u3066\u304a\u308a\u3001\u4f4d\u7f6e\u3092\u56fa\u5b9a\u3057\u3066\u3044\u308b\u9593\u306f20\u30c0\u30e1\u30fc\u30b8\u3092\u4e0e\u3048\u3089\u308c\u307e\u3059\u3002\u901a\u5e38\u6642\u3067\u30829-10\u30c0\u30e1\u30fc\u30b8\u3092\u4e0e\u3048\u3089\u308c\u307e\u3059\u3002" + }, + { + "key": "The Smoker can infect humans and heal infected with his hammer.", + "value": "\u30be\u30f3\u30d3\u306f\u30cf\u30f3\u30de\u30fc\u3067\u751f\u5b58\u8005\u3092\u611f\u67d3\u3055\u305b\u305f\u308a\u3001\u4ed6\u306e\u611f\u67d3\u8005\u3092\u56de\u5fa9\u3055\u305b\u305f\u308a\u3067\u304d\u307e\u3059\u3002" + }, + { + "key": "He can also inflict 4 damage points per second by hooking humans.", + "value": "\u307e\u305f\u3001\u30d5\u30c3\u30af\u3067\u751f\u5b58\u8005\u3092\u6355\u3089\u3048\u308b\u3068\u3001\u305d\u306e\u751f\u5b58\u8005\u306b4\u30c0\u30e1\u30fc\u30b8\u305a\u3064\u4e0e\u3048\u307e\u3059\u3002" + }, + { + "key": "The Boomer explodes when he attack.", + "value": "\u7206\u5f3e\u9b54\u306f\u81ea\u7206\u3092\u3059\u308b\u3053\u3068\u3067\u653b\u6483\u304c\u3067\u304d\u307e\u3059\u3002" + }, + { + "key": "All humans affected by the explosion become infected.", + "value": "\u3069\u3093\u306a\u751f\u5b58\u8005\u3067\u3082\u3001\u7206\u98a8\u306b\u89e6\u308c\u308b\u3068\u611f\u67d3\u3057\u307e\u3059\u3002" + }, + { + "key": "He can also inflict 1 damage point per second by hooking humans.", + "value": "\u307e\u305f\u3001\u30d5\u30c3\u30af\u3067\u751f\u5b58\u8005\u3092\u6355\u3089\u3048\u308b\u3068\u3001\u305d\u306e\u751f\u5b58\u8005\u306b1\u30c0\u30e1\u30fc\u30b8\u305a\u3064\u4e0e\u3048\u307e\u3059\u3002" + }, + { + "key": "The Hunter can infect humans and heal infected with his hammer.", + "value": "\u30cf\u30f3\u30bf\u30fc\u306f\u30cf\u30f3\u30de\u30fc\u3067\u751f\u5b58\u8005\u3092\u611f\u67d3\u3055\u305b\u305f\u308a\u3001\u4ed6\u306e\u611f\u67d3\u8005\u3092\u56de\u5fa9\u3055\u305b\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002" + }, + { + "key": "The Ghost can infect humans and heal infected with his hammer.", + "value": "\u30b4\u30fc\u30b9\u30c8\u306f\u30cf\u30f3\u30de\u30fc\u3067\u751f\u5b58\u8005\u3092\u611f\u67d3\u3055\u305b\u305f\u308a\u3001\u4ed6\u306e\u611f\u67d3\u8005\u3092\u56de\u5fa9\u3055\u305b\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002" + }, + { + "key": "He is invisible, except if a human is near him, if he takes a damage or if he use his hammer.", + "value": "\u307e\u305f\u3001\u5f7c\u306f\u5e38\u306b\u900f\u660e\u3067\u3001\u751f\u5b58\u8005\u304c\u8fd1\u304f\u306b\u3044\u308b\u3068\u59ff\u3092\u73fe\u3057\u307e\u3059\u3002\u5f7c\u304c\u30c0\u30e1\u30fc\u30b8\u3092\u53d7\u3051\u305f\u6642\u3084\u3001\u30cf\u30f3\u30de\u30fc\u3092\u4f7f\u7528\u3057\u305f\u6642\u306b\u3082\u59ff\u3092\u73fe\u3057\u307e\u3059\u3002" + }, + { + "key": "The Spider can infect humans and heal infected with his hammer.", + "value": "\u8718\u86db\u306f\u30cf\u30f3\u30de\u30fc\u3067\u751f\u5b58\u8005\u3092\u611f\u67d3\u3055\u305b\u305f\u308a\u3001\u4ed6\u306e\u611f\u67d3\u8005\u3092\u56de\u5fa9\u3055\u305b\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002" + }, + { + "key": "When selecting any gun, his hook enter in web mode.", + "value": "\u307e\u305f\u3001\u30de\u30a6\u30b9\u30ab\u30fc\u30bd\u30eb\u3092\u64cd\u4f5c\u3059\u308b\u3068\u3001\u30d5\u30c3\u30af\u3092\u8718\u86db\u7cf8\u30e2\u30fc\u30c9\u306b\u5909\u66f4\u3067\u304d\u307e\u3059\u3002" + }, + { + "key": "Any human that touch a hook in web mode is automatically grabbed.", + "value": "\u3069\u3093\u306a\u751f\u5b58\u8005\u3067\u3082\u3001\u8718\u86db\u7cf8\u30e2\u30fc\u30c9\u4e2d\u306b\u6355\u3089\u3048\u3089\u308c\u308b\u3068\u9003\u3052\u308b\u306e\u304c\u56f0\u96e3\u306b\u306a\u308a\u307e\u3059\u3002" + }, + { + "key": "The hook of the spider (in both mode) deal 1 damage point per second and can grab a human during 2 seconds.", + "value": "\u30d5\u30c3\u30af(\u8718\u86db\u7cf8\u30e2\u30fc\u30c9\u4e2d)\u3067\u751f\u5b58\u8005\u3092\u6355\u3089\u3048\u308b\u3068\u3001\u305d\u306e\u751f\u5b58\u8005\u306b1\u30c0\u30e1\u30fc\u30b8\u305a\u3064\u4e0e\u3048\u3001\u3055\u3089\u306b2\u79d2\u9593\u63b4\u3080\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002" + }, + { + "key": "The Undead can infect humans and heal infected with his hammer.", + "value": "\u30a2\u30f3\u30c7\u30c3\u30c9\u306f\u30cf\u30f3\u30de\u30fc\u3067\u751f\u5b58\u8005\u3092\u611f\u67d3\u3055\u305b\u305f\u308a\u3001\u4ed6\u306e\u611f\u67d3\u8005\u3092\u56de\u5fa9\u3055\u305b\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002" + }, + { + "key": "Instead of dying, he freezes during 10 seconds.", + "value": "\u5f7c\u304c\u5012\u308c\u308b\u306810\u79d2\u9593\u884c\u52d5\u4e0d\u80fd\u306b\u306a\u308a\u307e\u3059\u3002" + }, + { + "key": "If an infected heals him, the freeze effect disappear.", + "value": "\u3057\u304b\u3057\u3001\u4ed6\u306e\u611f\u67d3\u8005\u304b\u3089\u306e\u56de\u5fa9\u3067\u3059\u3050\u306b\u5fa9\u6d3b\u3067\u304d\u307e\u3059\u3002" + }, + { + "key": "The Witch can infect humans and heal infected with his hammer.", + "value": "\u9b54\u5973\u306f\u30cf\u30f3\u30de\u30fc\u3067\u751f\u5b58\u8005\u3092\u611f\u67d3\u3055\u305b\u305f\u308a\u3001\u4ed6\u306e\u611f\u67d3\u8005\u3092\u56de\u5fa9\u3055\u305b\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002" + }, + { + "key": "When an infected dies, he may re-spawn near her.", + "value": "\u307e\u305f\u3001\u611f\u67d3\u8005\u304c\u5012\u308c\u305f\u3068\u304d\u306e\u4e00\u6642\u7684\u306a\u5fa9\u6d3b\u5730\u70b9\u3068\u3057\u3066\u6a5f\u80fd\u3057\u307e\u3059\u3002" + }, + { + "key": "If the Witch dies, she disappear and is replaced by an another class of infected.", + "value": "\u9b54\u5973\u306f\u5012\u308c\u308b\u3068\u3001\u5225\u306e\u611f\u67d3\u8005\u306e\u8077\u696d\u306b\u306a\u3063\u3066\u5fa9\u6d3b\u3057\u307e\u3059\u3002" + }, + { + "key": "She can also inflict 1 damage point per second by hooking humans.", + "value": "\u5f7c\u5973\u304c\u30d5\u30c3\u30af\u3067\u751f\u5b58\u8005\u3092\u6355\u3089\u3048\u308b\u3068\u3001\u305d\u306e\u751f\u5b58\u8005\u306b1\u30c0\u30e1\u30fc\u30b8\u305a\u3064\u4e0e\u3048\u307e\u3059\u3002" + }, + { + "key": "Available help pages: {str:PageList}", + "value": "\u95b2\u89a7\u3067\u304d\u308b\u30d8\u30eb\u30d7\u30da\u30fc\u30b8\uff1a{str:PageList}" + }, + { + "key": "Choose a help page with /help ", + "value": "\"/help <\u30da\u30fc\u30b8>\"\u3067\u30d8\u30eb\u30d7\u30da\u30fc\u30b8\u3092\u9078\u3093\u3067\u4e0b\u3055\u3044" + }, + { + "key": "A random class will be automatically attributed to you when rounds start", + "value": "\u30b9\u30bf\u30fc\u30c8\u6642\u306b\u8077\u696d\u62bd\u9078\u3092\u9078\u3093\u3060\u5834\u5408\u3001\u8077\u696d\u304c\u30e9\u30f3\u30c0\u30e0\u3067\u6c7a\u307e\u308a\u307e\u3059" + }, + { + "key": "The class selector will be displayed when rounds start", + "value": "\u8077\u696d\u9078\u629e\u30e1\u30cb\u30e5\u30fc\u306f\u3001\u30b9\u30bf\u30fc\u30c8\u6642\u306b\u8868\u793a\u3055\u308c\u307e\u3059" + }, + { + "key": "Unknown language", + "value": "\u672a\u77e5\u306e\u8a00\u8a9e" + }, + { + "key": "Available languages: {str:ListOfLanguage}", + "value": "\u4f7f\u7528\u53ef\u80fd\u306a\u8a00\u8a9e\uff1a{str:ListOfLanguage}" + }, + { + "key": "List of commands", + "value": "\u30b3\u30de\u30f3\u30c9\u30ea\u30b9\u30c8" + }, + { + "key": "Press or to enable or disable hook protection", + "value": "\u30d5\u30c3\u30af\u306e\u4fdd\u8b77\u3092\u8a31\u53ef\u3001\u7981\u6b62\u3059\u308b\u305f\u3081\u306b\u304b\u3092\u62bc\u3057\u3066\u4e0b\u3055\u3044" + }, + { + "key": "No player was found with this name", + "value": "\u305d\u306e\u540d\u524d\u306e\u30d7\u30ec\u30a4\u30e4\u30fc\u306f\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f" + }, + { + "key": "Please wait 5 minutes before create an another account", + "value": "\u5225\u30a2\u30ab\u30a6\u30f3\u30c8\u304c\u4f5c\u6210\u5b8c\u4e86\u3059\u308b\u307e\u30675\u5206\u9593\u304a\u5f85\u3061\u304f\u3060\u3055\u3044" + }, + { + "key": "An error occured during the creation of your account.", + "value": "\u30a2\u30ab\u30a6\u30f3\u30c8\u4f5c\u6210\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002" + }, + { + "key": "This username is already taken by an existing account", + "value": "\u3053\u306e\u540d\u524d\u306f\u65e2\u306b\u4f7f\u7528\u3055\u308c\u3066\u3044\u307e\u3059" + }, + { + "key": "Your account has been created and you are now logged.", + "value": "\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u4f5c\u6210\u304c\u5b8c\u4e86\u3057\u3001\u73fe\u5728\u30a2\u30ab\u30a6\u30f3\u30c8\u60c5\u5831\u3092\u8a18\u9332\u3057\u3066\u3044\u307e\u3059\u3002" + }, + { + "key": "You must be logged to see your rank", + "value": "\u8a18\u9332\u3092\u3059\u308b\u3053\u3068\u3067\u3042\u306a\u305f\u306e\u30e9\u30f3\u30af\u304c\u95b2\u89a7\u3067\u304d\u308b\u3088\u3046\u306b\u306a\u308a\u307e\u3059\u3002" + }, + { + "key": "You must be logged to see your goal", + "value": "\u8a18\u9332\u304c\u5b8c\u4e86\u3057\u307e\u3057\u305f\u3002" + }, + { + "key": "You already notify that {str:PlayerName} must be banned", + "value": "\u3053\u306e\u30a2\u30ab\u30a6\u30f3\u30c8 {str:PlayerName} \u306fBAN\u3055\u308c\u3066\u3044\u307e\u3059" + }, + { + "key": "{str:PlayerName} wants {str:VictimName} to be banned ({str:Reason})", + "value": "{str:PlayerName}\u306b\u3088\u308a\u3001{str:VictimName}\u306fBAN\u3055\u308c\u307e\u3057\u305f ({str:Reason})" + }, +]} diff --git a/data/languages/uk.json b/data/languages/uk.json index cc6baadaa..ae2d4b54b 100644 --- a/data/languages/uk.json +++ b/data/languages/uk.json @@ -9,7 +9,7 @@ }, { "key": "{int:NumHumans} humans won the round", - "one": "\u041e\u0434\u043d\u0430 \u043b\u044e\u0434\u0438\u043d\u0430 \u0432\u0438\u0433\u0440\u0430\u043b\u0430", + "one": "{int:NumHumans} \u043b\u044e\u0434\u0438\u043d\u0430 \u0432\u0438\u0433\u0440\u0430\u043b\u0430", "few": "{int:NumHumans} \u041b\u044e\u0434\u0435\u0439 \u0432\u0438\u0433\u0440\u0430\u043b\u043e", "other": "{int:NumHumans} \u041b\u044e\u0434\u0435\u0439 \u0432\u0438\u0433\u0440\u0430\u043b\u043e", }, @@ -75,13 +75,13 @@ }, { "key": "{int:NumBombs} bombs left", - "one": "\u0417\u0430\u043b\u0438\u0448\u0438\u043b\u0430\u0441\u044c \u043e\u0434\u043d\u0430 \u0431\u043e\u043c\u0431\u0430", + "one": "\u0417\u0430\u043b\u0438\u0448\u0438\u043b\u0430\u0441\u044c {int:NumBombs} \u0431\u043e\u043c\u0431\u0430", "few": "{int:NumBombs} \u0431\u043e\u043c\u0431 \u0437\u0430\u043b\u0438\u0448\u0438\u043b\u043e\u0441\u044c", "other": "{int:NumBombs} \u0431\u043e\u043c\u0431 \u0437\u0430\u043b\u0438\u0448\u0438\u043b\u043e\u0441\u044c", }, { "key": "{int:NumMines} mines are actives", - "one": "\u0417\u0430\u043b\u0438\u0448\u0438\u043b\u0430\u0441\u044c \u043e\u0434\u043d\u0430 \u043c\u0456\u043d\u0430", + "one": "\u0417\u0430\u043b\u0438\u0448\u0438\u043b\u0430\u0441\u044c {int:NumMines} \u043c\u0456\u043d\u0430", "few": "{int:NumMines} \u043c\u0456\u043d\u0438 \u0437\u0430\u043b\u0438\u0448\u0438\u043b\u043e\u0441\u044c", "other": "{int:NumMines} \u043c\u0456\u043d\u0438 \u0437\u0430\u043b\u0438\u0448\u0438\u043b\u043e\u0441\u044c", }, @@ -203,7 +203,7 @@ }, { "key": "Switch language to english ?", - "value": "\u0417\u043c\u0456\u043d\u0438\u0442\u0438 \u043c\u043e\u0432\u0443 \u043d\u0430 \u0430\u043d\u0433\u043b\u0456\u0441\u044e\u043a\u0443 ?" + "value": "\u0417\u043c\u0456\u043d\u0438\u0442\u0438 \u043c\u043e\u0432\u0443 \u043d\u0430 \u0430\u043d\u0433\u043b\u0456\u0439\u0441\u044c\u043a\u0443 ?" }, { "key": "You can change the language of this mod using the command /language.", @@ -211,7 +211,7 @@ }, { "key": "If your language is not available, you can help with translation (/help translate).", - "value": "\u042f\u043a\u0449\u043e \u043c\u043e\u0432\u0430 \u043d\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0432\u0438 \u043c\u043e\u0436\u0435\u0442\u0435 \u0434\u043e\u043f\u043e\u043c\u043e\u0433\u0442\u0438 \u0437 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u043e\u043c (/help translate)." + "value": "\u042f\u043a\u0449\u043e \u043c\u043e\u0432\u0430 \u043d\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430, \u0432\u0438 \u043c\u043e\u0436\u0435\u0442\u0435 \u0434\u043e\u043f\u043e\u043c\u043e\u0433\u0442\u0438 \u0437 \u043f\u0435\u0440\u0435\u043a\u043b\u0430\u0434\u043e\u043c (/help translate)." }, { "key": "InfectionClass, by necropotame (version {str:VersionCode})", @@ -279,7 +279,7 @@ }, { "key": "Each bomb can explode {int:NumBombs} times.", - "one": "\u041a\u043e\u0436\u043d\u0430 \u0431\u043e\u043c\u0431\u0430 \u043c\u043e\u0436\u0435 \u043f\u0456\u0434\u0456\u0440\u0432\u0430\u0442\u0438\u0441\u044c \u043e\u0434\u0438\u043d \u0440\u0430\u0437.", + "one": "\u041a\u043e\u0436\u043d\u0430 \u0431\u043e\u043c\u0431\u0430 \u043c\u043e\u0436\u0435 \u043f\u0456\u0434\u0456\u0440\u0432\u0430\u0442\u0438\u0441\u044c {int:NumBombs} \u0440\u0430\u0437.", "few": "\u041a\u043e\u0436\u043d\u0430 \u0431\u043e\u043c\u0431\u0430 \u043c\u043e\u0436\u0435 \u043f\u0456\u0434\u0456\u0440\u0432\u0430\u0442\u0438\u0441\u044c {int:NumBombs} \u0440\u0430\u0437. ", "other": "\u041a\u043e\u0436\u043d\u0430 \u0431\u043e\u043c\u0431\u0430 \u043c\u043e\u0436\u0435 \u043f\u0456\u0434\u0456\u0440\u0432\u0430\u0442\u0438\u0441\u044c {int:NumBombs} \u0440\u0430\u0437. ", }, @@ -297,7 +297,7 @@ }, { "key": "Mines are limited to {int:NumMines} per player at the same time.", - "one": "\u041c\u0456\u043d\u0438 \u043e\u0431\u043c\u0435\u0436\u0435\u043d\u0456 \u0434\u043e \u043e\u0434\u043d\u043e\u0457 \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u0433\u0440\u0430\u0432\u0446\u044f.", + "one": "\u041c\u0456\u043d\u0438 \u043e\u0431\u043c\u0435\u0436\u0435\u043d\u0456 \u0434\u043e {int:NumMines} \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u0433\u0440\u0430\u0432\u0446\u044f.", "few": "\u041c\u0456\u043d\u0438 \u043e\u0431\u043c\u0435\u0436\u0435\u043d\u0456 \u0434\u043e {int:NumMines} \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u0433\u0440\u0430\u0432\u0446\u044f.", "other": "\u041c\u0456\u043d\u0438 \u043e\u0431\u043c\u0435\u0436\u0435\u043d\u0456 \u0434\u043e {int:NumMines} \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u0433\u0440\u0430\u0432\u0446\u044f.", }, @@ -319,7 +319,7 @@ }, { "key": "The Hero must find a flag hidden in the map.", - "value": "\u0413\u0435\u0440\u043e\u0439 \u043c\u0430\u0454 \u0437\u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0438 \u043f\u0440\u0430\u043f\u043e\u0440\u0438, \u0449\u043e \u0441\u0445\u043e\u0432\u0430\u043d\u0456 \u043d\u0430 \u043a\u0430\u0442\u0440\u0456." + "value": "\u0413\u0435\u0440\u043e\u0439 \u043c\u0430\u0454 \u0437\u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0438 \u043f\u0440\u0430\u043f\u043e\u0440\u0438, \u0449\u043e \u0441\u0445\u043e\u0432\u0430\u043d\u0456 \u043d\u0430 \u043a\u0430\u0440\u0442\u0456." }, { "key": "Once taken, the flag gives 1 health point, 4 armor points, and full ammo to all humans, furthermore full health and armor to the hero.", @@ -345,7 +345,7 @@ }, { "key": "He can also throw poison grenades that each deal {int:NumDamagePoints} damage points.", - "one": "\u0412\u0456\u043d \u0442\u0430\u043a\u043e\u0436 \u043c\u043e\u0436\u0435 \u043a\u0438\u0434\u0430\u0442\u0438 \u043e\u0442\u0440\u0443\u0439\u043d\u0456 \u0433\u0440\u0430\u043d\u0430\u0442\u0438 \u044f\u043a\u0456 \u043e\u0442\u0440\u0443\u044e\u0454 \u043d\u0430 \u043e\u0434\u043d\u0435 \u043e\u0447\u043e\u043a\u043e \u0443\u0448\u043a\u043e\u0434\u0436\u0435\u043d\u043d\u044f.", + "one": "\u0412\u0456\u043d \u0442\u0430\u043a\u043e\u0436 \u043c\u043e\u0436\u0435 \u043a\u0438\u0434\u0430\u0442\u0438 \u043e\u0442\u0440\u0443\u0439\u043d\u0456 \u0433\u0440\u0430\u043d\u0430\u0442\u0438 \u044f\u043a\u0456 \u043e\u0442\u0440\u0443\u044e\u0454 \u043d\u0430 {int:NumDamagePoints} \u043e\u0447\u043e\u043a\u043e \u0443\u0448\u043a\u043e\u0434\u0436\u0435\u043d\u043d\u044f.", "few": "\u0412\u0456\u043d \u0442\u0430\u043a\u043e\u0436 \u043c\u043e\u0436\u0435 \u043a\u0438\u0434\u0430\u0442\u0438 \u043e\u0442\u0440\u0443\u0439\u043d\u0456 \u0433\u0440\u0430\u043d\u0430\u0442\u0438 \u044f\u043a\u0456 \u043e\u0442\u0440\u0443\u044e\u044e\u0442\u044c \u043d\u0430 {int:NumDamagePoints} \u043e\u0447\u043e\u043a \u0443\u0448\u043a\u043e\u0434\u0436\u0435\u043d\u043d\u044f.", "other": "\u0412\u0456\u043d \u0442\u0430\u043a\u043e\u0436 \u043c\u043e\u0436\u0435 \u043a\u0438\u0434\u0430\u0442\u0438 \u043e\u0442\u0440\u0443\u0439\u043d\u0456 \u0433\u0440\u0430\u043d\u0430\u0442\u0438 \u044f\u043a\u0456 \u043e\u0442\u0440\u0443\u044e\u044e\u0442\u044c \u043d\u0430 {int:NumDamagePoints} \u043e\u0447\u043e\u043a \u0443\u0448\u043a\u043e\u0434\u0436\u0435\u043d\u043d\u044f.", }, @@ -475,11 +475,11 @@ }, { "key": "Please wait 5 minutes before create an another account", - "value": "\u0411\u0443\u0434\u044c \u043b\u0430\u0441\u043a\u0430 \u0437\u0430\u0436\u0434\u0456\u0442\u044c 5 \u0445\u0432\u0438\u043b\u0438\u043d \u043f\u0435\u0440\u0435\u0434 \u0441\u0442\u0432\u043e\u0440\u0435\u043d\u043d\u044f\u043c \u043d\u043e\u0432\u043e\u0433\u043e \u0430\u043a\u0430\u043d\u0442\u0443" + "value": "\u0411\u0443\u0434\u044c \u043b\u0430\u0441\u043a\u0430 \u0437\u0430\u0436\u0434\u0456\u0442\u044c 5 \u0445\u0432\u0438\u043b\u0438\u043d \u043f\u0435\u0440\u0435\u0434 \u0441\u0442\u0432\u043e\u0440\u0435\u043d\u043d\u044f\u043c \u043d\u043e\u0432\u043e\u0433\u043e \u0430\u043a\u043a\u0430\u043d\u0442\u0443" }, { "key": "An error occured during the creation of your account.", - "value": "\u0437'\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u043f\u043e\u043c\u0438\u043b\u043a\u0430 \u043f\u0440\u0438 \u0441\u0442\u0432\u043e\u0440\u0435\u043d\u0456 \u0432\u0430\u0448\u043e\u0433\u043e \u0430\u043a\u0430\u043d\u0442\u0443." + "value": "\u0417'\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u043f\u043e\u043c\u0438\u043b\u043a\u0430 \u043f\u0440\u0438 \u0441\u0442\u0432\u043e\u0440\u0435\u043d\u0456 \u0432\u0430\u0448\u043e\u0433\u043e \u0430\u043a\u0430\u043d\u0442\u0443." }, { "key": "This username is already taken by an existing account", @@ -487,15 +487,15 @@ }, { "key": "Your account has been created and you are now logged.", - "value": "\u0412\u0430\u0448 \u0430\u043a\u0430\u043d\u0442 \u0441\u0442\u0432\u043e\u0440\u0435\u043d\u043e \u0442\u0430 \u0437\u043d\u0430\u0439\u0434\u0435\u043d\u043e \u0432 \u043d\u044c\u043e\u0433\u043e." + "value": "\u0412\u0430\u0448 \u0430\u043a\u043a\u0430\u0443\u043d\u0442 \u0441\u0442\u0432\u043e\u0440\u0435\u043d\u043e \u0442\u0430 \u0437\u043d\u0430\u0439\u0434\u0435\u043d\u043e \u0432 \u043d\u044c\u043e\u0433\u043e." }, { "key": "You must be logged to see your rank", - "value": "\u0412\u0438 \u043c\u0430\u0454\u0442\u0435 \u0443\u0432\u0456\u0439\u0442\u0438 \u0432 \u0441\u0432\u0456\u0439 \u0430\u043a\u0430\u043d\u0442, \u0449\u043e\u0431 \u043f\u043e\u0431\u0430\u0447\u0438\u0442\u0438 \u0441\u0432\u0456\u0439 \u0440\u0430\u043d\u0433" + "value": "\u0412\u0438 \u043c\u0430\u0454\u0442\u0435 \u0443\u0432\u0456\u0439\u0442\u0438 \u0432 \u0441\u0432\u0456\u0439 \u0430\u043a\u043a\u0430\u0443\u043d\u0442, \u0449\u043e\u0431 \u043f\u043e\u0431\u0430\u0447\u0438\u0442\u0438 \u0441\u0432\u0456\u0439 \u0440\u0430\u043d\u0433" }, { "key": "You must be logged to see your goal", - "value": "\u0412\u0438 \u043c\u0430\u0454\u0442\u0435 \u0443\u0432\u0456\u0439\u0442\u0438 \u0432 \u0441\u0432\u0456\u0439 \u0430\u043a\u0430\u043d\u0442, \u0449\u043e\u0431 \u043f\u043e\u0431\u0430\u0447\u0438\u0442\u0438 \u0441\u0432\u043e\u044e \u0446\u0456\u043b\u044c" + "value": "\u0412\u0438 \u043c\u0430\u0454\u0442\u0435 \u0443\u0432\u0456\u0439\u0442\u0438 \u0432 \u0441\u0432\u0456\u0439 \u0430\u043a\u043a\u0430\u0443\u043d\u0442, \u0449\u043e\u0431 \u043f\u043e\u0431\u0430\u0447\u0438\u0442\u0438 \u0441\u0432\u043e\u044e \u0446\u0456\u043b\u044c" }, { "key": "You already notify that {str:PlayerName} must be banned", diff --git a/scripts/translation.py b/scripts/translation.py index ae701d706..f69f62697 100644 --- a/scripts/translation.py +++ b/scripts/translation.py @@ -35,8 +35,10 @@ def ConvertPo2Json(languageCode, plurals): ConvertPo2Json("de", ["one", "other"]) ConvertPo2Json("es", ["one", "other"]) ConvertPo2Json("fr", ["one", "other"]) +ConvertPo2Json("hr", ["one", "few", "other"]) ConvertPo2Json("hu", ["one", "other"]) ConvertPo2Json("it", ["one", "other"]) +ConvertPo2Json("ja", ["other"]) ConvertPo2Json("la", ["one", "other"]) ConvertPo2Json("nl", ["one", "other"]) ConvertPo2Json("pl", ["one", "many", "other"]) diff --git a/src/engine/server.h b/src/engine/server.h index f12f08809..59dce19bd 100644 --- a/src/engine/server.h +++ b/src/engine/server.h @@ -263,6 +263,12 @@ class IGameServer : public IInterface virtual void SendMOTD_Localization(int To, const char* pText, ...) = 0; virtual void OnSetAuthed(int ClientID, int Level) = 0; + + virtual int GetTargetToKill() = 0; + virtual void TargetKilled() = 0; + virtual void EnableTargetToKill() = 0; + virtual void DisableTargetToKill() = 0; + virtual int GetTargetToKillCoolDown() = 0; /* INFECTION MODIFICATION END *****************************************/ }; diff --git a/src/engine/server/mapconverter.cpp b/src/engine/server/mapconverter.cpp index fe7a9e9bd..66bd1d0d5 100644 --- a/src/engine/server/mapconverter.cpp +++ b/src/engine/server/mapconverter.cpp @@ -164,6 +164,34 @@ void CMapConverter::CreateCircle(array* pQuads, vec2 CenterPos, float Siz } } +void CMapConverter::AddImageQuad(const char* pName, int ImageID, int GridX, int GridY, int X, int Y, int Width, int Height, vec2 Pos, vec2 Size, int Env) +{ + array aQuads; + CQuad Quad; + + float StepX = 1.0f/GridX; + float StepY = 1.0f/GridY; + + InitQuad(&Quad, Pos, Size); + Quad.m_ColorEnv = Env; + Quad.m_aTexcoords[0].x = Quad.m_aTexcoords[2].x = f2fx(StepX * X); + Quad.m_aTexcoords[1].x = Quad.m_aTexcoords[3].x = f2fx(StepX * (X + Width)); + Quad.m_aTexcoords[0].y = Quad.m_aTexcoords[1].y = f2fx(StepY * Y); + Quad.m_aTexcoords[2].y = Quad.m_aTexcoords[3].y = f2fx(StepY * (Y + Height)); + aQuads.add(Quad); + + CMapItemLayerQuads Item; + Item.m_Version = 2; + Item.m_Layer.m_Flags = 0; + Item.m_Layer.m_Type = LAYERTYPE_QUADS; + Item.m_Image = ImageID; + Item.m_NumQuads = aQuads.size(); + StrToInts(Item.m_aName, sizeof(Item.m_aName)/sizeof(int), pName); + Item.m_Data = m_DataFile.AddDataSwapped(aQuads.size()*sizeof(CQuad), aQuads.base_ptr()); + + m_DataFile.AddItem(MAPITEMTYPE_LAYER, m_NumLayers++, sizeof(Item), &Item); +} + void CMapConverter::AddTeeLayer(const char* pName, int ImageID, vec2 Pos, float Size, int Env, bool Black) { array aQuads; @@ -463,250 +491,437 @@ void CMapConverter::Finalize() int NinjaImageID = AddExternalImage("../skins/x_ninja", 256, 128); int MercenaryImageID = AddExternalImage("../skins/bluestripe", 256, 128); int SniperImageID = AddExternalImage("../skins/warpaint", 256, 128); + int GameImageID = AddExternalImage("../game", 1024, 512); + int ParticlesImageID = AddExternalImage("../particles", 512, 512); //Menu const float MenuRadius = 196.0f; const float MenuAngleStart = -pi/2.0f; - const float MenuAngleStep = 2.0f*pi/static_cast(NUM_MENUCLASS); - //Menu Group - { - CMapItemGroup Item; - Item.m_Version = CMapItemGroup::CURRENT_VERSION; - Item.m_ParallaxX = 0; - Item.m_ParallaxY = 0; - Item.m_OffsetX = 0; - Item.m_OffsetY = 0; - Item.m_StartLayer = m_NumLayers; - Item.m_NumLayers = 10; - Item.m_UseClipping = 0; - Item.m_ClipX = 0; - Item.m_ClipY = 0; - Item.m_ClipW = 0; - Item.m_ClipH = 0; - StrToInts(Item.m_aName, sizeof(Item.m_aName)/sizeof(int), "Menu"); - - m_DataFile.AddItem(MAPITEMTYPE_GROUP, m_NumGroups++, sizeof(Item), &Item); - } - //Menu Layers { - array aQuads; + const float MenuAngleStep = 2.0f*pi/static_cast(NUM_MENUCLASS); - int HiddenValues[4]; - int NormalValues[4]; - int HighlightValues[4]; - - HiddenValues[0] = 0; - HiddenValues[1] = 0; - HiddenValues[2] = 0; - HiddenValues[3] = 0; + //Menu Group + { + CMapItemGroup Item; + Item.m_Version = CMapItemGroup::CURRENT_VERSION; + Item.m_ParallaxX = 0; + Item.m_ParallaxY = 0; + Item.m_OffsetX = 0; + Item.m_OffsetY = 0; + Item.m_StartLayer = m_NumLayers; + Item.m_NumLayers = 10; + Item.m_UseClipping = 0; + Item.m_ClipX = 0; + Item.m_ClipY = 0; + Item.m_ClipW = 0; + Item.m_ClipH = 0; + StrToInts(Item.m_aName, sizeof(Item.m_aName)/sizeof(int), "Class Menu"); - //Two passes: one for circles, one for tees - for(int pass=0; pass<2; pass++) + m_DataFile.AddItem(MAPITEMTYPE_GROUP, m_NumGroups++, sizeof(Item), &Item); + } + //Menu Layers { - if(pass == 0) - { - NormalValues[0] = 0; - NormalValues[1] = 0; - NormalValues[2] = 0; - NormalValues[3] = 500; - - HighlightValues[0] = 1000; - HighlightValues[1] = 1000; - HighlightValues[2] = 1000; - HighlightValues[3] = 500; - } - else - { - NormalValues[0] = 1000; - NormalValues[1] = 1000; - NormalValues[2] = 1000; - NormalValues[3] = 1000; - - HighlightValues[0] = 1000; - HighlightValues[1] = 1000; - HighlightValues[2] = 1000; - HighlightValues[3] = 1000; - } + array aQuads; - for(int i=0; i(NUM_MENUEFFECT); + + //Menu Group + { + CMapItemGroup Item; + Item.m_Version = CMapItemGroup::CURRENT_VERSION; + Item.m_ParallaxX = 0; + Item.m_ParallaxY = 0; + Item.m_OffsetX = 0; + Item.m_OffsetY = 0; + Item.m_StartLayer = m_NumLayers; + Item.m_NumLayers = 10; + Item.m_UseClipping = 0; + Item.m_ClipX = 0; + Item.m_ClipY = 0; + Item.m_ClipW = 0; + Item.m_ClipH = 0; + StrToInts(Item.m_aName, sizeof(Item.m_aName)/sizeof(int), "Effect Menu"); - //Create Circle + m_DataFile.AddItem(MAPITEMTYPE_GROUP, m_NumGroups++, sizeof(Item), &Item); + } + + //Menu Layers + { + array aQuads; + + int HiddenValues[4]; + int NormalValues[4]; + int HighlightValues[4]; + + HiddenValues[0] = 0; + HiddenValues[1] = 0; + HiddenValues[2] = 0; + HiddenValues[3] = 0; + + //Two passes: one for circles, one for effects + for(int pass=0; pass<2; pass++) + { if(pass == 0) { - CreateCircle(&aQuads, m_MenuPosition+rotate(vec2(MenuRadius, 0.0f), MenuAngleStart+MenuAngleStep*i), 96.0f, vec4(1.0f, 1.0f, 1.0f, 0.5f), m_NumEnvs-1); + NormalValues[0] = 0; + NormalValues[1] = 0; + NormalValues[2] = 0; + NormalValues[3] = 500; + + HighlightValues[0] = 1000; + HighlightValues[1] = 1000; + HighlightValues[2] = 1000; + HighlightValues[3] = 500; } else { - vec2 Pos = m_MenuPosition+rotate(vec2(MenuRadius, 0.0f), MenuAngleStart+MenuAngleStep*i); - switch(i) + NormalValues[0] = 1000; + NormalValues[1] = 1000; + NormalValues[2] = 1000; + NormalValues[3] = 1000; + + HighlightValues[0] = 1000; + HighlightValues[1] = 1000; + HighlightValues[2] = 1000; + HighlightValues[3] = 1000; + } + + for(int i=0; iTick(); m_IsFrozen = false; m_FrozenTime = -1; - m_GhoulLevel = 0; - m_GhoulLevelTick = 0; + m_LoveTick = -1; m_PositionLockTick = -Server()->TickSpeed()*10; m_PositionLocked = false; m_Poison = 0; @@ -479,7 +476,7 @@ void CCharacter::UpdateTuningParam() if(GetClass() == PLAYERCLASS_GHOUL) { - float Factor = clamp(m_GhoulLevel/static_cast(g_Config.m_InfGhoulStomachSize), 0.0f, 1.0f); + float Factor = clamp(m_pPlayer->m_GhoulLevel/static_cast(g_Config.m_InfGhoulStomachSize), 0.0f, 1.0f); pTuningParams->m_GroundControlSpeed = pTuningParams->m_GroundControlSpeed * (1.0f + 0.5f*Factor); pTuningParams->m_GroundControlAccel = pTuningParams->m_GroundControlAccel * (1.0f + 0.5f*Factor); pTuningParams->m_GroundJumpImpulse = pTuningParams->m_GroundJumpImpulse * (1.0f + 0.35f*Factor); @@ -526,7 +523,7 @@ void CCharacter::FireWeapon() if(FullAuto && (m_LatestInput.m_Fire&1) && (m_aWeapons[m_ActiveWeapon].m_Ammo || (GetInfWeaponID(m_ActiveWeapon) == INFWEAPON_MERCENARY_GRENADE))) WillFire = true; - if(!WillFire) + if(!WillFire || m_pPlayer->MapMenu() > 0) return; // check for ammo @@ -619,26 +616,32 @@ void CCharacter::FireWeapon() } else if(GetClass() == PLAYERCLASS_MERCENARY) { - int NumBombs = 0; + CMercenaryBomb* pCurrentBomb = NULL; for(CMercenaryBomb *pBomb = (CMercenaryBomb*) GameWorld()->FindFirst(CGameWorld::ENTTYPE_MERCENARY_BOMB); pBomb; pBomb = (CMercenaryBomb*) pBomb->TypeNext()) { if(pBomb->m_Owner == m_pPlayer->GetCID()) - NumBombs++; + { + pCurrentBomb = pBomb; + break; + } } - if(NumBombs < g_Config.m_InfMercBombs) + if(pCurrentBomb) { - new CMercenaryBomb(GameWorld(), m_Pos, m_pPlayer->GetCID()); - GameServer()->CreateSound(m_Pos, SOUND_PICKUP_ARMOR); + if(distance(pCurrentBomb->m_Pos, m_Pos) < 120.0f) + { + pCurrentBomb->IncreaseDamage(); + GameServer()->CreateSound(m_Pos, SOUND_PICKUP_ARMOR); + } + else + pCurrentBomb->Explode(); } else { - for(CMercenaryBomb *pBomb = (CMercenaryBomb*) GameWorld()->FindFirst(CGameWorld::ENTTYPE_MERCENARY_BOMB); pBomb; pBomb = (CMercenaryBomb*) pBomb->TypeNext()) - { - if(pBomb->m_Owner == m_pPlayer->GetCID()) - pBomb->Explode(); - } + m_pPlayer->OpenMapMenu(2); } + + m_ReloadTimer = Server()->TickSpeed()/4; } else if(GetClass() == PLAYERCLASS_SCIENTIST) { @@ -1008,7 +1011,7 @@ void CCharacter::FireWeapon() if(GetClass() == PLAYERCLASS_SNIPER) { if(m_PositionLocked) - Damage = 20; + Damage = 30; else Damage = min(10, 9 + rand()%4); } @@ -1139,7 +1142,7 @@ void CCharacter::HandleWeapons() } else if(GetClass() == PLAYERCLASS_GHOUL) { - Rate = 0.25f + 0.75/(1.0f+m_GhoulLevel/2.0f); + Rate = 0.25f + 0.75/(1.0f+m_pPlayer->m_GhoulLevel/2.0f); } if(m_HookDmgTick + Server()->TickSpeed()*Rate < Server()->Tick()) @@ -1253,18 +1256,18 @@ void CCharacter::Tick() if(GetClass() == PLAYERCLASS_GHOUL) { - if(m_GhoulLevel > 0) + if(m_pPlayer->m_GhoulLevel > 0) { - m_GhoulLevelTick--; + m_pPlayer->m_GhoulLevelTick--; - if(m_GhoulLevelTick <= 0) + if(m_pPlayer->m_GhoulLevelTick <= 0 && m_pPlayer->m_GhoulLevel > 0) { - m_GhoulLevelTick = (Server()->TickSpeed()*g_Config.m_InfGhoulDigestion); - m_GhoulLevel--; + m_pPlayer->m_GhoulLevelTick = (Server()->TickSpeed()*g_Config.m_InfGhoulDigestion); + m_pPlayer->m_GhoulLevel--; } } - m_pPlayer->SetClassSkin(PLAYERCLASS_GHOUL, m_GhoulLevel); + m_pPlayer->SetClassSkin(PLAYERCLASS_GHOUL, m_pPlayer->m_GhoulLevel); } //Check is the character is in toxic gaz @@ -1305,10 +1308,13 @@ void CCharacter::Tick() else { int FreezeSec = 1+(m_FrozenTime/Server()->TickSpeed()); - GameServer()->SendBroadcast_Localization(m_pPlayer->GetCID(), BROADCAST_PRIORITY_EFFECTSTATE, BROADCAST_DURATION_REALTIME, "You are frozen: {sec:EffectDuration}", "EffectDuration", &FreezeSec, NULL); + GameServer()->SendBroadcast_Localization(m_pPlayer->GetCID(), BROADCAST_PRIORITY_EFFECTSTATE, BROADCAST_DURATION_REALTIME, _("You are frozen: {sec:EffectDuration}"), "EffectDuration", &FreezeSec, NULL); } } + if(m_LoveTick > 0) + --m_LoveTick; + if(m_Poison > 0) { if(m_PoisonTick == 0) @@ -1571,12 +1577,12 @@ void CCharacter::Tick() } } - if(m_pPlayer->InClassChooserMenu()) + if(m_pPlayer->MapMenu() == 1) { if(GetClass() != PLAYERCLASS_NONE) { m_AntiFireTick = Server()->Tick(); - m_pPlayer->m_InClassChooserMenu = 0; + m_pPlayer->CloseMapMenu(); } else { @@ -1588,9 +1594,9 @@ void CCharacter::Tick() { float Angle = 2.0f*pi+atan2(CursorPos.x, -CursorPos.y); float AngleStep = 2.0f*pi/static_cast(CMapConverter::NUM_MENUCLASS); - m_pPlayer->m_MenuClassChooserItem = ((int)((Angle+AngleStep/2.0f)/AngleStep))%CMapConverter::NUM_MENUCLASS; + m_pPlayer->m_MapMenuItem = ((int)((Angle+AngleStep/2.0f)/AngleStep))%CMapConverter::NUM_MENUCLASS; - switch(m_pPlayer->m_MenuClassChooserItem) + switch(m_pPlayer->m_MapMenuItem) { case CMapConverter::MENUCLASS_RANDOM: GameServer()->SendBroadcast_Localization(m_pPlayer->GetCID(), BROADCAST_PRIORITY_INTERFACE, BROADCAST_DURATION_REALTIME, _("Random choice"), NULL); @@ -1657,16 +1663,16 @@ void CCharacter::Tick() if(!Broadcast) { - m_pPlayer->m_MenuClassChooserItem = -1; + m_pPlayer->m_MapMenuItem = -1; GameServer()->SendBroadcast_Localization(m_pPlayer->GetCID(), BROADCAST_PRIORITY_INTERFACE, BROADCAST_DURATION_REALTIME, _("Choose your class"), NULL); } - if(m_Input.m_Fire&1 && m_pPlayer->m_MenuClassChooserItem >= 0) + if(m_Input.m_Fire&1 && m_pPlayer->m_MapMenuItem >= 0) { bool Bonus = false; int NewClass = -1; - switch(m_pPlayer->m_MenuClassChooserItem) + switch(m_pPlayer->m_MapMenuItem) { case CMapConverter::MENUCLASS_MEDIC: NewClass = PLAYERCLASS_MEDIC; @@ -1701,7 +1707,7 @@ void CCharacter::Tick() if(NewClass >= 0 && GameServer()->m_pController->IsChoosableClass(NewClass)) { m_AntiFireTick = Server()->Tick(); - m_pPlayer->m_InClassChooserMenu = 0; + m_pPlayer->m_MapMenuItem = 0; m_pPlayer->SetClass(NewClass); if(Bonus) @@ -1710,6 +1716,73 @@ void CCharacter::Tick() } } } + else if(m_pPlayer->MapMenu() == 2) + { + vec2 CursorPos = vec2(m_Input.m_TargetX, m_Input.m_TargetY); + + bool Broadcast = false; + + if(length(CursorPos) > 100.0f) + { + float Angle = 2.0f*pi+atan2(CursorPos.x, -CursorPos.y); + float AngleStep = 2.0f*pi/static_cast(CMapConverter::NUM_MENUEFFECT); + m_pPlayer->m_MapMenuItem = ((int)((Angle+AngleStep/2.0f)/AngleStep))%CMapConverter::NUM_MENUEFFECT; + + switch(m_pPlayer->m_MapMenuItem) + { + case CMapConverter::MENUEFFECT_CANCEL: + GameServer()->SendBroadcast_Localization(m_pPlayer->GetCID(), BROADCAST_PRIORITY_INTERFACE, BROADCAST_DURATION_REALTIME, _("Cancel"), NULL); + Broadcast = true; + break; + case CMapConverter::MENUEFFECT_EXPLOSION: + GameServer()->SendBroadcast_Localization(m_pPlayer->GetCID(), BROADCAST_PRIORITY_INTERFACE, BROADCAST_DURATION_REALTIME, _("Explosion"), NULL); + Broadcast = true; + break; + case CMapConverter::MENUEFFECT_LOVE: + GameServer()->SendBroadcast_Localization(m_pPlayer->GetCID(), BROADCAST_PRIORITY_INTERFACE, BROADCAST_DURATION_REALTIME, _("Aphrodisiac"), NULL); + Broadcast = true; + break; + case CMapConverter::MENUEFFECT_SHOCKWAVE: + GameServer()->SendBroadcast_Localization(m_pPlayer->GetCID(), BROADCAST_PRIORITY_INTERFACE, BROADCAST_DURATION_REALTIME, _("Shockwave"), NULL); + Broadcast = true; + break; + } + } + + if(!Broadcast) + { + m_pPlayer->m_MapMenuItem = -1; + GameServer()->SendBroadcast_Localization(m_pPlayer->GetCID(), BROADCAST_PRIORITY_INTERFACE, BROADCAST_DURATION_REALTIME, _("Choose bomb effect"), NULL); + } + + if(m_Input.m_Fire&1 && m_pPlayer->m_MapMenuItem >= 0 && m_pPlayer->MapMenuClickable()) + { + int BombType = -1; + switch(m_pPlayer->m_MapMenuItem) + { + case CMapConverter::MENUEFFECT_CANCEL: + m_pPlayer->CloseMapMenu(); + break; + case CMapConverter::MENUEFFECT_EXPLOSION: + BombType = CMercenaryBomb::EFFECT_EXPLOSION; + break; + case CMapConverter::MENUEFFECT_LOVE: + BombType = CMercenaryBomb::EFFECT_LOVE; + break; + case CMapConverter::MENUEFFECT_SHOCKWAVE: + BombType = CMercenaryBomb::EFFECT_SHOCKWAVE; + break; + } + + if(BombType >= 0) + { + new CMercenaryBomb(GameWorld(), m_Pos, m_pPlayer->GetCID(), BombType); + GameServer()->CreateSound(m_Pos, SOUND_PICKUP_ARMOR); + + m_pPlayer->CloseMapMenu(); + } + } + } if(GetClass() == PLAYERCLASS_ENGINEER) { @@ -1769,6 +1842,29 @@ void CCharacter::Tick() ); } } + else if(GetClass() == PLAYERCLASS_NINJA) + { + int TargetID = GameServer()->GetTargetToKill(); + int CoolDown = GameServer()->GetTargetToKillCoolDown(); + + if(CoolDown > 0) + { + int Seconds = 1+CoolDown/Server()->TickSpeed(); + GameServer()->SendBroadcast_Localization(GetPlayer()->GetCID(), BROADCAST_PRIORITY_WEAPONSTATE, BROADCAST_DURATION_REALTIME, + _("Next target in {sec:RemainingTime}"), + "RemainingTime", &Seconds, + NULL + ); + } + else if(TargetID >= 0) + { + GameServer()->SendBroadcast_Localization(GetPlayer()->GetCID(), BROADCAST_PRIORITY_WEAPONSTATE, BROADCAST_DURATION_REALTIME, + _("Target to eliminate: {str:PlayerName}"), + "PlayerName", Server()->ClientName(TargetID), + NULL + ); + } + } else if(GetClass() == PLAYERCLASS_SNIPER) { if(m_PositionLocked) @@ -1783,31 +1879,24 @@ void CCharacter::Tick() } else if(GetClass() == PLAYERCLASS_MERCENARY) { - int NumBombs = 0; + CMercenaryBomb* pCurrentBomb = NULL; for(CMercenaryBomb *pBomb = (CMercenaryBomb*) GameWorld()->FindFirst(CGameWorld::ENTTYPE_MERCENARY_BOMB); pBomb; pBomb = (CMercenaryBomb*) pBomb->TypeNext()) { if(pBomb->m_Owner == m_pPlayer->GetCID()) - NumBombs++; + { + pCurrentBomb = pBomb; + break; + } } - if(NumBombs) + if(pCurrentBomb) { - if(NumBombs < g_Config.m_InfMercBombs) - { - GameServer()->SendBroadcast_Localization_P(GetPlayer()->GetCID(), BROADCAST_PRIORITY_WEAPONSTATE, BROADCAST_DURATION_REALTIME, NumBombs, - _P("One bomb installed", "{int:NumBombs} bombs installed"), - "NumBombs", &NumBombs, - NULL - ); - } - else if(NumBombs >= g_Config.m_InfMercBombs) - { - GameServer()->SendBroadcast_Localization_P(GetPlayer()->GetCID(), BROADCAST_PRIORITY_WEAPONSTATE, BROADCAST_DURATION_REALTIME, NumBombs, - _P("One bomb ready", "{int:NumBombs} bombs ready"), - "NumBombs", &NumBombs, - NULL - ); - } + float BombLevel = pCurrentBomb->m_Damage/static_cast(g_Config.m_InfMercBombs); + GameServer()->SendBroadcast_Localization(GetPlayer()->GetCID(), BROADCAST_PRIORITY_WEAPONSTATE, BROADCAST_DURATION_REALTIME, + _("Explosive yield: {percent:BombLevel}"), + "BombLevel", &BombLevel, + NULL + ); } } else if(GetClass() == PLAYERCLASS_HERO) @@ -1844,9 +1933,9 @@ void CCharacter::Tick() } else if(GetClass() == PLAYERCLASS_GHOUL) { - if(m_GhoulLevel) + if(m_pPlayer->m_GhoulLevel) { - float FodderInStomach = m_GhoulLevel/static_cast(g_Config.m_InfGhoulStomachSize); + float FodderInStomach = m_pPlayer->m_GhoulLevel/static_cast(g_Config.m_InfGhoulStomachSize); GameServer()->SendBroadcast_Localization(GetPlayer()->GetCID(), BROADCAST_PRIORITY_WEAPONSTATE, BROADCAST_DURATION_REALTIME, _("Stomach filled by {percent:FodderInStomach}"), "FodderInStomach", &FodderInStomach, @@ -1864,7 +1953,6 @@ void CCharacter::Tick() void CCharacter::TickDefered() { - // advance the dummy { CCharacterCore::CParams CoreTickParams(&GameWorld()->m_Core.m_Tuning); @@ -2013,9 +2101,14 @@ void CCharacter::Die(int Killer, int Weapon) if(pGhoul && MinLen < 800.0f) { - new CFlyingPoint(GameWorld(), m_Pos, pGhoul->GetPlayer()->GetCID(), m_Core.m_Vel); + int Points = (IsInfected() ? 8 : 14); + new CFlyingPoint(GameWorld(), m_Pos, pGhoul->GetPlayer()->GetCID(), Points, m_Core.m_Vel); } } + if(GetClass() == PLAYERCLASS_GHOUL) + { + IncreaseGhoulLevel(-15); + } DestroyChildEntities(); /* INFECTION MODIFICATION END *****************************************/ @@ -2099,6 +2192,12 @@ bool CCharacter::TakeDamage(vec2 Force, int Dmg, int From, int Weapon, int Mode) if(GetClass() == PLAYERCLASS_HERO && Mode == TAKEDAMAGEMODE_INFECTION && pKillerPlayer && pKillerPlayer->IsInfected()) Dmg = 12; + if(pKillerPlayer && pKillerPlayer->GetCharacter() && pKillerPlayer->GetCharacter()->m_LoveTick > 0) + { + Dmg = 0; + Mode = TAKEDAMAGEMODE_NOINFECTION; + } + if(GetClass() != PLAYERCLASS_HUNTER || Weapon != WEAPON_SHOTGUN) { m_Core.m_Vel += Force; @@ -2109,7 +2208,7 @@ bool CCharacter::TakeDamage(vec2 Force, int Dmg, int From, int Weapon, int Mode) int DamageAccepted = 0; for(int i=0; i= m_GhoulLevel) + if(rand()%(g_Config.m_InfGhoulStomachSize) >= m_pPlayer->m_GhoulLevel/2) DamageAccepted++; } Dmg = DamageAccepted; @@ -2378,6 +2477,7 @@ void CCharacter::Snap(int SnappingClient) int EmoteNormal = EMOTE_NORMAL; if(IsInfected()) EmoteNormal = EMOTE_ANGRY; if(m_IsInvisible) EmoteNormal = EMOTE_BLINK; + if(m_LoveTick > 0) EmoteNormal = EMOTE_SURPRISE; if(IsFrozen()) EmoteNormal = EMOTE_PAIN; // write down the m_Core @@ -2462,7 +2562,7 @@ void CCharacter::OpenClassChooser() } else { - m_pPlayer->m_InClassChooserMenu = 1; + m_pPlayer->OpenMapMenu(1); } } @@ -2795,15 +2895,22 @@ bool CCharacter::IsInfected() const return m_pPlayer->IsInfected(); } -void CCharacter::IncreaseLevel() +void CCharacter::IncreaseGhoulLevel(int Points) { - if(GetClass() == PLAYERCLASS_GHOUL && m_GhoulLevel < static_cast(g_Config.m_InfGhoulStomachSize)) + if(GetClass() == PLAYERCLASS_GHOUL && m_pPlayer->m_GhoulLevel < static_cast(g_Config.m_InfGhoulStomachSize)) { - m_GhoulLevelTick = (Server()->TickSpeed()*g_Config.m_InfGhoulDigestion); - m_GhoulLevel++; + m_pPlayer->m_GhoulLevel += Points; + if(Points > 0) + m_pPlayer->m_GhoulLevelTick = (Server()->TickSpeed()*g_Config.m_InfGhoulDigestion); } } +void CCharacter::Love() +{ + if(m_LoveTick <= 0) + m_LoveTick = Server()->TickSpeed()*5; +} + void CCharacter::Freeze(float Time, int Player, int Reason) { if(m_IsFrozen) diff --git a/src/game/server/entities/character.h b/src/game/server/entities/character.h index fa77ac9de..faa5c0cb1 100644 --- a/src/game/server/entities/character.h +++ b/src/game/server/entities/character.h @@ -173,8 +173,6 @@ class CCharacter : public CEntity int m_FrozenTime; int m_FreezeReason; int m_InAirTick; - int m_GhoulLevel; - int m_GhoulLevelTick; char m_GhostSearchMap[GHOST_SEARCHMAP_SIZE*GHOST_SEARCHMAP_SIZE]; @@ -183,6 +181,7 @@ class CCharacter : public CEntity public: int m_PositionLockTick; bool m_PositionLocked; + int m_LoveTick; int m_PoisonTick; int m_Poison; int m_PoisonFrom; @@ -203,14 +202,14 @@ class CCharacter : public CEntity bool IsFrozen() const; void Unfreeze(); void Poison(int Count, int From); + void Love(); bool IsTeleportable(); int GetInfWeaponID(int WID); void UpdateTuningParam(); bool FindPortalPosition(vec2 Pos, vec2& Res); bool FindWitchSpawnPosition(vec2& Res); void SaturateVelocity(vec2 Force, float MaxSpeed); - void IncreaseLevel(); - inline int GetGhoulLevel() { return m_GhoulLevel; } + void IncreaseGhoulLevel(int Points); /* INFECTION MODIFICATION END *****************************************/ }; diff --git a/src/game/server/entities/engineer-wall.cpp b/src/game/server/entities/engineer-wall.cpp index 7d031b99a..d45e7ff45 100644 --- a/src/game/server/entities/engineer-wall.cpp +++ b/src/game/server/entities/engineer-wall.cpp @@ -79,8 +79,8 @@ void CEngineerWall::Tick() if(p->GetClass() == PLAYERCLASS_GHOUL) { - float Factor = clamp(p->GetGhoulLevel()/static_cast(g_Config.m_InfGhoulStomachSize), 0.0f, 1.0f); - LifeSpanReducer += Server()->TickSpeed() * 8.0f * Factor; + float Factor = clamp(p->GetPlayer()->m_GhoulLevel/static_cast(g_Config.m_InfGhoulStomachSize), 0.0f, 1.0f); + LifeSpanReducer += Server()->TickSpeed() * 5.0f * Factor; } m_LifeSpan -= LifeSpanReducer; diff --git a/src/game/server/entities/flyingpoint.cpp b/src/game/server/entities/flyingpoint.cpp index c5c589fd1..55f13713c 100644 --- a/src/game/server/entities/flyingpoint.cpp +++ b/src/game/server/entities/flyingpoint.cpp @@ -4,12 +4,13 @@ #include #include "flyingpoint.h" -CFlyingPoint::CFlyingPoint(CGameWorld *pGameWorld, vec2 Pos, int TrackedPlayer, vec2 InitialVel) +CFlyingPoint::CFlyingPoint(CGameWorld *pGameWorld, vec2 Pos, int TrackedPlayer, int Points, vec2 InitialVel) : CEntity(pGameWorld, CGameWorld::ENTTYPE_FLYINGPOINT) { m_Pos = Pos; m_TrackedPlayer = TrackedPlayer; m_InitialVel = InitialVel; + m_Points = Points; m_InitialAmount = 1.0f; GameWorld()->InsertEntity(this); } @@ -22,7 +23,7 @@ void CFlyingPoint::Tick() float Dist = distance(m_Pos, OwnerChar->m_Pos); if(Dist < 24.0f) { - OwnerChar->IncreaseLevel(); + OwnerChar->IncreaseGhoulLevel(m_Points); GameServer()->m_World.DestroyEntity(this); } else diff --git a/src/game/server/entities/flyingpoint.h b/src/game/server/entities/flyingpoint.h index cdb834c0c..2dedd12b5 100644 --- a/src/game/server/entities/flyingpoint.h +++ b/src/game/server/entities/flyingpoint.h @@ -11,9 +11,10 @@ class CFlyingPoint : public CEntity int m_TrackedPlayer; vec2 m_InitialVel; float m_InitialAmount; + int m_Points; public: - CFlyingPoint(CGameWorld *pGameWorld, vec2 Pos, int TrackedPlayer, vec2 InitialVel); + CFlyingPoint(CGameWorld *pGameWorld, vec2 Pos, int TrackedPlayer, int Points, vec2 InitialVel); virtual void Tick(); virtual void Snap(int SnappingClient); diff --git a/src/game/server/entities/growingexplosion.cpp b/src/game/server/entities/growingexplosion.cpp new file mode 100644 index 000000000..3eb85f2a5 --- /dev/null +++ b/src/game/server/entities/growingexplosion.cpp @@ -0,0 +1,329 @@ +/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ +/* If you are missing that file, acquire a complete release at teeworlds.com. */ + +#include "growingexplosion.h" + +#include + +CGrowingExplosion::CGrowingExplosion(CGameWorld *pGameWorld, vec2 Pos, vec2 Dir, int Owner, int Radius, int ExplosionEffect) + : CEntity(pGameWorld, CGameWorld::ENTTYPE_GROWINGEXPLOSION), + m_pGrowingMap(NULL), + m_pGrowingMapVec(NULL) +{ + m_MaxGrowing = Radius; + m_GrowingMap_Length = (2*m_MaxGrowing+1); + m_GrowingMap_Size = (m_GrowingMap_Length*m_GrowingMap_Length); + + m_pGrowingMap = new int[m_GrowingMap_Size]; + m_pGrowingMapVec = new vec2[m_GrowingMap_Size]; + + m_Pos = Pos; + m_StartTick = Server()->Tick(); + m_Owner = Owner; + m_ExplosionEffect = ExplosionEffect; + + mem_zero(m_Hit, sizeof(m_Hit)); + + GameWorld()->InsertEntity(this); + + vec2 explosionTile = vec2(16.0f, 16.0f) + vec2( + static_cast(static_cast(round(m_Pos.x))/32)*32.0, + static_cast(static_cast(round(m_Pos.y))/32)*32.0); + + //Check is the tile is occuped, and if the direction is valide + if(GameServer()->Collision()->CheckPoint(explosionTile) && length(Dir) <= 1.1) + { + m_SeedPos = vec2(16.0f, 16.0f) + vec2( + static_cast(static_cast(round(m_Pos.x + 32.0f*Dir.x))/32)*32.0, + static_cast(static_cast(round(m_Pos.y + 32.0f*Dir.y))/32)*32.0); + } + else + { + m_SeedPos = explosionTile; + } + + m_SeedX = static_cast(round(m_SeedPos.x))/32; + m_SeedY = static_cast(round(m_SeedPos.y))/32; + + for(int j=0; jCollision()->CheckPoint(Tile) || distance(Tile, m_SeedPos) > m_MaxGrowing*32.0f) + { + m_pGrowingMap[j*m_GrowingMap_Length+i] = -2; + } + else + { + m_pGrowingMap[j*m_GrowingMap_Length+i] = -1; + } + + m_pGrowingMapVec[j*m_GrowingMap_Length+i] = vec2(0.0f, 0.0f); + } + } + + m_pGrowingMap[m_MaxGrowing*m_GrowingMap_Length+m_MaxGrowing] = Server()->Tick(); + + switch(m_ExplosionEffect) + { + case GROWINGEXPLOSIONEFFECT_FREEZE_INFECTED: + if(rand()%10 == 0) + { + GameServer()->CreateHammerHit(m_SeedPos); + } + break; + case GROWINGEXPLOSIONEFFECT_POISON_INFECTED: + if(rand()%10 == 0) + { + GameServer()->CreateDeath(m_SeedPos, m_Owner); + } + break; + case GROWINGEXPLOSIONEFFECT_EXPLOSION_INFECTED: + if(rand()%5 == 0) + { + GameServer()->CreateDeath(m_SeedPos, m_Owner); + } + break; + case GROWINGEXPLOSIONEFFECT_SHOCKWAVE_INFECTED: + if(rand()%5 == 0) + { + GameServer()->CreateDeath(m_SeedPos, m_Owner); + } + m_pGrowingMapVec[m_MaxGrowing*m_GrowingMap_Length+m_MaxGrowing] = vec2(0.0f, 0.0f); + break; + case GROWINGEXPLOSIONEFFECT_ELECTRIC_INFECTED: + { + //~ GameServer()->CreateHammerHit(m_SeedPos); + + vec2 EndPoint = m_SeedPos + vec2(-16.0f + frandom()*32.0f, -16.0f + frandom()*32.0f); + m_pGrowingMapVec[m_MaxGrowing*m_GrowingMap_Length+m_MaxGrowing] = EndPoint; + } + break; + } +} + +CGrowingExplosion::~CGrowingExplosion() +{ + if(m_pGrowingMap) + { + delete[] m_pGrowingMap; + m_pGrowingMap = NULL; + } + + if(m_pGrowingMapVec) + { + delete[] m_pGrowingMapVec; + m_pGrowingMapVec = NULL; + } +} + +void CGrowingExplosion::Reset() +{ + GameServer()->m_World.DestroyEntity(this); +} + +void CGrowingExplosion::Tick() +{ + int tick = Server()->Tick(); + //~ if((tick - m_StartTick) > Server()->TickSpeed()) + if((tick - m_StartTick) > m_MaxGrowing) + { + GameServer()->m_World.DestroyEntity(this); + return; + } + + bool NewTile = false; + + for(int j=0; j 0 && m_pGrowingMap[j*m_GrowingMap_Length+i-1] < tick && m_pGrowingMap[j*m_GrowingMap_Length+i-1] >= 0); + bool FromRight = (i < m_GrowingMap_Length-1 && m_pGrowingMap[j*m_GrowingMap_Length+i+1] < tick && m_pGrowingMap[j*m_GrowingMap_Length+i+1] >= 0); + bool FromTop = (j > 0 && m_pGrowingMap[(j-1)*m_GrowingMap_Length+i] < tick && m_pGrowingMap[(j-1)*m_GrowingMap_Length+i] >= 0); + bool FromBottom = (j < m_GrowingMap_Length-1 && m_pGrowingMap[(j+1)*m_GrowingMap_Length+i] < tick && m_pGrowingMap[(j+1)*m_GrowingMap_Length+i] >= 0); + + if(FromLeft || FromRight || FromTop || FromBottom) + { + m_pGrowingMap[j*m_GrowingMap_Length+i] = tick; + NewTile = true; + vec2 TileCenter = m_SeedPos + vec2(32.0f*(i-m_MaxGrowing) - 16.0f + frandom()*32.0f, 32.0f*(j-m_MaxGrowing) - 16.0f + frandom()*32.0f); + switch(m_ExplosionEffect) + { + case GROWINGEXPLOSIONEFFECT_FREEZE_INFECTED: + if(rand()%10 == 0) + { + GameServer()->CreateHammerHit(TileCenter); + } + break; + case GROWINGEXPLOSIONEFFECT_POISON_INFECTED: + if(rand()%10 == 0) + { + GameServer()->CreateDeath(TileCenter, m_Owner); + } + break; + case GROWINGEXPLOSIONEFFECT_EXPLOSION_INFECTED: + if(rand()%5 == 0) + { + GameServer()->CreateExplosion(TileCenter, m_Owner, WEAPON_HAMMER, true); + } + break; + case GROWINGEXPLOSIONEFFECT_LOVE_INFECTED: + if(rand()%5 == 0) + { + GameServer()->CreateLoveEvent(TileCenter); + } + break; + case GROWINGEXPLOSIONEFFECT_SHOCKWAVE_INFECTED: + if(rand()%5 == 0) + { + GameServer()->CreateExplosion(TileCenter, m_Owner, WEAPON_HAMMER, true); + } + + { + vec2 Dir = vec2(0.0f, 0.0f); + + if(FromLeft) + Dir += m_pGrowingMapVec[j*m_GrowingMap_Length+i-1] + vec2(-1.0f, 0.0f); + if(FromRight) + Dir += m_pGrowingMapVec[j*m_GrowingMap_Length+i+1] + vec2(1.0f, 0.0f); + if(FromTop) + Dir += m_pGrowingMapVec[(j-1)*m_GrowingMap_Length+i] + vec2(0.0f, -1.0f); + if(FromBottom) + Dir += m_pGrowingMapVec[(j+1)*m_GrowingMap_Length+i+1] + vec2(0.0f, 1.0f); + + Dir = normalize(Dir); + + m_pGrowingMapVec[j*m_GrowingMap_Length+i] = Dir; + } + break; + case GROWINGEXPLOSIONEFFECT_ELECTRIC_INFECTED: + { + vec2 EndPoint = m_SeedPos + vec2(32.0f*(i-m_MaxGrowing) - 16.0f + frandom()*32.0f, 32.0f*(j-m_MaxGrowing) - 16.0f + frandom()*32.0f); + m_pGrowingMapVec[j*m_GrowingMap_Length+i] = EndPoint; + + int NumPossibleStartPoint = 0; + vec2 PossibleStartPoint[4]; + + if(FromLeft) + { + PossibleStartPoint[NumPossibleStartPoint] = m_pGrowingMapVec[j*m_GrowingMap_Length+i-1]; + NumPossibleStartPoint++; + } + if(FromRight) + { + PossibleStartPoint[NumPossibleStartPoint] = m_pGrowingMapVec[j*m_GrowingMap_Length+i+1]; + NumPossibleStartPoint++; + } + if(FromTop) + { + PossibleStartPoint[NumPossibleStartPoint] = m_pGrowingMapVec[(j-1)*m_GrowingMap_Length+i]; + NumPossibleStartPoint++; + } + if(FromBottom) + { + PossibleStartPoint[NumPossibleStartPoint] = m_pGrowingMapVec[(j+1)*m_GrowingMap_Length+i]; + NumPossibleStartPoint++; + } + + if(NumPossibleStartPoint > 0) + { + int randNb = rand()%NumPossibleStartPoint; + vec2 StartPoint = PossibleStartPoint[randNb]; + GameServer()->CreateLaserDotEvent(StartPoint, EndPoint, Server()->TickSpeed()/6); + } + + if(rand()%10 == 0) + { + GameServer()->CreateSound(EndPoint, SOUND_RIFLE_BOUNCE); + } + } + break; + } + } + } + } + } + + if(NewTile) + { + switch(m_ExplosionEffect) + { + case GROWINGEXPLOSIONEFFECT_POISON_INFECTED: + if(rand()%10 == 0) + { + GameServer()->CreateSound(m_Pos, SOUND_PLAYER_DIE); + } + break; + } + } + + // Find other players + for(CCharacter *p = (CCharacter*) GameWorld()->FindFirst(CGameWorld::ENTTYPE_CHARACTER); p; p = (CCharacter *)p->TypeNext()) + { + int tileX = m_MaxGrowing + static_cast(round(p->m_Pos.x))/32 - m_SeedX; + int tileY = m_MaxGrowing + static_cast(round(p->m_Pos.y))/32 - m_SeedY; + + if(!p->IsInfected()) + continue; + + if(tileX < 0 || tileX >= m_GrowingMap_Length || tileY < 0 || tileY >= m_GrowingMap_Length) + continue; + + if(m_Hit[p->GetPlayer()->GetCID()]) + continue; + + int k = tileY*m_GrowingMap_Length+tileX; + if(m_pGrowingMap[k] >= 0) + { + if(tick - m_pGrowingMap[k] < Server()->TickSpeed()/4) + { + switch(m_ExplosionEffect) + { + case GROWINGEXPLOSIONEFFECT_FREEZE_INFECTED: + p->Freeze(3.0f, m_Owner, FREEZEREASON_FLASH); + GameServer()->SendEmoticon(p->GetPlayer()->GetCID(), EMOTICON_QUESTION); + m_Hit[p->GetPlayer()->GetCID()] = true; + break; + case GROWINGEXPLOSIONEFFECT_POISON_INFECTED: + p->Poison(g_Config.m_InfPoisonDamage, m_Owner); + GameServer()->SendEmoticon(p->GetPlayer()->GetCID(), EMOTICON_DROP); + m_Hit[p->GetPlayer()->GetCID()] = true; + break; + case GROWINGEXPLOSIONEFFECT_EXPLOSION_INFECTED: + p->TakeDamage(vec2(0.0f, 0.0f), 9, m_Owner, WEAPON_HAMMER, TAKEDAMAGEMODE_NOINFECTION); + m_Hit[p->GetPlayer()->GetCID()] = true; + break; + case GROWINGEXPLOSIONEFFECT_SHOCKWAVE_INFECTED: + { + vec2 Force = -m_pGrowingMapVec[tileY*m_GrowingMap_Length+tileX] * 20.0f; + p->m_Core.m_Vel += Force; + break; + } + case GROWINGEXPLOSIONEFFECT_LOVE_INFECTED: + { + p->Love(); + GameServer()->SendEmoticon(p->GetPlayer()->GetCID(), EMOTICON_HEARTS); + m_Hit[p->GetPlayer()->GetCID()] = true; + break; + } + case GROWINGEXPLOSIONEFFECT_ELECTRIC_INFECTED: + { + int Damage = 5+20*((float)(m_MaxGrowing - min(tick - m_StartTick, (int)m_MaxGrowing)))/(m_MaxGrowing); + p->TakeDamage(normalize(p->m_Pos - m_SeedPos)*10.0f, Damage, m_Owner, WEAPON_HAMMER, TAKEDAMAGEMODE_NOINFECTION); + m_Hit[p->GetPlayer()->GetCID()] = true; + break; + } + } + } + } + } +} + +void CGrowingExplosion::TickPaused() +{ + ++m_StartTick; +} diff --git a/src/game/server/entities/growingexplosion.h b/src/game/server/entities/growingexplosion.h index 9da0c5d00..29855b44c 100644 --- a/src/game/server/entities/growingexplosion.h +++ b/src/game/server/entities/growingexplosion.h @@ -2,6 +2,7 @@ /* If you are missing that file, acquire a complete release at teeworlds.com. */ #include +#include #ifndef GAME_SERVER_ENTITIES_GROWINGEXP_H #define GAME_SERVER_ENTITIES_GROWINGEXP_H @@ -11,259 +12,33 @@ enum GROWINGEXPLOSIONEFFECT_FREEZE_INFECTED=0, GROWINGEXPLOSIONEFFECT_POISON_INFECTED, GROWINGEXPLOSIONEFFECT_ELECTRIC_INFECTED, + GROWINGEXPLOSIONEFFECT_EXPLOSION_INFECTED, + GROWINGEXPLOSIONEFFECT_SHOCKWAVE_INFECTED, + GROWINGEXPLOSIONEFFECT_LOVE_INFECTED, }; - -template + class CGrowingExplosion : public CEntity { -private: - enum - { - MAXGROWING = Radius, - GROWINGMAP_LENGTH = (2*MAXGROWING+1), - GROWINGMAP_SIZE = (GROWINGMAP_LENGTH*GROWINGMAP_LENGTH), - }; - public: - CGrowingExplosion(CGameWorld *pGameWorld, vec2 Pos, vec2 Dir, int Owner, int ExplosionEffect) - : CEntity(pGameWorld, CGameWorld::ENTTYPE_GROWINGEXPLOSION) - { - m_Pos = Pos; - m_StartTick = Server()->Tick(); - m_Owner = Owner; - m_ExplosionEffect = ExplosionEffect; - - mem_zero(m_Hit, sizeof(m_Hit)); - - GameWorld()->InsertEntity(this); - - vec2 explosionTile = vec2(16.0f, 16.0f) + vec2( - static_cast(static_cast(round(m_Pos.x))/32)*32.0, - static_cast(static_cast(round(m_Pos.y))/32)*32.0); - - //Check is the tile is occuped, and if the direction is valide - if(GameServer()->Collision()->CheckPoint(explosionTile) && length(Dir) <= 1.1) - { - m_SeedPos = vec2(16.0f, 16.0f) + vec2( - static_cast(static_cast(round(m_Pos.x + 32.0f*Dir.x))/32)*32.0, - static_cast(static_cast(round(m_Pos.y + 32.0f*Dir.y))/32)*32.0); - } - else - { - m_SeedPos = explosionTile; - } - - m_SeedX = static_cast(round(m_SeedPos.x))/32; - m_SeedY = static_cast(round(m_SeedPos.y))/32; - - for(int j=0; jCollision()->CheckPoint(Tile) || distance(Tile, m_SeedPos) > MAXGROWING*32.0f) - { - m_GrowingMap[j*GROWINGMAP_LENGTH+i] = -2; - } - else - { - m_GrowingMap[j*GROWINGMAP_LENGTH+i] = -1; - } - - m_GrowingMapVec[j*GROWINGMAP_LENGTH+i] = vec2(0.0f, 0.0f); - } - } - - m_GrowingMap[MAXGROWING*GROWINGMAP_LENGTH+MAXGROWING] = Server()->Tick(); - - switch(m_ExplosionEffect) - { - case GROWINGEXPLOSIONEFFECT_FREEZE_INFECTED: - if(rand()%10 == 0) - { - GameServer()->CreateHammerHit(m_SeedPos); - } - break; - case GROWINGEXPLOSIONEFFECT_POISON_INFECTED: - if(rand()%10 == 0) - { - GameServer()->CreateDeath(m_SeedPos, m_Owner); - } - break; - case GROWINGEXPLOSIONEFFECT_ELECTRIC_INFECTED: - { - //~ GameServer()->CreateHammerHit(m_SeedPos); - - vec2 EndPoint = m_SeedPos + vec2(-16.0f + frandom()*32.0f, -16.0f + frandom()*32.0f); - m_GrowingMapVec[MAXGROWING*GROWINGMAP_LENGTH+MAXGROWING] = EndPoint; - } - break; - } - } - - virtual void Reset() - { - GameServer()->m_World.DestroyEntity(this); - } + CGrowingExplosion(CGameWorld *pGameWorld, vec2 Pos, vec2 Dir, int Owner, int Radius, int ExplosionEffect); + virtual ~CGrowingExplosion(); - virtual void Tick() - { - int tick = Server()->Tick(); - if((tick - m_StartTick) > Server()->TickSpeed()) - { - GameServer()->m_World.DestroyEntity(this); - return; - } - - bool NewTile = false; - - for(int j=0; j 0 && m_GrowingMap[j*GROWINGMAP_LENGTH+i-1] < tick && m_GrowingMap[j*GROWINGMAP_LENGTH+i-1] >= 0); - bool FromRight = (i < GROWINGMAP_LENGTH-1 && m_GrowingMap[j*GROWINGMAP_LENGTH+i+1] < tick && m_GrowingMap[j*GROWINGMAP_LENGTH+i+1] >= 0); - bool FromTop = (j > 0 && m_GrowingMap[(j-1)*GROWINGMAP_LENGTH+i] < tick && m_GrowingMap[(j-1)*GROWINGMAP_LENGTH+i] >= 0); - bool FromBottom = (j < GROWINGMAP_LENGTH-1 && m_GrowingMap[(j+1)*GROWINGMAP_LENGTH+i] < tick && m_GrowingMap[(j+1)*GROWINGMAP_LENGTH+i] >= 0); - - if(FromLeft || FromRight || FromTop || FromBottom) - { - m_GrowingMap[j*GROWINGMAP_LENGTH+i] = tick; - NewTile = true; - switch(m_ExplosionEffect) - { - case GROWINGEXPLOSIONEFFECT_FREEZE_INFECTED: - if(rand()%10 == 0) - { - GameServer()->CreateHammerHit(m_SeedPos + vec2(32.0f*(i-MAXGROWING) - 16.0f + frandom()*32.0f, 32.0f*(j-MAXGROWING) - 16.0f + frandom()*32.0f)); - } - break; - case GROWINGEXPLOSIONEFFECT_POISON_INFECTED: - if(rand()%10 == 0) - { - GameServer()->CreateDeath(m_SeedPos + vec2(32.0f*(i-MAXGROWING) - 16.0f + frandom()*32.0f, 32.0f*(j-MAXGROWING) - 16.0f + frandom()*32.0f), m_Owner); - } - break; - case GROWINGEXPLOSIONEFFECT_ELECTRIC_INFECTED: - { - vec2 EndPoint = m_SeedPos + vec2(32.0f*(i-MAXGROWING) - 16.0f + frandom()*32.0f, 32.0f*(j-MAXGROWING) - 16.0f + frandom()*32.0f); - m_GrowingMapVec[j*GROWINGMAP_LENGTH+i] = EndPoint; - - int NumPossibleStartPoint = 0; - vec2 PossibleStartPoint[4]; - - if(FromLeft) - { - PossibleStartPoint[NumPossibleStartPoint] = m_GrowingMapVec[j*GROWINGMAP_LENGTH+i-1]; - NumPossibleStartPoint++; - } - if(FromRight) - { - PossibleStartPoint[NumPossibleStartPoint] = m_GrowingMapVec[j*GROWINGMAP_LENGTH+i+1]; - NumPossibleStartPoint++; - } - if(FromTop) - { - PossibleStartPoint[NumPossibleStartPoint] = m_GrowingMapVec[(j-1)*GROWINGMAP_LENGTH+i]; - NumPossibleStartPoint++; - } - if(FromBottom) - { - PossibleStartPoint[NumPossibleStartPoint] = m_GrowingMapVec[(j+1)*GROWINGMAP_LENGTH+i]; - NumPossibleStartPoint++; - } - - if(NumPossibleStartPoint > 0) - { - int randNb = rand()%NumPossibleStartPoint; - vec2 StartPoint = PossibleStartPoint[randNb]; - GameServer()->CreateLaserDotEvent(StartPoint, EndPoint, Server()->TickSpeed()/6); - } - - if(rand()%10 == 0) - { - GameServer()->CreateSound(EndPoint, SOUND_RIFLE_BOUNCE); - } - } - break; - } - } - } - } - } - - if(NewTile) - { - switch(m_ExplosionEffect) - { - case GROWINGEXPLOSIONEFFECT_POISON_INFECTED: - if(rand()%10 == 0) - { - GameServer()->CreateSound(m_Pos, SOUND_PLAYER_DIE); - } - break; - } - } - - // Find other players - for(CCharacter *p = (CCharacter*) GameWorld()->FindFirst(CGameWorld::ENTTYPE_CHARACTER); p; p = (CCharacter *)p->TypeNext()) - { - int tileX = MAXGROWING + static_cast(round(p->m_Pos.x))/32 - m_SeedX; - int tileY = MAXGROWING + static_cast(round(p->m_Pos.y))/32 - m_SeedY; - - if(!p->IsInfected()) - continue; - - if(tileX < 0 || tileX >= GROWINGMAP_LENGTH || tileY < 0 || tileY >= GROWINGMAP_LENGTH) - continue; - - if(m_Hit[p->GetPlayer()->GetCID()]) - continue; - - int k = tileY*GROWINGMAP_LENGTH+tileX; - if(m_GrowingMap[k] >= 0) - { - if(tick - m_GrowingMap[k] < Server()->TickSpeed()/4) - { - switch(m_ExplosionEffect) - { - case GROWINGEXPLOSIONEFFECT_FREEZE_INFECTED: - p->Freeze(3.0f, m_Owner, FREEZEREASON_FLASH); - GameServer()->SendEmoticon(p->GetPlayer()->GetCID(), EMOTICON_QUESTION); - break; - case GROWINGEXPLOSIONEFFECT_POISON_INFECTED: - p->Poison(g_Config.m_InfPoisonDamage, m_Owner); - GameServer()->SendEmoticon(p->GetPlayer()->GetCID(), EMOTICON_DROP); - break; - case GROWINGEXPLOSIONEFFECT_ELECTRIC_INFECTED: - { - int Damage = 5+20*((float)(MAXGROWING - min(tick - m_StartTick, (int)MAXGROWING)))/(MAXGROWING); - p->TakeDamage(normalize(p->m_Pos - m_SeedPos)*10.0f, Damage, m_Owner, WEAPON_HAMMER, TAKEDAMAGEMODE_NOINFECTION); - break; - } - } - - m_Hit[p->GetPlayer()->GetCID()] = true; - } - } - } - } - - virtual void TickPaused() - { - ++m_StartTick; - } + virtual void Reset(); + virtual void Tick(); + virtual void TickPaused(); private: + int m_MaxGrowing; + int m_GrowingMap_Length; + int m_GrowingMap_Size; + int m_Owner; vec2 m_SeedPos; int m_SeedX; int m_SeedY; int m_StartTick; - int m_GrowingMap[GROWINGMAP_SIZE]; - vec2 m_GrowingMapVec[GROWINGMAP_SIZE]; + int* m_pGrowingMap; + vec2* m_pGrowingMapVec; int m_ExplosionEffect; bool m_Hit[MAX_CLIENTS]; }; diff --git a/src/game/server/entities/merc-bomb.cpp b/src/game/server/entities/merc-bomb.cpp index 5273cfdc1..3fca98c2e 100644 --- a/src/game/server/entities/merc-bomb.cpp +++ b/src/game/server/entities/merc-bomb.cpp @@ -2,15 +2,18 @@ /* If you are missing that file, acquire a complete release at teeworlds.com. */ #include #include +#include "growingexplosion.h" #include "merc-bomb.h" -CMercenaryBomb::CMercenaryBomb(CGameWorld *pGameWorld, vec2 Pos, int Owner) +CMercenaryBomb::CMercenaryBomb(CGameWorld *pGameWorld, vec2 Pos, int Owner, int Type) : CEntity(pGameWorld, CGameWorld::ENTTYPE_MERCENARY_BOMB) { m_Pos = Pos; GameWorld()->InsertEntity(this); m_StartTick = Server()->Tick(); m_Owner = Owner; + m_Damage = 6; + m_Type = Type; } void CMercenaryBomb::Reset() @@ -18,34 +21,30 @@ void CMercenaryBomb::Reset() GameServer()->m_World.DestroyEntity(this); } +void CMercenaryBomb::IncreaseDamage() +{ + m_Damage += 2; + if(m_Damage > g_Config.m_InfMercBombs) + m_Damage = g_Config.m_InfMercBombs; +} + void CMercenaryBomb::Explode() { - float InnerRadius = 48.0f; - - GameServer()->CreateSound(m_Pos, SOUND_GRENADE_EXPLODE); - - for(int i=0; i<8; i++) - { - float Angle = 2.0f * pi * static_cast(i)/8.0f; - GameServer()->CreateExplosion(m_Pos + vec2(cos(Angle), sin(Angle)) * InnerRadius, m_Owner, WEAPON_HAMMER, true); - } + float Factor = static_cast(m_Damage)/g_Config.m_InfMercBombs; - CCharacter *apEnts[MAX_CLIENTS]; - float Radius = 135.0f; - int Num = GameServer()->m_World.FindEntities(m_Pos, Radius, (CEntity**)apEnts, MAX_CLIENTS, CGameWorld::ENTTYPE_CHARACTER); - for(int i = 0; i < Num; i++) + switch(m_Type) { - vec2 Diff = apEnts[i]->m_Pos - m_Pos; - vec2 ForceDir(0,1); - float l = length(Diff); - if(l) - ForceDir = normalize(Diff); - l = 1-clamp((l-InnerRadius)/(Radius-InnerRadius), 0.0f, 1.0f); - float Dmg = 12 * l; - if((int)Dmg) - apEnts[i]->TakeDamage(ForceDir*Dmg*2, (int)Dmg, m_Owner, WEAPON_HAMMER, TAKEDAMAGEMODE_NOINFECTION); + case EFFECT_EXPLOSION: + new CGrowingExplosion(GameWorld(), m_Pos, vec2(0.0, -1.0), m_Owner, 14.0f * Factor, GROWINGEXPLOSIONEFFECT_EXPLOSION_INFECTED); + break; + case EFFECT_LOVE: + new CGrowingExplosion(GameWorld(), m_Pos, vec2(0.0, -1.0), m_Owner, 14.0f * Factor, GROWINGEXPLOSIONEFFECT_LOVE_INFECTED); + break; + case EFFECT_SHOCKWAVE: + new CGrowingExplosion(GameWorld(), m_Pos, vec2(0.0, -1.0), m_Owner, 14.0f * Factor, GROWINGEXPLOSIONEFFECT_SHOCKWAVE_INFECTED); + break; } - + GameServer()->m_World.DestroyEntity(this); } @@ -54,6 +53,10 @@ void CMercenaryBomb::Snap(int SnappingClient) if(NetworkClipped(SnappingClient)) return; + CPlayer* pClient = GameServer()->m_apPlayers[SnappingClient]; + if(pClient->IsInfected()) + return; + CNetObj_Pickup *pP = static_cast(Server()->SnapNewItem(NETOBJTYPE_PICKUP, m_ID, sizeof(CNetObj_Pickup))); if(!pP) return; diff --git a/src/game/server/entities/merc-bomb.h b/src/game/server/entities/merc-bomb.h index 13d418e64..78e0df98d 100644 --- a/src/game/server/entities/merc-bomb.h +++ b/src/game/server/entities/merc-bomb.h @@ -9,16 +9,27 @@ class CMercenaryBomb : public CEntity { public: - CMercenaryBomb(CGameWorld *pGameWorld, vec2 Pos, int Owner); + enum + { + EFFECT_EXPLOSION = 0, + EFFECT_SHOCKWAVE, + EFFECT_LOVE, + }; + +public: + CMercenaryBomb(CGameWorld *pGameWorld, vec2 Pos, int Owner, int Type); virtual void Snap(int SnappingClient); void Reset(); void Explode(); void TickPaused(); + void IncreaseDamage(); public: int m_StartTick; int m_Owner; + int m_Damage; + int m_Type; }; #endif diff --git a/src/game/server/entities/merc-grenade.cpp b/src/game/server/entities/merc-grenade.cpp index c16ba4349..65f5f48e1 100644 --- a/src/game/server/entities/merc-grenade.cpp +++ b/src/game/server/entities/merc-grenade.cpp @@ -123,6 +123,6 @@ void CMercenaryGrenade::Snap(int SnappingClient) void CMercenaryGrenade::Explode() { - new CGrowingExplosion<4>(GameWorld(), m_ActualPos, m_ActualDir, m_Owner, GROWINGEXPLOSIONEFFECT_POISON_INFECTED); + new CGrowingExplosion(GameWorld(), m_ActualPos, m_ActualDir, m_Owner, 4, GROWINGEXPLOSIONEFFECT_POISON_INFECTED); GameServer()->m_World.DestroyEntity(this); } diff --git a/src/game/server/entities/projectile.cpp b/src/game/server/entities/projectile.cpp index 08c806e3d..70bb44ce6 100644 --- a/src/game/server/entities/projectile.cpp +++ b/src/game/server/entities/projectile.cpp @@ -87,7 +87,7 @@ void CProjectile::Tick() vec2 Dir = normalize(PrevPos - CurPos); if(length(Dir) > 1.1) Dir = normalize(m_StartPos - CurPos); - new CGrowingExplosion<8>(GameWorld(), CurPos, Dir, m_Owner, GROWINGEXPLOSIONEFFECT_FREEZE_INFECTED); + new CGrowingExplosion(GameWorld(), CurPos, Dir, m_Owner, 8, GROWINGEXPLOSIONEFFECT_FREEZE_INFECTED); } else if(m_IsPortal) { diff --git a/src/game/server/entities/scientist-mine.cpp b/src/game/server/entities/scientist-mine.cpp index 4b69e09ba..37a11f890 100644 --- a/src/game/server/entities/scientist-mine.cpp +++ b/src/game/server/entities/scientist-mine.cpp @@ -42,7 +42,7 @@ int CScientistMine::GetOwner() const void CScientistMine::Explode(int DetonatedBy) { - new CGrowingExplosion<6>(GameWorld(), m_Pos, vec2(0.0, -1.0), m_Owner, GROWINGEXPLOSIONEFFECT_ELECTRIC_INFECTED); + new CGrowingExplosion(GameWorld(), m_Pos, vec2(0.0, -1.0), m_Owner, 6, GROWINGEXPLOSIONEFFECT_ELECTRIC_INFECTED); GameServer()->m_World.DestroyEntity(this); //Self damage diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 1d0b4db93..06512a0e2 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -166,6 +166,16 @@ void CGameContext::CreateHammerDotEvent(vec2 Pos, int LifeSpan) m_HammerDots.add(State); } +void CGameContext::CreateLoveEvent(vec2 Pos) +{ + CGameContext::LoveDotState State; + State.m_Pos = Pos; + State.m_LifeSpan = Server()->TickSpeed(); + State.m_SnapID = Server()->SnapNewID(); + + m_LoveDots.add(State); +} + void CGameContext::CreateExplosion(vec2 Pos, int Owner, int Weapon, bool NoDamage, int TakeDamageMode) { // create the event @@ -775,6 +785,27 @@ void CGameContext::OnTick() } } + //Target to kill + if(m_TargetToKillCoolDown > 0) + m_TargetToKillCoolDown--; + + if(m_TargetToKillCoolDown == 0 && m_TargetToKill == -1) + { + int m_aTargetList[MAX_CLIENTS]; + int NbTargets = 0; + for(int i=0; iIsInfected()) + { + m_aTargetList[NbTargets] = i; + NbTargets++; + } + } + + if(NbTargets > 0) + m_TargetToKill = m_aTargetList[rand()%NbTargets]; + } + //Check for banvote if(!m_VoteCloseTime) { @@ -962,6 +993,20 @@ void CGameContext::OnTick() else DotIter++; } + + DotIter = 0; + while(DotIter < m_LoveDots.size()) + { + m_LoveDots[DotIter].m_LifeSpan--; + m_LoveDots[DotIter].m_Pos.y -= 5.0f; + if(m_LoveDots[DotIter].m_LifeSpan <= 0) + { + Server()->SnapFreeID(m_LoveDots[DotIter].m_SnapID); + m_LoveDots.remove_index(DotIter); + } + else + DotIter++; + } /* INFECTION MODIFICATION END *****************************************/ // update voting @@ -1617,56 +1662,42 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) switch(pMsg->m_Country) { - case 336: //Vatican - str_copy(m_VoteLanguage[ClientID], "la", sizeof(m_VoteLanguage[ClientID])); - break; - case 533: //Aruba - case 531: //Curacao - case 534: //Sint Maarten - case 528: //Netherland - case 740: //Suriname - case 56: //Belgique - str_copy(m_VoteLanguage[ClientID], "nl", sizeof(m_VoteLanguage[ClientID])); - break; - case 204: //Benin - case 854: //Burkina Faso - case 178: //Republic of the Congo - case 384: //Cote d'Ivoire - case 266: //Gabon - case 324: //Ginea - case 466: //Mali - case 562: //Niger - case 686: //Senegal - case 768: //Togo - case 250: //France - case 492: //Monaco - str_copy(m_VoteLanguage[ClientID], "fr", sizeof(m_VoteLanguage[ClientID])); + /* ar - Arabic ************************************/ + case 12: //Algeria + case 48: //Bahrain + case 262: //Djibouti + case 818: //Egypt + case 368: //Iraq + case 400: //Jordan + case 414: //Kuwait + case 422: //Lebanon + case 434: //Libya + case 478: //Mauritania + case 504: //Morocco + case 512: //Oman + case 275: //Palestine + case 634: //Qatar + case 682: //Saudi Arabia + case 706: //Somalia + case 729: //Sudan + case 760: //Syria + case 788: //Tunisia + case 784: //United Arab Emirates + case 887: //Yemen + str_copy(m_VoteLanguage[ClientID], "ar", sizeof(m_VoteLanguage[ClientID])); break; + /* cs - Czech *************************************/ case 203: //Czechia str_copy(m_VoteLanguage[ClientID], "cs", sizeof(m_VoteLanguage[ClientID])); break; - case 616: //Poland - str_copy(m_VoteLanguage[ClientID], "pl", sizeof(m_VoteLanguage[ClientID])); - break; + /* de - German ************************************/ case 40: //Austria case 276: //Germany case 438: //Liechtenstein case 756: //Switzerland str_copy(m_VoteLanguage[ClientID], "de", sizeof(m_VoteLanguage[ClientID])); break; - case 112: //Belarus - case 643: //Russia - str_copy(m_VoteLanguage[ClientID], "ru", sizeof(m_VoteLanguage[ClientID])); - break; - case 804: //Ukraine - str_copy(m_VoteLanguage[ClientID], "uk", sizeof(m_VoteLanguage[ClientID])); - break; - case 380: //Italy - str_copy(m_VoteLanguage[ClientID], "it", sizeof(m_VoteLanguage[ClientID])); - break; - case 348: //Hungary - str_copy(m_VoteLanguage[ClientID], "hu", sizeof(m_VoteLanguage[ClientID])); - break; + /* es - Spanish ***********************************/ case 32: //Argentina case 68: //Bolivia case 152: //Chile @@ -1689,7 +1720,56 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) case 858: //Uruguay case 862: //Venezuela str_copy(m_VoteLanguage[ClientID], "es", sizeof(m_VoteLanguage[ClientID])); + break; + /* fr - French ************************************/ + case 204: //Benin + case 854: //Burkina Faso + case 178: //Republic of the Congo + case 384: //Cote d'Ivoire + case 266: //Gabon + case 324: //Ginea + case 466: //Mali + case 562: //Niger + case 686: //Senegal + case 768: //Togo + case 250: //France + case 492: //Monaco + str_copy(m_VoteLanguage[ClientID], "fr", sizeof(m_VoteLanguage[ClientID])); + break; + /* hu - Croatian **********************************/ + case 191: //Croatia + str_copy(m_VoteLanguage[ClientID], "hr", sizeof(m_VoteLanguage[ClientID])); + break; + /* hu - Hungarian *********************************/ + case 348: //Hungary + str_copy(m_VoteLanguage[ClientID], "hu", sizeof(m_VoteLanguage[ClientID])); break; + /* it - Italian ***********************************/ + case 380: //Italy + str_copy(m_VoteLanguage[ClientID], "it", sizeof(m_VoteLanguage[ClientID])); + break; + /* ja - Japanese **********************************/ + case 392: //Japan + str_copy(m_VoteLanguage[ClientID], "ja", sizeof(m_VoteLanguage[ClientID])); + break; + /* la - Latin *************************************/ + case 336: //Vatican + str_copy(m_VoteLanguage[ClientID], "la", sizeof(m_VoteLanguage[ClientID])); + break; + /* nl - Dutch *************************************/ + case 533: //Aruba + case 531: //Curacao + case 534: //Sint Maarten + case 528: //Netherland + case 740: //Suriname + case 56: //Belgique + str_copy(m_VoteLanguage[ClientID], "nl", sizeof(m_VoteLanguage[ClientID])); + break; + /* pl - Polish *************************************/ + case 616: //Poland + str_copy(m_VoteLanguage[ClientID], "pl", sizeof(m_VoteLanguage[ClientID])); + break; + /* pt - Portuguese ********************************/ case 24: //Angola case 76: //Brazil case 132: //Cape Verde @@ -1700,28 +1780,18 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) case 678: //Sao Tome and Principe str_copy(m_VoteLanguage[ClientID], "pt", sizeof(m_VoteLanguage[ClientID])); break; - case 12: //Algeria - case 48: //Bahrain - case 262: //Djibouti - case 818: //Egypt - case 368: //Iraq - case 400: //Jordan - case 414: //Kuwait - case 422: //Lebanon - case 434: //Libya - case 478: //Mauritania - case 504: //Morocco - case 512: //Oman - case 275: //Palestine - case 634: //Qatar - case 682: //Saudi Arabia - case 706: //Somalia - case 729: //Sudan - case 760: //Syria - case 788: //Tunisia - case 784: //United Arab Emirates - case 887: //Yemen - str_copy(m_VoteLanguage[ClientID], "ar", sizeof(m_VoteLanguage[ClientID])); + /* ru - Russian ***********************************/ + case 112: //Belarus + case 643: //Russia + str_copy(m_VoteLanguage[ClientID], "ru", sizeof(m_VoteLanguage[ClientID])); + break; + /* sk - Slovak ************************************/ + case 703: //Slovakia + str_copy(m_VoteLanguage[ClientID], "sk", sizeof(m_VoteLanguage[ClientID])); + break; + /* uk - Ukranian **********************************/ + case 804: //Ukraine + str_copy(m_VoteLanguage[ClientID], "uk", sizeof(m_VoteLanguage[ClientID])); break; } @@ -2379,8 +2449,11 @@ bool CGameContext::ConChatInfo(IConsole::IResult *pResult, void *pUserData) const char aContributors[] = "guenstig werben, Defeater, Orangus, BlinderHeld, Warpaint, Serena, Socialdarwinist, FakeDeath, tee_to_F_U_UP!, Stitch626..."; pSelf->Server()->Localization()->Format_L(Buffer, pLanguage, _("InfectionClass, by necropotame (version {str:VersionCode})"), "{str:VersionCode}", "2.0", NULL); + Buffer.append("\n\n"); pSelf->Server()->Localization()->Format_L(Buffer, pLanguage, _("Based on Infection mod by Gravity"), NULL); + Buffer.append("\n\n"); pSelf->Server()->Localization()->Format_L(Buffer, pLanguage, _("Thanks to {str:ListOfContributors}"), "ListOfContributors", aContributors, NULL); + Buffer.append("\n\n"); pSelf->SendMOTD(ClientID, Buffer.buffer()); @@ -2929,46 +3002,28 @@ bool CGameContext::ConLanguage(IConsole::IResult *pResult, void *pUserData) int ClientID = pResult->GetClientID(); const char *pLanguageCode = (pResult->NumArguments()>0) ? pResult->GetString(0) : 0x0; - - bool ExistingLanguage = false; + char aFinalLanguageCode[8]; + aFinalLanguageCode[0] = 0; if(pLanguageCode) { - if(str_comp_nocase(pLanguageCode, "fr") == 0) - ExistingLanguage = true; - else if(str_comp_nocase(pLanguageCode, "de") == 0) - ExistingLanguage = true; - else if(str_comp_nocase(pLanguageCode, "uk") == 0) - ExistingLanguage = true; - else if(str_comp_nocase(pLanguageCode, "ru") == 0) - ExistingLanguage = true; - else if(str_comp_nocase(pLanguageCode, "it") == 0) - ExistingLanguage = true; - else if(str_comp_nocase(pLanguageCode, "es") == 0) - ExistingLanguage = true; - else if(str_comp_nocase(pLanguageCode, "ar") == 0) - ExistingLanguage = true; - else if(str_comp_nocase(pLanguageCode, "hu") == 0) - ExistingLanguage = true; - else if(str_comp_nocase(pLanguageCode, "pl") == 0) - ExistingLanguage = true; - else if(str_comp_nocase(pLanguageCode, "nl") == 0) - ExistingLanguage = true; - else if(str_comp_nocase(pLanguageCode, "la") == 0) - ExistingLanguage = true; - else if(str_comp_nocase(pLanguageCode, "pt") == 0) - ExistingLanguage = true; - else if(str_comp_nocase(pLanguageCode, "cs") == 0) - ExistingLanguage = true; - else if(str_comp_nocase(pLanguageCode, "en") == 0) - ExistingLanguage = true; - } - - if(ExistingLanguage) - { - pSelf->Server()->SetClientLanguage(ClientID, pLanguageCode); + if(str_comp_nocase(pLanguageCode, "ua") == 0) + str_copy(aFinalLanguageCode, "uk", sizeof(aFinalLanguageCode)); + else + { + for(int i=0; iServer()->Localization()->m_pLanguages.size(); i++) + { + if(str_comp_nocase(pLanguageCode, pSelf->Server()->Localization()->m_pLanguages[i]->GetFilename()) == 0) + str_copy(aFinalLanguageCode, pLanguageCode, sizeof(aFinalLanguageCode)); + } + } + } + + if(aFinalLanguageCode[0]) + { + pSelf->Server()->SetClientLanguage(ClientID, aFinalLanguageCode); if(pSelf->m_apPlayers[ClientID]) - pSelf->m_apPlayers[ClientID]->SetLanguage(pLanguageCode); + pSelf->m_apPlayers[ClientID]->SetLanguage(aFinalLanguageCode); } else { @@ -3243,6 +3298,28 @@ void CGameContext::OnSnap(int ClientID) pObj->m_Type = WEAPON_HAMMER; } } + for(int i=0; i < m_LoveDots.size(); i++) + { + if(ClientID >= 0) + { + vec2 CheckPos = m_LoveDots[i].m_Pos; + float dx = m_apPlayers[ClientID]->m_ViewPos.x-CheckPos.x; + float dy = m_apPlayers[ClientID]->m_ViewPos.y-CheckPos.y; + if(absolute(dx) > 1000.0f || absolute(dy) > 800.0f) + continue; + if(distance(m_apPlayers[ClientID]->m_ViewPos, CheckPos) > 1100.0f) + continue; + } + + CNetObj_Pickup *pObj = static_cast(Server()->SnapNewItem(NETOBJTYPE_PICKUP, m_LoveDots[i].m_SnapID, sizeof(CNetObj_Pickup))); + if(pObj) + { + pObj->m_X = (int)m_LoveDots[i].m_Pos.x; + pObj->m_Y = (int)m_LoveDots[i].m_Pos.y; + pObj->m_Type = POWERUP_HEALTH; + pObj->m_Subtype = 0; + } + } /* INFECTION MODIFICATION END *****************************************/ for(int i = 0; i < MAX_CLIENTS; i++) @@ -3251,6 +3328,17 @@ void CGameContext::OnSnap(int ClientID) m_apPlayers[i]->Snap(ClientID); } } + +int CGameContext::GetTargetToKill() +{ + return m_TargetToKill; +} +void CGameContext::TargetKilled() +{ + m_TargetToKill = -1; + m_TargetToKillCoolDown = Server()->TickSpeed()*15; +} + void CGameContext::OnPreSnap() {} void CGameContext::OnPostSnap() { diff --git a/src/game/server/gamecontext.h b/src/game/server/gamecontext.h index 43ba0615d..16ebf8565 100644 --- a/src/game/server/gamecontext.h +++ b/src/game/server/gamecontext.h @@ -63,6 +63,8 @@ class CGameContext : public IGameServer CCollision m_Collision; CNetObjHandler m_NetObjHandler; CTuningParams m_Tuning; + int m_TargetToKill; + int m_TargetToKillCoolDown; static bool ConTuneParam(IConsole::IResult *pResult, void *pUserData); static bool ConTuneReset(IConsole::IResult *pResult, void *pUserData); @@ -239,6 +241,7 @@ class CGameContext : public IGameServer void CreateLaserDotEvent(vec2 Pos0, vec2 Pos1, int LifeSpan); void CreateHammerDotEvent(vec2 Pos, int LifeSpan); + void CreateLoveEvent(vec2 Pos); void SendHitSound(int ClientID); void SendScoreSound(int ClientID); void AddBroadcast(int ClientID, const char* pText, int Priority, int LifeSpan); @@ -281,7 +284,22 @@ class CGameContext : public IGameServer }; array m_HammerDots; + struct LoveDotState + { + vec2 m_Pos; + int m_LifeSpan; + int m_SnapID; + }; + array m_LoveDots; + int m_aHitSoundState[MAX_CLIENTS]; //1 for hit, 2 for kill (no sounds must be sent) + +public: + virtual int GetTargetToKill(); + virtual void TargetKilled(); + virtual void EnableTargetToKill() { m_TargetToKill = (m_TargetToKill < 0 ? -1 : m_TargetToKill); } + virtual void DisableTargetToKill() { m_TargetToKill = -2; } + virtual int GetTargetToKillCoolDown() { return m_TargetToKillCoolDown; } /* INFECTION MODIFICATION END *****************************************/ }; diff --git a/src/game/server/gamemodes/mod.cpp b/src/game/server/gamemodes/mod.cpp index e731c194b..bd788c57d 100644 --- a/src/game/server/gamemodes/mod.cpp +++ b/src/game/server/gamemodes/mod.cpp @@ -241,6 +241,8 @@ void CGameControllerMOD::Tick() { bool StartInfectionStrigger = (m_RoundStartTick + Server()->TickSpeed()*10 == Server()->Tick()); + GameServer()->EnableTargetToKill(); + if(m_pHeroFlag) m_pHeroFlag->Show(); @@ -325,6 +327,8 @@ void CGameControllerMOD::Tick() if(m_pHeroFlag) m_pHeroFlag->Show(); + GameServer()->DisableTargetToKill(); + CPlayerIterator IterSpec(GameServer()->m_apPlayers); while(IterSpec.Next()) { @@ -453,6 +457,8 @@ void CGameControllerMOD::Tick() } else { + GameServer()->DisableTargetToKill(); + if(m_pHeroFlag) m_pHeroFlag->Show(); @@ -526,13 +532,24 @@ void CGameControllerMOD::Snap(int SnappingClient) ClassMask |= CMapConverter::MASK_SUPPORT; } - if(GameServer()->m_apPlayers[SnappingClient] && GameServer()->m_apPlayers[SnappingClient]->InClassChooserMenu()) + if(GameServer()->m_apPlayers[SnappingClient]) { - int Item = GameServer()->m_apPlayers[SnappingClient]->m_MenuClassChooserItem; - int Timer = ((CMapConverter::TIMESHIFT_MENUCLASS + (Item+1) + ClassMask*CMapConverter::TIMESHIFT_MENUCLASS_MASK)*60 + 30)*Server()->TickSpeed(); - - pGameInfoObj->m_RoundStartTick = Server()->Tick() - Timer; - pGameInfoObj->m_TimeLimit = 0; + if(GameServer()->m_apPlayers[SnappingClient]->MapMenu() == 1) + { + int Item = GameServer()->m_apPlayers[SnappingClient]->m_MapMenuItem; + int Timer = ((CMapConverter::TIMESHIFT_MENUCLASS + (Item+1) + ClassMask*CMapConverter::TIMESHIFT_MENUCLASS_MASK)*60 + 30)*Server()->TickSpeed(); + + pGameInfoObj->m_RoundStartTick = Server()->Tick() - Timer; + pGameInfoObj->m_TimeLimit = 0; + } + else if(GameServer()->m_apPlayers[SnappingClient]->MapMenu() == 2) + { + int Item = GameServer()->m_apPlayers[SnappingClient]->m_MapMenuItem; + int Timer = ((CMapConverter::TIMESHIFT_MENUEFFECT + (Item+1))*60 + 30)*Server()->TickSpeed(); + + pGameInfoObj->m_RoundStartTick = Server()->Tick() - Timer; + pGameInfoObj->m_TimeLimit = 0; + } } CNetObj_GameData *pGameDataObj = (CNetObj_GameData *)Server()->SnapNewItem(NETOBJTYPE_GAMEDATA, 0, sizeof(CNetObj_GameData)); @@ -597,6 +614,13 @@ int CGameControllerMOD::OnCharacterDeath(class CCharacter *pVictim, class CPlaye Server()->RoundStatistics()->OnScoreEvent(pKiller->GetCID(), SCOREEVENT_KILL_WITCH, pKiller->GetClass()); GameServer()->SendScoreSound(pKiller->GetCID()); } + else if(pKiller->GetClass() == PLAYERCLASS_NINJA && pVictim->GetPlayer()->GetCID() == GameServer()->GetTargetToKill()) + { + GameServer()->SendChatTarget_Localization(pKiller->GetCID(), CHATCATEGORY_SCORE, _("You have eliminated your target, +3 points"), NULL); + Server()->RoundStatistics()->OnScoreEvent(pKiller->GetCID(), SCOREEVENT_KILL_TARGET, pKiller->GetClass()); + GameServer()->SendScoreSound(pKiller->GetCID()); + GameServer()->TargetKilled(); + } else if(pVictim->IsInfected()) { Server()->RoundStatistics()->OnScoreEvent(pKiller->GetCID(), SCOREEVENT_KILL_INFECTED, pKiller->GetClass()); diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp index 8d536bd44..64faa5f2d 100644 --- a/src/game/server/player.cpp +++ b/src/game/server/player.cpp @@ -39,8 +39,9 @@ CPlayer::CPlayer(CGameContext *pGameServer, int ClientID, int Team) } m_WasHumanThisRound = false; - m_InClassChooserMenu = 0; - m_MenuClassChooserItem = -1; + m_MapMenu = 0; + m_MapMenuItem = -1; + m_MapMenuTick = -1; m_HookProtectionAutomatic = true; m_PrevTuningParams = *pGameServer->Tuning(); @@ -119,6 +120,9 @@ void CPlayer::Tick() ++m_LastActionTick; ++m_TeamChangeTick; } + + if(m_MapMenu > 0) + m_MapMenuTick++; HandleTuningParams(); } @@ -597,6 +601,9 @@ void CPlayer::SetClass(int newClass) if(m_class == newClass) return; + m_GhoulLevel = 0; + m_GhoulLevelTick = 0; + m_class = newClass; if(m_class < END_HUMANCLASS) @@ -657,4 +664,21 @@ void CPlayer::SetLanguage(const char* pLanguage) { str_copy(m_aLanguage, pLanguage, sizeof(m_aLanguage)); } +void CPlayer::OpenMapMenu(int Menu) +{ + m_MapMenu = Menu; + m_MapMenuTick = 0; +} + +void CPlayer::CloseMapMenu() +{ + m_MapMenu = 0; + m_MapMenuTick = -1; +} + +bool CPlayer::MapMenuClickable() +{ + return (m_MapMenu > 0 && (m_MapMenuTick > Server()->TickSpeed()/2)); +} + /* INFECTION MODIFICATION END *****************************************/ diff --git a/src/game/server/player.h b/src/game/server/player.h index 385ed7b78..5ce5f303d 100644 --- a/src/game/server/player.h +++ b/src/game/server/player.h @@ -123,11 +123,17 @@ class CPlayer int m_DefaultScoreMode; char m_aLanguage[16]; + int m_MapMenu; + int m_MapMenuTick; + public: int m_Authed; int m_ScoreRound; int m_HumanTime; + int m_GhoulLevel; + int m_GhoulLevelTick; + bool m_knownClass[NB_PLAYERCLASS]; int m_InfectionTick; @@ -149,8 +155,7 @@ class CPlayer bool m_HookProtection; bool m_HookProtectionAutomatic; - int m_InClassChooserMenu; - int m_MenuClassChooserItem; + int m_MapMenuItem; CTuningParams m_PrevTuningParams; CTuningParams m_NextTuningParams; @@ -158,7 +163,10 @@ class CPlayer void HandleTuningParams(); bool InscoreBoard() { return m_PlayerFlags & PLAYERFLAG_SCOREBOARD; }; - bool InClassChooserMenu() { return m_InClassChooserMenu && (m_Team != TEAM_SPECTATORS); }; + int MapMenu() { return (m_Team != TEAM_SPECTATORS) ? m_MapMenu : 0; }; + void OpenMapMenu(int Menu); + void CloseMapMenu(); + bool MapMenuClickable(); /* INFECTION MODIFICATION END *****************************************/ };