RU

Помощь в создании "Асатамы III"

mkir #1281 16.01.2020 14:00 59 comments 15498 views

Спустя годы я все-таки вновь возвращаюсь к мысли создать еще более глобальную и интересную игру в этой серии, несмотря на то, что, возможно, это практически никому не интересно (а вдруг станет интересно?). (и вообще я так понимаю в целом в “сообществе любителей текстовых игр” тишина, или это поверхностное впечатление?)

Новую часть делаю медленно, но кропотливо и аккуратно, не совершая прошлых ошибок. Это касается и общих моментов касательно геймплея, и более удобного кода - чтобы не рябило в глазах и все было понятно, если придется к нему возвращаться спустя какое-то время. Упрощая то, что можно упростить, оптимизируя то, что можно оптимизировать и улучшая то, что требует доработки, как-то так.

Но уже появляются вопросы, с которыми нет сил биться совсем в одиночку. В частности, это касается моих гуманитарных мозгов. Код я осваивал самостоятельно и с чем сумел разобраться, то и использовал в первых двух частях. А с чем не сумел - так и осталось темным пятном.

Поэтому создаю эту тему не только по тому вопросу, который волнует сейчас, но и впрок, если появятся новые.

1. Первый вопрос касается моего главного пробела в языке qsp, из-за которого для обеих частей я придумал собственный большой костыль, который сейчас уже кажется слишком неудобным. Это массивы. Я много раз пытался их освоить и уже не пытаюсь. Поэтому прошу просто подсказать, что и как писать, чтобы реализовать конкретную идею.

ЧТО ИМЕЕМ

1. Есть переменная $mon=‘’ - это имя монстра.
Когда игрок нападает на монстра, мы присваиваем ему имя, а затем переходим в служебную одноименную локацию gs ‘mon’
В ней содержатся все данные о любом монстре, выглядят это так:

if $mon = 'Крыса':
hp = 10
st = 10
... и так далее
end

Причем данных, особенно если монстр непростой бывает очень много, до 30+ строчек получается.

2 Когда игрок находится в свободном плавании, он рискует столкнуться со случайным монстром. Это зависит от типа локации “Лес”, “Поле”, “Горы” и т.д., и сложности конкретного отрезка местности - “1, 2, 3…”. Т.е. если игрок в лесу и сложность 1, он будет встречать всяких зайчиков и оленей и в худшем случае какого-нибудь волка повстречает. Если он в горах и сложность максимальная, то встретит какого-нибудь убер-страшного горного великана. А некоторые монстры могут встречаться сразу в нескольких типах местностях - разбойник, например. Также некоторые монстры могут встречаться на нескольких уровнях сложности. Т.е. мы не обязательно столкнемся с тем горным великаном, вполне, что за поворотом затесался горный козлик, мирно жующий травку. +какие монстры при одинаковых условиях встречаются реже или чаще остальных.

Сам код в этом месте определения монстра получился у меня жутко неудобным. Я просто на отдельной локации “checkmon” настраивал множество условий и вероятностей, типа:

if местность = лес:
	if сложность = 1:
	х=rand(1,12)
		if x < 2:
		$mon='Заяц'
		end
		if x > 1 and x < 5:
		$mon='Разбойник'
			if rand(1,100) > 80:
			$mon = 'Матерый разбойник'
			end
		end
		if x > 4:
		$mon = 'Волк'
		end
		if x = 12:
		$mon = 'Медведь'
		end
	end
	if сложность = 2:
	!то же самое, но если хотим чтобы какой-нибудь заяц встречался и здесь, то также вручную добавляем и его:)
	end
end

Итого, при том что монстров очень много и условий то же, все это со временем превратилось в кашу.

ЧТО ХОЧЕТСЯ РЕАЛИЗОВАТЬ

Я представляю себе это так: есть некий пакет с именами монстров и с их “полевыми характеристиками”, типа каким местностям они свойственны, какая у них максимальная и минимальная планка сложности и какой уровень редкости.

Когда игрок должен столкнуться со случайным монстром он одной командой просто получает из этого пакета своего монстра, - т.е. оттуда сразу же исключается те, кому местность, в которой находится игрок не по душе, те, кому нынешняя сложность не подходит и из оставшихся рэндомно кто-нибудь вытягивается, но у кого-то в силу редкости шанс на вытягивание ниже или выше.

Вот как такой пакет “написать” без полного погружения меня в мир массивов :)
И какая должна быть команда в момент столкновения игрока с монстром и может ли она уместиться в одну строчку?

