RU 📌 Pinned

Как сделать?

Dark[Ol(U23)leneri] #34 18.04.2010 22:57 6408 comments 2426712 views

Aleks Versus Moderator 15.07.2016 08:21 (9 years ago)

kolvados,
cleep,
схема календаря не важна, если игровое время считается в минутах. Оба кода (JDN и :loop) по факту пересчитывают все прочие значения исходя из прибавленного количества минут. Только последний код не использует переменную time для хранения игрового времени, прошедшего с начала игры, а сразу делает перерасчёт по всем значениям: часы, дни, недели. Оба этих кода будем называть календарями.

Чтобы календарь создавал в игре правильное текущее время, необходимо выполнять его код всякий раз, когда время изменяется. Для первого календаря (JDN) необходимо изменять переменную time. Например:

act 'Идти в гости к бабушке':
     ! дорога до бабушки 2 часа
     time = time + 2*60
     ! здесь ставим код календаря
end

Поскольку это очень громоздко (каждый раз при изменении времени воротить такой огромный код), календарь оформляют в отдельную локацию и вызывают через GOSUB (например календарь мы поместили на локации ‘Календарь’):

act 'Идти в гости к бабушке':
     ! дорога до бабушки 2 часа
     time = time + 2*60
     ! вызываем календарь:
     GOSUB 'Календарь'
end

Для второго случая, где используются циклы (через метки :loop), то же самое можно записать так:

act 'Идти в гости к бабушке':
     ! дорога до бабушки 2 часа
     minute = minute + 2*60
     ! вызываем календарь:
     GOSUB 'Календарь'
end

или так

act 'Идти в гости к бабушке':
     ! дорога до бабушки 2 часа
     hour = hour + 2
     ! вызываем календарь:
     GOSUB 'Календарь'
end

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

Голод должен изменяться периодически, т.е. через равные промежутки времени его значение увеличивается (герой становится голоднее). Например, каждые двадцать минут на единицу. Но, время, которое герой тратит на действия не всегда кратно двадцати минутам, и это надо учитывать, “запоминая” остаток времени для пересчёта голода.

Возьмём для примера два действия “Покрасить забор” (4 часа 43 минуты) и “Постоять потупить, глядя на часы, ровно 7 минут” (7 минут), и рассмотрим их в контексте календаря JDN.
За четыре часа сорок три минуты герой успеет проголодаться на 14 единиц , но при этом останутся три неучтённые минуты.
За 7 минут герой успеет проголодаться на 0 единиц  и останется 7 неучтённых минут.

Исходя из этих двух случаев несложно составить маленький код, вычисляющий значение голода для двух конкретных действий:

act 'Покрасить забор':
     ! красим забор за 4 часа и 43 минуты
     time = time + 4*60 + 43
     ! вызываем календарь:
     GOSUB 'Календарь'
     ! считаем голод
     голод = голод + (4*60 + 43 + голод_остаток)/20
     ! запоминаем остаток минут, чтобы добавить в другой раз
     голод_остаток = (4*60 + 43 + голод_остаток) MOD 20
end
act 'Постоять потупить, глядя на часы, ровно 7 минут':
     ! стоим тупим семь минут
     time = time + 7
     ! вызываем календарь:
     GOSUB 'Календарь'
     ! считаем голод
     голод = голод + (7 + голод_остаток)/20
     ! запоминаем остаток минут, чтобы добавить в другой раз
     голод_остаток = (7 + голод_остаток) MOD 20
end

Как мы видим, из действия в действие код повторяется, а значит его можно вынести в отдельную локацию, а потом просто обращаться к ней по GOSUB, чтоб не писать один и тот же код всякий раз. Но, в разных действиях у нас разные значения. В “покрасить забор” – одно, в “постоять потупить” – другое. Как быть?
Всё очень просто. Дело в том, что локация может получать несколько значений и хранить их ровно то время, пока выполняется её код. Для передачи значения, нужно указать его через запятую после названия локации, например:

