![]()
TheBestOrc
![]() offline
Опыт:
350Активность: |
АИ на джассе
GadenbIsh сделай обучающие статьи для АИ на джассе :) |
![]() |
#1
+0/−0
Профиль |
Приват |
Поиск |
Цитата |
IP: Записан
|
![]()
FellGuard
Losyash
![]() ![]() offline
Опыт:
39,547Активность: |
Пипец, люди, что вы за люди :)
TheBestOrc, спс за мануал на английском по ИИ, я могу перевести. Тебя устроит? FellGuard добавил: Кто не въехал - речь об этом вот http://xgm.guru/forum/showthread.php?t=8699 |
![]() |
#2
+0/−0
Профиль |
Приват |
Поиск |
Цитата |
IP: Записан
|
![]()
TheBestOrc
![]() offline
Опыт:
350Активность: |
FellGuard ты хорошем человеком :) , а может сделать анализ на ето :
The first couple of lines youll see is
================================================== ========================== Human Melee Strategic AI ================================================== ========================== globals boolean startup = true integer C_footmen = 0
integer C_priest = 0 integer C_riflemen = 0 integer C_gyro = 0 integer C_gryphon = 0 integer C_vs_air = 0 If you see this at the top you prolly opened the right ai file.
The Next Section you will see will be the Computers skill in order ai. This is what the computer will pick in order of skills for the corasponding hero. In this case its the paladin. The first skill that is used is HOLY BOLT. Change it around if you dont like that in that order. // ==================================================function set_skills takes nothing returns nothing
------------------------------------------------------------------------ if hero_id == PALADIN then ------------------------------------------------------------------------ set skills1[ 1] = HOLY_BOLT set skills1[ 2] = DEVOTION_AURA set skills1[ 3] = HOLY_BOLT set skills1[ 4] = DIVINE_SHIELD set skills1[ 5] = HOLY_BOLT set skills1[ 6] = RESURRECTION set skills1[ 7] = DEVOTION_AURA set skills1[ 8] = DEVOTION_AURA set skills1[ 9] = DIVINE_SHIELD set skills1[10] = DIVINE_SHIELD endif Notice the hero idea number. This is random between one or 2 possibilities of skill order for each hero. Scroll down and you should see Hero Id 2 for paladin then mountain king and so on...
Edit this how you want then save the txt doc.
Tip:Save The Changes every 5 minites of editing at least! Becuase one error in your scripting can make the whole thing not work! Every 5 minites test it cus.... in Ai Scripting you can make a mistake easily.
Part 2:SetUp Force
// ==================================================setup_force
================================================== ========================== function setup_force takes nothing returns nothing local integer foot local integer knight call AwaitMeleeHeroes()
loop
set foot = GetUnitCountDone(FOOTMAN) exitwhen foot >= 5 set knight = GetUnitCountDone(KNIGHT)
exitwhen foot + 2*knight >= 6 call Sleep(2)
endloop call InitAssaultGroup()
call RemoveInjuries() call SetAssaultGroup( 1, 9, hero_id )
call SetAssaultGroup( 0, 9, hero_id2 ) call SetAssaultGroup( 0, 9, FOOTMEN ) call SetAssaultGroup( 0, 9, KNIGHT ) call SetAssaultGroup( 0, 9, RIFLEMEN ) call SetAssaultGroup( 0, 9, PRIEST ) call SetAssaultGroup( 0, 9, SORCERESS ) call SetAssaultGroup( 0, 9, GRYPHON ) call SetAssaultGroup( 0, 9, COPTER ) call SetAssaultGroup( 0, 9, MORTAR ) call SetInitialWave(10)
endfunction If you want to get an in depth ai script you'll edit most of the script for the humans or whatever race you want to edit...
lol this is very hard to explain.... ill explain it as best as i can though...
First of all *i think that the ai for the computer has to build 5 footmen before it can build a knight* Then the amount of footmen + 2 knight has to = greater than 6 so the ai can goto the next step.
(Ideas i have about this):
1.The Local Integer Foot could indeed be a variable for a (FOOTMAN) so im guessing that you could change that to Local Integer Rifle Then make it say (RIFLEMAN) theres more to it than that but thats part of how you would go about changing something like that.
Part 3 Attack Sequence:
==================================================
==========================
attack_sequence ================================================== ==========================
function attack_sequence takes nothing returns nothing local boolean needs_exp local boolean has_siege local boolean major_ok local boolean air_units loop
exitwhen GetUnitCountDone(hero_id)>0 call Sleep(2) endloop call StaggerSleep(0,2)
loop loop exitwhen not CaptainRetreating() call Sleep(2) endloop call setup_force()
set major_ok = GetUnitCountDone(RIFLEMAN)>=2
set needs_exp = take_exp and major_ok set has_siege = GetUnitCountDone(MORTAR)>0 or GetUnitCountDone(TANK)>0 set air_units = GetUnitCountDone(COPTER)>0 or GetUnitCountDone(GRYPHON)>0 set allow_air_creeps = air_units or major_ok call SingleMeleeAttack(needs_exp,has_siege,major_ok,air
_units)
endloop endfunction something i noticed about all the ai scripting is it looks kind of like Jass 2 Programing language that blizzard came up with.
First part of this is that it states the variables that are used prolly.
Next it says Exit When GetUnitCount(hero_id)>0 This most likely means that the computer has to choose a skill for a hero of idea 1 or 2 to continue this part of the attack sequence.
This is all very confusing yes i know :P but try to understand as much as you can.
After that it says call Sleep(2) i havnt figured that term out yet but my guess is it waits a certain amount of time before it follows the next steps of ai.
i dont know what Stagger means lol... Ill post a reply later when i find out more about stagger sleep.
Now this is were Setup_force is used. It says call setup_Force most likely runs whatever ai you wrote for that part of the ai txt doc.
Next it should say set major_ok then alot of spaces to make it all fit perfectly i think it has to be like that or it wont work.
major_ok = GetUnitCountDone(RIFLEMAN)>=2 this ditermines that amount of riflemen that have to be built for the attack_sequence. That would be my best bet. You could change RILFMAN to FOOTMAN or anything you want but you have to know what your doing. For instance if you make it say tank right there your going to first find out if the computer has a WORKSHOP first to build the tank. So make sure that you know what you are doing before you change that. all the parts where it says set. This most likely sets the variable to either a value or a command of some sort.
The thing it says is set needs_exp = take_exp and major_ok
This probably means that the comp needs to get exp and at the same time the major_ok has to be set.
the last 2 sets basically tell you that the computer cant have motor teams or tanks at this time or air units.
Part 4 Init_Booleans:
==================================================
==========================
init_booleans ================================================== ==========================
function init_booleans takes nothing returns nothing set C_footmen = GetUnitCount(FOOTMEN) set C_priest = GetUnitCount(PRIEST) set C_riflemen = GetUnitCount(RIFLEMAN) set C_gyro = GetUnitCount(COPTER) set C_gryphon = GetUnitCount(GRYPHON) set keep = TownCountDone(KEEP)>0
set castle = GetUnitCountDone(CASTLE)>0 set mill = GetUnitCountDone(LUMBER_MILL)>0 set smith = GetUnitCountDone(BLACKSMITH)>0 set barracks = GetUnitCountDone(BARRACKS)>0 set knights = barracks and mill and smith and castle set workshop = GetUnitCountDone(WORKSHOP)>0 set sanctum = GetUnitCountDone(SANCTUM)>0 set aviary = GetUnitCountDone(AVIARY)>0 set priests = C_priest>0 set sorcery = GetUnitCount(SORCERESS)>0 if workshop and (castle or GetUpgradeLevel(UPG_BOMBS)>0) then
if aviary then set max_rifle = 0 0 set max_gyro = 2 4 set max_gryphon = 2 8 (=12) else set max_rifle = 3 9 set max_gyro = 1 2 set max_gryphon = 0 0 (=11) endif else if aviary then set max_rifle = 1 3 set max_gyro = 0 0 set max_gryphon = 2 8 (=11) else set max_rifle = 4 12 set max_gyro = 0 0 set max_gryphon = 0 0 (=12) endif endif endfunction Ok this part isnt as confusing as others that i will explain later. This part is first telling you some variables set most likly :P not possitive. Then It shows that if certain things were upgraded like the castle or upgrade bombs then it would set the max rilfe men to build to = 0 0 and so on...
Then it states if that isnt true then the computer builds all the other things you see. end if is the end of the section of the ai.
after that it says else if aviary then
i think this means that if that doesnt apply it goes to script (b) of part 4 script b is the other 2 sets of aviarys
so then it tells the computer to build those. else it builds set max_rifle = 4 12
set max_gyro = 0 0 That is the end of part 4. If you donnot understand this part dont bother reading the rest cus it gets even more confusing. This is one of the easy parts to understand. Not as easy as part 1 :P
Part 5 Upgrade_Sequence
================================================== ========================== upgrade_sequence ================================================== ========================== function upgrade_sequence takes nothing returns nothing *** BARRACKS UPGRADES ***
if barracks then call SetBuildUpgr( 1, UPG_DEFEND ) if workshop then
call SetBuildUpgr( 1, UPG_GUN_RANGE ) endif if knights then
call SetBuildUpgr( 1, UPG_BREEDING ) endif endif *** BLACKSMITH UPGRADES ***
if smith then call SetBuildUpgr( 1, UPG_MELEE ) call SetBuildUpgr( 1, UPG_ARMOR ) call SetBuildUpgr( 1, UPG_RANGED ) call SetBuildUpgr( 1, UPG_LEATHER ) if keep then
call SetBuildUpgr( 2, UPG_MELEE ) call SetBuildUpgr( 2, UPG_ARMOR ) call SetBuildUpgr( 2, UPG_RANGED ) call SetBuildUpgr( 2, UPG_LEATHER ) if castle then
call SetBuildUpgr( 3, UPG_MELEE ) call SetBuildUpgr( 3, UPG_ARMOR ) call SetBuildUpgr( 3, UPG_RANGED ) call SetBuildUpgr( 3, UPG_LEATHER ) endif endif endif *** SANCTUM UPGRADES ***
if sanctum and priests then call SetBuildUpgr( 1, UPG_PRAYING ) if sorcery then
call SetBuildUpgr( 1, UPG_SORCERY ) endif if castle and priests then
call SetBuildUpgr( 2, UPG_PRAYING ) if sorcery then
call SetBuildUpgr( 2, UPG_SORCERY ) call SetBuildUpgr( 1, UPG_SENTINEL ) endif endif endif *** LUMBER MILL UPGRADES ***
if mill and keep then call SetBuildUpgr( 1, UPG_WOOD ) if castle then
call SetBuildUpgr( 2, UPG_WOOD ) call SetBuildUpgr( 2, UPG_MASONRY ) endif endif *** WORKSHOP UPGRADES ***
if workshop and C_gyro>0 then call SetBuildUpgr( 1, UPG_BOMBS ) endif *** AVIARY UPGRADES ***
if aviary and C_gryphon>0 then call SetBuildUpgr( 1, UPG_HAMMERS ) endif endfunction this is were ai scripting starts making sense because you'll notice aviary is used in this part and other variables that you have learned up to this point are being used. If you change the variables values then it will have to do something else before it can upgrade.
First part of part 5 tells us
if barracks then upgrade defend. At a first glance this would be very confusing but sense you know thats a variable it has to be followed before it can be done so lets go back to where the variable barracks is set. set barracks = GetUnitCountDone(BARRACKS)>0
this is in part 4
Now as you can see this is starting to make alot more sense. If you dont know what some of the variables are then just go back and find out.
Set barracks variable means that the computer has to have more than one unit built from the barracks. So it has to do that before it can upgrade defend and you can specify what unit it has to build before it can upgrade defend.
Now your prolly saying hmm... This is all coming together now lol...
Scroll down youll see different variables. You can probably figure the rest out on this part of ai scripting only because i covered the other parts about variables in Part 4 Init_Boolean. In that part it states what some variables are and how they can be met before continuing with the next steps of ai.
Part 6 Basic Range:
================================================== ========================== basic_range ================================================== ========================== function basic_ranged takes integer food returns nothing local integer C_rifle = GetUnitCount(COPTER) local integer rifle local integer gyro local integer gryphon set rifle = (food - 2*C_gyro - 4*C_gryphon) / 3
set gyro = (food - 3*C_rifle - 4*C_gryphon) / 2 set gryphon = (food - 3*C_rifle - 2*C_gyro ) / 4 if rifle > max_rifle then
set rifle = max_rifle endif if gyro > max_gyro then set gyro = max_gyro endif if gryphon > max_gryphon then set gryphon = max_gryphon endif if rifle <= max_rifle then
call SetBuildUnit( rifle, RIFLEMAN ) endif if gyro <= max_gyro then call SetBuildUnit( gyro, COPTER ) endif if gryphon <= max_gryphon then call SetBuildUnit( gryphon, GRYPHON ) endif endfunction First of all this tells us some more local integers.
It sets that Rilfe = Minus 2 food per Rifleman which makes sense.
Then it says *C_gyro - 4*C_gryphon) / 3 that doesnt make much sense to me lol.... That part you'll have to figure out on your own. Ill post a reply if i find out from exparamenting what it means. After you read that read down it simply tells you that if the max_rilfe and or the other stuff is met it wont build more if it isnt the ai will build more of the corrasponding unit.
Part 7 Forces Sequence:
================================================== ========================== forces_sequence ================================================== ========================== function forces_sequence takes nothing returns nothing local integer farms = GetUnitCountDone(HOUSE) + 2*TownCountDone(TOWN_HALL) *** MELEE FORCES ***
if farms < 9 then return endif if knights then call SetBuildUnit( (8 - GetUnitCount(FOOTMAN)) / 2, KNIGHT ) endif *** SIEGE FORCES ***
if farms < 10 then return endif if workshop then call SetBuildUnit( 2, MORTAR ) endif *** CASTER FORCES ***
if farms < 11 then return endif if sanctum then call SetBuildUnit( 3, PRIEST ) endif if farms < 12 then return endif if sanctum then if GetUpgradeLevel(UPG_SORCERY)>=2 then call SetBuildUnit( 2, SORCERESS ) else call SetBuildUnit( 1, SORCERESS ) endif endif endfunction MELEE FORCES
First thing we should look at is the Knights Variable which means
barracks and mill and smith and castle in the init_booleans If this condition is met it will build ( (8 - GetUnitCount(FOOTMAN)) / 2, KNIGHT )
Before it can build that the farms count has to be greater than 9.
SIEGE FORCES
Farms are less than 10 then it skips the next actions.
if the computer has a work shop then it can build 2 motor teams.
You can figure the rest of part 7 from here. Part 8 Basic Melee:
================================================== ========================== basic_melee ================================================== ========================== function basic_melee takes integer food returns nothing call FoodPool( food, true,FOOTMAN,2, knights,KNIGHT,4 ) endfunction First thing is that i bet you dont know what FoodPool is so here is the variable meaning. If you cant find out what some variables mean then check in the common.ai file it has all the functions and names there as far as i know. Im not going to discus Common.Ai in this tutorial becuase there is to much to teach in it. Maybe later if someone asks.
// ==================================================FoodPool
================================================== ========================== function FoodPool takes integer food, boolean weak, integer id1, integer use1, boolean strong, integer id2, integer use2 returns nothing if strong then call SetBuildUnit( (food - use1 * TownCount(id1)) / use2, id2 ) elseif weak then call SetBuildUnit( (food - use2 * TownCount(id2)) / use1, id1 ) endif endfunction The Best way to describe basic melee is that it is a just a big variable that is used to continue certain parts of the ai script. Basically dont worry about this.
Part 9 Build Sequence:
================================================== ========================== build_sequence ================================================== ========================== function build_sequence takes nothing returns nothing local integer mines = GetMinesOwned() call InitBuildArray()
call init_booleans() call MeleeTownHall( 0, TOWN_HALL )
call MeleeTownHall( 1, TOWN_HALL ) call SetBuildUnit( 1, TOWN_HALL )
call SetBuildUnit( 6, PEASANT ) call BuildFactory( BARRACKS ) call SetBuildUnit( 8, PEASANT ) call SetBuildUnit( 1, HOUSE ) call SetBuildUnit(10, PEASANT ) call basic_melee( 2 )
call SetBuildUnit( 1, HUMAN_ALTAR ) call SetBuildUnit(11, PEASANT ) call SetBuildUnit( 2, HOUSE ) call basic_melee( 6 )
call SetBuildUnit( 1, hero_id ) call SetBuildUnit( 3, HOUSE ) call basic_melee( 10 ) if startup then
if GetUnitCountDone(FOOTMAN)<5 then return endif set startup = false endif call SetBuildUpgr( 1, UPG_DEFEND )
call SetBuildUnit( 1, BLACKSMITH ) call SetBuildUnit( 1, LUMBER_MILL ) call SetBuildUnit( 4, HOUSE ) call basic_melee( 12 )
call basic_ranged( 3 ) call SetBuildUpgr( 1, UPG_ARMOR ) call SetBuildUnit( 5, HOUSE ) call basic_ranged( 6 )
call SetBuildUnit( 1, KEEP ) call basic_ranged( 9 )
call SetBuildUpgr( 1, UPG_MELEE ) call basic_ranged( 12 )
call UpgradeAll( WATCH_TOWER, GUARD_TOWER ) call SetBuildUnit( 2, WATCH_TOWER )
call SetBuildUpgr( 1, UPG_RANGED ) call BasicExpansion( mines < 2, TOWN_HALL )
call SetBuildUnit( 7, HOUSE )
call SetBuildUnit( 13, PEASANT ) call SetBuildUnit( 8, HOUSE ) call GuardSecondary( 1, 2, WATCH_TOWER )
call GuardSecondary( 2, 2, WATCH_TOWER ) call SetBuildUpgr( 1, UPG_LEATHER )
call SetBuildUpgr( 1, UPG_WOOD ) call SetBuildUnit( 1, hero_id2 ) if mines > 1 then
call SetBuildUnit( 16, PEASANT ) endif call forces_sequence()
call upgrade_sequence() call BuildFactory( WORKSHOP )
if GetUnitCount(MORTAR)<1 then
return endif call BuildFactory( SANCTUM )
call SetBuildUnit( 1, CASTLE )
call SetBuildUnit(10, HOUSE ) call SetBuildUnit( 1, AVIARY ) if GetUnitCount(AVIARY)>0 and GetUnitCount(ZEPPELIN)<3 then
call GetZeppelin() endif call MeleeTownHall( 2, TOWN_HALL )
call BasicExpansion( mines < 3, TOWN_HALL )
endfunction This is my favorite part of ai scripting :P
The First thing we look at is the mines which are the gold mines owned.
Then it calls InitBuildArray which i havnt covered cus it is in Common.Ai.
// ==================================================function InitBuildArray takes nothing returns nothing
set build_length = 0 endfunction thats what InitBuildArray is.
After that it calls init_booleans()
call MeleeTownHall( 0, TOWN_HALL )
call MeleeTownHall( 1, TOWN_HALL ) This states weather to build another town hall or not i think.
Then you'll start reading the interesting stuff like what build order the computer has. First it builds a town hall then 6 peasants and so on. You can edit this and add more lines if you know what your doing.
Startup is another variable. Dont worry about that part it doesnt mean much. Then you can determine what kind of defense the computer will build and in what order.
If the computer has 2 mines it will build 16 peasants as shown when you scrolly down to the part that says
if mines > 1 then
call SetBuildUnit( 16, PEASANT ) endif Avairy is used in this section of ai scripting as you can see. Scroll up for referencing.
Part 10 peon_assignment:
================================================== ========================== peon_assignment ================================================== ========================== function peon_assignment takes nothing returns nothing local integer halls = TownCountDone(TOWN_HALL) local integer T loop call ClearHarvestAI() set T = TownWithMine()
call HarvestGold(T,5)
call HarvestWood(0,2) if TownCountDone(TOWN_HALL)>1 then
call HarvestGold(T+1,4) endif call HarvestWood(0,15)
call build_sequence()
call Sleep(3) endloop endfunction On this part you may have to look in the common.ai for a quick reference on what some of these variables mean.
ClearHarvestAi Dont worry about that to confusing to explain hehe. towns with mines get 5 peons to a mine and 2 to wood hmm. Im not sure about that part. You can figure the rest out from here in other parts of the tutorial look back for reference.
Part 11 Main:
================================================== ==========================
main ================================================== ==========================
function main takes nothing returns nothing set do_debug_cheats = GetAiPlayer()==1 call PickMeleeHero(RACE_HUMAN) call set_skills() call StandardAI(function SkillArrays, function peon_assignment, function attack_sequence) call PlayGame() endfunction |
![]() |
#3
+0/−0
Профиль |
Приват |
Поиск |
Цитата |
IP: Записан
|
![]()
FellGuard
Losyash
![]() ![]() offline
Опыт:
39,547Активность: |
Убири эту кучу текста, я уже скопировал :) Анализ делать не буду, но перевод выложу завтра. |
![]() |
#4
+0/−0
Профиль |
Приват |
Поиск |
Цитата |
IP: Записан
|
![]()
TheBestOrc
![]() offline
Опыт:
350Активность: |
thank you friend ! |
![]() |
#5
+0/−0
Профиль |
Приват |
Поиск |
Цитата |
IP: Записан
|
![]()
FellGuard
Losyash
![]() ![]() offline
Опыт:
39,547Активность: |
Кст, есть пример аи для карты для кампании. Можешь посамообучаться немного ;) |
![]() |
#6
+0/−0
Профиль |
Приват |
Поиск |
Цитата |
IP: Записан
|
![]()
TheBestOrc
![]() offline
Опыт:
350Активность: |
Анализ сделать знатоков , pls
TheBestOrc добавил: thank you friend для файла rar scr01_green.rar |
![]() |
#7
+0/−0
Профиль |
Приват |
Поиск |
Цитата |
IP: Записан
|
![]()
FellGuard
Losyash
![]() ![]() offline
Опыт:
39,547Активность: |
Пришел сюда чтобы сказать, что задержу на часик - другой... Жуткий текст :) |
![]() |
#8
+0/−0
Профиль |
Приват |
Поиск |
Цитата |
IP: Записан
|
![]()
TheBestOrc
![]() offline
Опыт:
350Активность: |
FellGuard я жду с перевод |
![]() |
#9
+0/−0
Профиль |
Приват |
Поиск |
Цитата |
IP: Записан
|
![]()
FellGuard
Losyash
![]() ![]() offline
Опыт:
39,547Активность: |
Я же тебе написал в приват, что не успеваю седня :(
Давай завтра я выложу, я перевел где-то 65% FellGuard добавил: Приватное сообщение сверху на главной странице форума Сорри, что так выходит, завтра должно все быть дописано. |
![]() |
#10
+0/−0
Профиль |
Приват |
Поиск |
Цитата |
IP: Записан
|
![]()
TheBestOrc
![]() offline
Опыт:
350Активность: |
FellGuard можно задать тебе несколько вопросов для АИ на джассе с приватное сообщение ? |
![]() |
#11
+0/−0
Профиль |
Приват |
Поиск |
Цитата |
IP: Записан
|
![]()
FellGuard
Losyash
![]() ![]() offline
Опыт:
39,547Активность: |
http://xgm.guru/forum/showthread.php?t=8759
Перевод статьи. По поводу ИИ в целом можешь задать вопросы в отдельной теме, имхо это полезней. |
![]() |
#12
+0/−0
Профиль |
Приват |
Поиск |
Цитата |
IP: Записан
|
![]()
TheBestOrc
![]() offline
Опыт:
350Активность: |
FellGuard привет , спосибо для статьи . где можно задать тебе несколько вопросов для АИ ? |
![]() |
#13
+0/−0
Профиль |
Приват |
Поиск |
Цитата |
IP: Записан
|
![]()
FellGuard
Losyash
![]() ![]() offline
Опыт:
39,547Активность: |
В приват. |
![]() |
#14
+0/−0
Профиль |
Приват |
Поиск |
Цитата |
IP: Записан
|
![]()
TheBestOrc
![]() offline
Опыт:
350Активность: |
call SetAssaultGroup( 1, 9, hero_id )
call SetAssaultGroup( 0, 9, hero_id2 ) call SetAssaultGroup( 0, 9, GRUNT ) call SetAssaultGroup( 0, 9, RAIDER ) call SetAssaultGroup( 0, 9, TAUREN ) call SetAssaultGroup( 0, 9, HEAD_HUNTER ) call SetAssaultGroup( 0, 9, WYVERN ) call SetAssaultGroup( 0, 9, WITCH_DOCTOR ) call SetAssaultGroup( 0, 9, SHAMAN ) call SetAssaultGroup( 0, 9, KODO_BEAST ) 1, 9, 0, 9, что значить ето ? |
![]() |
#15
+0/−0
Профиль |
Приват |
Поиск |
Цитата |
IP: Записан
|
![]()
TheBestOrc
![]() offline
Опыт:
350Активность: |
pls , жду ответ |
![]() |
#16
+0/−0
Профиль |
Приват |
Поиск |
Цитата |
IP: Записан
|
![]()
DioD
![]() ![]() offline
Опыт:
45,134Активность: |
Код:
в комон аи всё есть |
![]() |
#17
+0/−0
Профиль |
Приват |
Поиск |
Цитата |
IP: Записан
|