И два прохладных вопроса:
1. Как и в предыдущей части, здесь будет много различных персонажей со своими “портретами”. Если есть стать таким персонажем, присылайте свои фотографии мне на почту - mkirdan@mail.ru
Хотя пока не прописан весь сюжет и непонятно, сколько таких персонажей понадобится (точно 30+) и какие будут “роли” и типажи.
2. Есть ли желающие помочь автору нарисовать красивую карту мира?
Задача не в том, чтобы ее придумать, она есть, но нарисована плохо.

mkir,
Инициализируй заранее:

Spoiler
$name[0]='Волк'
!Тут прописываем локации для моба.
$loc_area_a[0]='loc1'
$loc_area_b[0]='loc2'
$loc_area_c[0]='loc3'
!Эта переменная будет отвечать за вероятность встречи этого моба.
population[0]=30
!Тут прописываем уровни сложности локации, на которой можно встретить моба.
lvl_a[0]=1
lvl_b[0]=2
lvl_c[0]=3

$name[1]='Заяц'
$loc_area_a[1]='loc1'
$loc_area_b[1]='loc2'
population[1]=80
lvl_a[1]=1
$name[2]='Медведь'
$loc_area_a[2]='loc2'
$loc_area_b[2]='loc3'
population[2]=10
lvl_a[2]=3

На локации loc1:

Spoiler
!Этот код пишем на всех локациях, где будут встречаться мобы.
!В этой переменной храним имя локации.
$loc=curloc
!В этой - уровень.
loc_lvl=1
!Идем подбирать моба.
gs'gen'
!Это проверочная запись, показывает какой моб получился.
'Вы видите <<$mon>>'

gen:

Spoiler
!На этой локации происходит индексация массива $name
i=0
a=0

:marc
!Проверяем соответствие локации.
if $loc_area_a[i]=$loc or $loc_area_b[i]=$loc or $loc_area_c[i]=$loc:
         !Проверяем соответствие уровню. Тут есть момент, первым надо выставить проверку условия наименьшего количества, т.е. если локаций меньше, чем уровней сложности, то ничего не меняем, если больше, то сначала производим проверку уровня. Оно будет работать в любом случае, но так мы сэкономим время вычисления.
	 if lvl_a[i]=loc_lvl or lvl_b[i]=loc_lvl or lvl_C[i]=loc_lvl:
         !Если проверки пройдены, создаем временный массив со значением, соответствующим индексу массива $name
	 temp[a]=i
         !Создаем временный массив, для определения вероятности встречи.
	 temp_population[a]=population[i]
	 a+=1
	 end
end
i+=1
if i<arrsize('$name')-1:jump 'marc'

!Определяем вероятность.
b=rand(0,max'temp_population')

!В этом блоке мы рандомно шерстим временно созданный массив на соответствие вероятности.
:marc1
c=rand(0,arrsize('temp')-1)
if population[c]>=b:
$mon=$name[c]
else
jump 'marc1'
end
!Уничтожаем временные массивы
killvar 'temp'
killvar 'temp_population'

Вероятность мне не очень нравится, но вроде работает.

Спасибо! Попробую разобраться, но тоже вечером, а то и утром скорее. Так что и комментарии все равно лишними не будут)

Тут критика Асатамы 2.

Spoiler

А зачем у тебя в Асатаме 2 в бою стоит задержка 650?, чтобы успевать читать логи? Бои и так затянутые. Сделай настройку для желающих отключить задержку.
Слишком много пропусков строк в тексте, особенно в описании противника, запаришься скроллить. В окне предметов тоже пропуски. Все это лишние движения и потеря времени.

Да, согласен, этот момент тоже собирался оптимизировать

Изучил код - до половины понятно, дальше не очень.
Попробовал вставить точно по рекомендациям, добавив свои 5 названий локаций и 4 уровня сложности, но что-то не работает.
Волк появляется слишком часто на любых типах локаций и сложности, хотя для него прописаны только 3 локации и 3 сложности (как и для всех, теста ради), редко бывает заяц, медведь никогда.
Иногда выскакивает вместо имени монстра пустое место. Иногда плеер виснет и вылетает.
Буду пытаться!

mkir,
Как я и говорил - вероятность не очень.
Придется прописать ее для каждой локации отдельно и вставить этот код после инициализации локации, но перед инициализацией моба.

if $loc='loc1' and loc_lvl=1:population[0]=30