GOSUB 'улётная_лока',455

Чтобы использовать это значение на локации, берём специальные переменные args[], значения которых работают только на этой конкретной локации. На всех других локациях значения переменных args[] будут другими. Применим это знание к нашему коду. Создаём локацию “изменение_времени”:

!#изменение_времени
     ! вызывать например так GOSUB 'изменение_времени',7
     args[0]=args[0] & ! значение этой переменной для примера равно 7. См. строку выше
     ! изменяем время
     time = time + args[0]
     ! вызываем календарь:
     GOSUB 'Календарь'
     ! считаем голод
     голод = голод + (args[0] + голод_остаток)/20
     ! запоминаем остаток минут, чтобы добавить в другой раз
     голод_остаток = (args[0] + голод_остаток) MOD 20
end

Теперь переписываем действия “покрасить забор” и “постоять” согласно нашей новой локации:

act 'Покрасить забор':
     ! красим забор за 4 часа и 43 минуты
     GOSUB 'изменение_времени',(4*60 + 43)
end
act 'Постоять потупить, глядя на часы, ровно 7 минут':
     ! стоим тупим семь минут
     GOSUB 'изменение_времени',7
end

Всё чертовски упростилось, не правда ли?

P.S.: Для календаря с loop вместо time нужно использовать minute. Числовые значения будут те же.

Edited at 15.07.2016 08:29 (9 years ago)

Aleks Versus,Благодарю за столь подробное разъяснение сия вопроса.
Но тем не менее вопрос встречный: (несколько раз перечитал сообщение) но так и не понял откуда берется голод_остаток в смысле как вычисляется?

Aleks Versus Moderator 15.07.2016 10:18 (9 years ago)

kolvados,
это остаток от деления времени, которое потрачено на действие, на время, которое требуется, чтобы голод увеличился на единицу.

В примере голод возрастает на 1 каждые двадцать минут. Поэтому, если на действие тратится 4 часа 43 минуты (283 минуты), то за это время голод возрастёт на 14 единиц и ещё 3 минуты останутся неучтёнными. Их записываем в голод_остаток. При следующем действии в вычислении нам необходимо приплюсовать этот остаток к потраченному на действие время, чтобы учесть. Поэтомуголод_остатокя сразу вставил в формулу.

Возможно это не слишком удачное название переменной. Но называть её неучтённое_время_на_голод слишком громоздко.

Остаток от деления вычисляется оператором MOD

283 MOD 20 = 3
7 MOD 20 = 7
20 MOD 20 = 0

в QSP эквивалентно:
283 - (283/20)*20

Aleks Versus, Вопрос в другом. Т.к. в коде никак не прописывается то, что остаток от деления присваивается этой переменной, мне не понятно это делает сама программа или я сам в ручную должен это сделать?

Aleks Versus Moderator 15.07.2016 10:50 (9 years ago)

kolvados,
как это не прописывается?

Aleks Versus:

голод_остаток = (7 + голод_остаток) MOD 20

Действия игроком могут выполняться в произвольном порядке. Если он выберет “покрасить забор” а потом “потупить” произойдёт следующее:
в действии “покрасить забор” будет вычислен голод и остаток времени (голод_остаток) равный 3 минуты.
в действии “потупить” нужно учесть этот остаток. Поэтому он сразу вставлен в формулу и прибавляется к тем семи минутам, что мы тратим на действие “потупить”.

Но если действия будут выполняться игроком в обратном порядке, то сначала будет выполнено действие “потупить” и в остаток запишется 7 минут. Когда игрок выберет “покрасить забор”, нужно прибавить эти семь минут ко времени на действие, поэтому остаток тоже заранее внесён в формулу.

P.S.: Мне казалось, это очевидно, но очевидно не очевидно. )) Надо будет учесть.