Объясняю:
возьмем локацию лес первого уровня сложности, заселяем мобов в порядке возрастания редкости: медведь-5%, разбойник-10%, волк 25%, заяц-все остальное.
Применяя наш код получаем два этапа рандома, т.е., для медведя на втором этапе вероятность выпадения составит 25% (1 из 4-х), соответственно 5х4=20, population=20. Для разбойника вероятность на втором этапе уже будет 1 из 3-х, т.е. 10х3=30, для волка 25х2=50. Оставшемуся зверю всегда будет 100, т.к. от 100% удобнее считать.
Итак, получаем:
медведь=20
разбойник=30
волк=50
заяц=100.
Теперь, если ты хочешь, чтоб на второй локации вероятность встретить зайца была 10%, а волка 50% - это не удастся реализовать, т.к. у зайца всегда будет вероятность выше. Допустим, мы смирились, что зайцев на любой локации будет больше, идем дальше.
Если ты захочешь, чтоб в рандоме участвовали новые мобы, придется балансировать между уже инициализированных процентов, т.е. если в локации горы будет полно медведей и 10% нужно для некоего огра, придется делать пропорцию где 20 медведевских в лесу это 100 в горах, соответственно, 10 для огра - это 2, а 2 из 2-х - это 4. Это офигенный гемор, ящитаю.
Потому, необходимо прописать популяцию для каждой локации отдельно.
Но даже при этом подходе необходимо быть внимательным, к примеру, не получится сделать шаг в 1%. Если мы захотим вероятность для разбойника сделать 6%, то 6х3=18, что меньше, чем у медведя, весь расчет сломается и по факту у разбойник будет 18/4=4, а у медведя 20/3=6, за этим надо следить.

mkir:

Иногда плеер виснет и вылетает.

Выложи код, я посмотрю, я тестировал только на 3-х локациях.

Да, момент с вероятностями пока для меня слишком мозговыносящ. Я тогда пока решил его отпустить и сделать хотя бы рандомное вытягивание монстра в соответствии с уровнем сложности и типом местности, а заодно освоить более понятную часть кода. Но тоже проблема, и я хотя бы понимаю в чем.

В общем сделал 6 монстров, вот такой список:

Spoiler
$mname[0]='Волк'
$terra_area_a[0]='Леса'
$terra_area_b[0]='Болота'
$terra_area_c[0]='Холмы'
lvl_a[0]=1
lvl_b[0]=2
lvl_c[0]=3

$mname[1]='Заяц'
$terra_area_a[1]='Леса'
$terra_area_b[1]='Холмы'
$terra_area_c[1]='Болота'
lvl_a[1]=1
lvl_b[1]=2

$mname[2]='Медведь'
$terra_area_a[2]='Леса'
$terra_area_b[2]='Пустоши'
$terra_area_c[2]='Горы'
lvl_a[2]=2
lvl_b[2]=3
lvl_c[2]=4

$mname[3]='Ягуар'
$terra_area_a[3]='Холмы'
$terra_area_b[3]='Равнины'
$terra_area_c[3]='Горы'
lvl_a[3]=1
lvl_b[3]=3
lvl_c[3]=4

$mname[4]='Скальный наездник'
$terra_area_a[4]='Пустоши'
$terra_area_b[4]='Горы'
$terra_area_c[4]='Холмы'
lvl_a[4]=1
lvl_b[4]=2
lvl_c[4]=3

$mname[5]='Йетти'
$terra_area_a[5]='Леса'
$terra_area_b[5]='Болота'
$terra_area_c[5]='Равнины'
lvl_a[5]=3
lvl_b[5]=4

$mname[6]='Великан'
$terra_area_a[6]='Болота'
$terra_area_b[6]='Горы'
$terra_area_c[6]='Равнины'
lvl_a[6]=2
lvl_b[6]=3
lvl_c[6]=4

Ключевую локацию видоизменил, удалив все что касается “вероятностей” (добавил pl - чтобы в тесте фиксировать, все ли правильно происходит)

Spoiler
i=0
a=0
:marc
if $terra_area_a[i]=$terra or $terra_area_b[i]=$terra or $terra_area_c[i]=$terra:
	pl '<<$mname[i]>><<i>>Местность та'
     if lvl_a[i]=tdanger or lvl_b[i]=tdanger or lvl_c[i]=tdanger:
     pl '<<$mname[i]>><<i>>Опасность та'
     temp[a]=i
     a+=1
     end
end
i+=1
if i<arrsize('$mname')+1:jump 'marc'
c=rand(0,arrsize('temp'))
$mon=$mname[c]
killvar 'temp'