Aleks Versus, Спасибо. Видимо я продолжаю тупить вместо того, чтобы красить забор.

Лисий Дух #1781 17.07.2016 21:14 (9 years ago)

cleep:

kolvados, привет, сразу говорю, что не эксперт)

Лучше бы ты заменил код времени на более простой. Например:

!!!Время
!!минуты в часы
:loopminute
if minute>=60:
	 hour+=1
	 gs 'gs_время'
	 minute-=60
	 jump'loopminute'
end
!!часы в сутки
:loophour
if hour>=24:
	 day+=1
	 dayspast+=1
	 weekday+=1
	 hour-=24
	 jump'loophour'
end
!!Цикл дней недели
:loopweek
if weekday>7:
	 weekday-=7
	 jump'loopweek'
end
!!Дни в месяцы
:loopmonth
!это еще и годовая метка, ибо смена года влияет на високосность
!Благодаря этому ифу, мы прервем конвертацию дней в месяцы, если месяцев набралось более чем на год. Сначла месяцы в год, потом возвращаемся снова к дням в месяцы.
if month<13:
	 !Невисокосный февраль
	 if month=2 and day>28 and year mod 4!0:
     month+=1
     day-=28
     jump'loopmonth'
	 end
	 !Високосный февраль
	 if month=2 and day>29 and year mod 4=0:
     month+=1
     day-=29
     jump'loopmonth'
	 end
	 !Январь, март, май, июль, август, октябрь, декабрь
	 if (month=1 or month=3 or month=5 or month=7 or month=8 or month=10 or month=12) and day>31:
     month+=1
     day-=31
     jump'loopmonth'
	 end
	 !Апрель, июнь, сентябрь, ноябрь
	 if (month=4 or month=6 or month=9 or month=11) and day>30:
     month+=1
     day-=30
     jump'loopmonth'
	 end
end
!!месяцы в годы
if month>12:
	 year+=1
	 month-=12
	 jump'loopmonth'
end
!Сопоставление текстового названия дня недели его числовому значению
if weekday=1:$weekday='Понедельник'
if weekday=2:$weekday='Вторник'
if weekday=3:$weekday='Среда'
if weekday=4:$weekday='Четверг'
if weekday=5:$weekday='Пятница'
if weekday=6:$weekday='Суббота'
if weekday=7:$weekday='Воскресенье'
!тоже самое, только для месяцев
if month=1:$month='Января'
if month=2:$month='Февраля'
if month=3:$month='Марта'
if month=4:$month='Апреля'
if month=5:$month='Мая'
if month=6:$month='Июня'
if month=7:$month='Июля'
if month=8:$month='Августа'
if month=9:$month='Сентября'
if month=10:$month='Октября'
if month=11:$month='Ноября'
if month=12:$month='Декабря'
!преобразовывает, например, 9 часов в 09 часов
if hour<10:$nullh='0'
if hour>=10:$nullh=''
!тоже самое, но для минут
if minute<10:$nullm='0'
if minute>=10:$nullm=''

Сам в начале работал с тем, что у тебя, но потом забил)

Что касается убывания, то здесь:

:loopminute
if minute>=60:
	 hour+=1
	   gs 'gs_время'
	 minute-=60
	 jump'loopminute'
end

В gs ‘gs_время’ прописываешь gg[’голод’]-=1 (или как там у тебя голод обозначается) и все должно работать

P.S. Если решишь использовать этот код, то формат вывода:
pl’Время <B><<$nullh>><<hour>></B>:<B><<$nullm>><<minute>></B>’
pl’Сейчас <<day>> <<$month>> <<year>> года, <<$weekday>>.’

Код вывода нужно использовать непосредственно в каждой локации или можно разово закинуть в статистику?

Лисий дух, достаточно закинуть в статистику

Лисий Дух #1781 17.07.2016 21:54 (9 years ago)

cleep:

Лисий дух, достаточно закинуть в статистику

Спасибо.
Получается статистику через gs надо прописывать в каждой локации?
Пробовал через $onnewloc - прописал gs ‘статистика’, но выходит бешеное размножение:

Или там нужно прописывать что-то ещё?

Aleks Versus Moderator 18.07.2016 08:08 (9 years ago)

Лисий Дух,
окно дополнительного описания не очищается при переходе на новую локацию. Чтобы не было “размножения”, поставь перед строками вывода команду clear (clr).

Лисий Дух #1781 18.07.2016 08:23 (9 years ago)

Aleks Versus, спасибо.



Разобрался, неправильно задал переменную

Появился еще один вопрос:
Как реализовать следующее - если игрок оставляет поле ввода пустым - рост устанавливается по умолчанию и его переносит в следующую локацию?
Вот что есть:

$рост = input(’Введите рост Вашего персонажа в сантиметрах (см):’)
if $пол = 1 and $рост <= 169: msg(’Слишком маленький рост’)
if $пол = 1 and $рост >= 211: msg(’Слишком большой рост’)
if $пол = 0 and $рост <= 144: msg(’Слишком маленький рост’)
if $пол = 0 and $рост >= 186: msg(’Слишком большой рост’)
else
if $пол = 1 and $рост >= 170 and $рост <=210: gt ‘Начало’
if $пол = 0 and $рост >= 145 and $рост <=185: gt ‘Начало’
end

Здравствуйте. Недавно начал изучение QSP, появилось несколько трудностей:
1. Как зациклить проигрывание аудио? Желательно с примером. (Знаю что здесь вопрос уже поднимался но разобраться не удалось).
2. Как сделать переход между тремя локациями A B C по схеме: локация А - кнопка перехода на локацию В - на локации В ожидание несколько секунд и автоматический переход на локацию С.

Заранее спасибо.

Aleks Versus Moderator 19.07.2016 06:18 (9 years ago)

Лисий Дух,
твой код неправильный, либо вырван из контекста, отчего неправильно читается.

:вводим_рост
рост = input('Введите рост Вашего персонажа в сантиметрах (см):')
if рост = 0:
! если игрок ничего не ввёл
    if пол = 1: рост=186
    if пол = 0: рост=167
    goto 'Начало'
else
        if пол = 1 and рост <= 169: msg('Слишком маленький рост') & jump 'вводим_рост'
        if пол = 1 and рост >= 211: msg('Слишком большой рост') & jump 'вводим_рост'
        if пол = 0 and рост <= 144: msg('Слишком маленький рост') & jump 'вводим_рост'
        if пол = 0 and рост >= 186: msg('Слишком большой рост') & jump 'вводим_рост'
        if пол = 1 and рост >= 170 and рост <=210: gt 'Начало' 
        if пол = 0 and рост >= 145 and рост <=185: gt 'Начало' 
end

Числовые переменные пишутся без знака $. Различай однострочные и многострочные формы записи, и лучше всегда используй многострочные. Если не знаешь, что такое однострочные и многострочные формы if и act, то в старой справке это объясняется, целый раздел под многострочные отведён. Либо воспользуйся поиском по форуму.

Vlad,
зациклить аудио:

!самая первая локация в игре
$counter = 'counter'
!создаёшь локацию counter и пишешь в ней
if isplay('путь к мелодии/мелодия.mp3')=0:
   play 'путь к мелодии/мелодия.mp3'
end

Того, что ты описал во втором вопросе, лучше не делать. Вернее: так делать плохо. Но делается это так. В локации B в поле выполнить при посещении:

wait 5000 & ! задержка пять секунд
goto 'C'
Лисий Дух #1781 19.07.2016 09:24 (9 years ago)

Aleks Versus, спасибо.

Aleks Versus,спасибо. Но хотелось ещё кое-что уточнить. Почему переход во втором вопросе нежелателен?

Log in or Register to post comments.