Соответственно на локации проверки где можно задать любую местность и сложность сразу же видна ошибка, появляется там где быть не должен - на холмах при низкой опасности.
Разбираюсь больше, благодаря PL - понимаю, что на этом этапе все рассчитывается правильно, а ошибка в последнем присвоении.
А именно - arrsize - это видимо максимальное число значений.
следовательно - $mon=$mname[c] - выбирает случайное число среди первых 4 зверей, например, если совпадений по условиям было 4. Либо среди первых двух, если совпадений было 2.
Но не отбирает среди нужных зверей, учитывая их совпадения. В общем, я запутался, и на этом этапе это не могу исправить

upD
Другими словами при данном списке монстров, массив temp будет иметь 4 значения
temp[0]=0
temp[1]=1
temp[2]=3
temp[3]=4
Вот как в соответствии с этими значениями отобрать из массива $mname - только 0, 1, 3 и 4 и уже из них рандомно выбирать.

mkir, надо -1, а не +

if i<arrsize('$mname')+1:jump 'marc'

Уточни про холмы, какая сложность, 1? Кто появляется?
Тут тоже -1 пропустил.

c=rand(0,arrsize('temp'))

arrsize - это размер массива, как ты правильно понял. Но так как индекс массива начинается с 0, то последний индекс массива с четырьмя записями будет 3. На твоем примере это видно).

Вроде бы не - и не +, а просто без единички, или я чего-то не понимаю.

C каждым jumpом i увеличивается на 1.
И после 6-й проверки - i будет равно 6.

В списке монстров 7.
Соответственно условие
if i < arrsize(’$mname’)
не выполняется, а значит 7й монстр не будет проверяться на условия

Там ошибка эта везде. Про медведя на холмах в качестве примера просто. Холмы, уровень сложности 1. Появляются все кроме Йетти и Великана. Но по идее, у медведя, не прописаны ни холмы и ни сложность 1, он должен присоединиться к Йетти и Великану.

апд.

Если поставить пропущенные мной -1, то разнообразие монстров уменьшится на -1, причем с конца. Все тот же медведь, заяц и волк, ягуар. А вот скальный наездник оказался крайним, хотя к условиям подходит.

mkir:

Другими словами при данном списке монстров, массив temp будет иметь 4 значения
temp[0]=0
temp[1]=1
temp[2]=3
temp[3]=4
Вот как в соответствии с этими значениями отобрать из массива $mname - только 0, 1, 3 и 4 и уже из них рандомно выбирать.

Эта строчка рандомно выбирает из временного массива индекс.

c=rand(0,arrsize('temp')-1)

В этой строчке косяк

$mon=$name[c]

с - это индекс массива temp, потому надо попробовать так

$mon=$name[temp[c]]

Если будет выдавать ошибку, то проверни через промежуточную переменную,

d=temp[c]
$mon=$name[d]

Извини, я все переменные использую свои, надеюсь, ты разберешься.

mkir:

Вроде бы не - и не +, а просто без единички, или я чего-то не понимаю.

C каждым jumpом i увеличивается на 1.
И после 6-й проверки - i будет равно 6.

В списке монстров 7.
Соответственно условие
if i < arrsize(’$mname’)
не выполняется, а значит 7й монстр не будет проверяться на условия

Мы быстро пишем посты), я выше уже объяснил, почему индекс меньше размера на 1.

Кстати, у моей системы еще один недостаток.
Возьмем твой код

$mname[0]='Волк'
$terra_area_a[0]='Леса'
$terra_area_b[0]='Болота'
$terra_area_c[0]='Холмы'
lvl_a[0]=1
lvl_b[0]=2
lvl_c[0]=3

Если ты захочешь, чтоб волки появлялись только на 3-м уровне сложности холмов, то ничего не выйдет, они будут на всех уровнях. Это можно решить с помощь вероятности, если будешь ее использовать, а если нет, придется писать условия для комбинаций локация/сложность.
Короче, предстоит тебе огромная работа.

$mon=$name[temp[c]]
Я поставил эту строчку - и все заработало, так, как нужно! с одним исключением. Великан (крайний последний монстр) не появлялся даже если условия были подходящие. Убрал все-таи эту единичку -1 - и стал появляться.
Вот сейчас точно все работает! Это было круто. Но к вероятностям как-нибудь потом вернусь). Огромное спасибо за поддержку!

А со сложностями ничего подобного. Какие указаны, такие и есть.

Log in or Register to post comments.