gamedev Игры дневники разработчиков Roguelike 

Олдфажного геймдева пост номер 7

По традиции для тех, кто не видел прошлые посты, скопирую короткое вступление.


Итак, что такое Citadel? Одскульная текстовая RPG/roguelike. И, говоря "олдскульная", я имею в виду рили олд. Вспоминайте не эти ваши новомодные Wizardry I, а Eamon и всякое такое из второй половины семидесятых. При этом я, конечно, не ставлю себе цели мучить игрока и стараюсь сделать интерфейс и управление максимально простыми и понятными. Нужные подсказки и требующая внимания информация всегда отображаются в нижней части экрана, так что Citadel можно просто запустить и начать играть, не вникая в многостраничный мануал, как это бывало со старыми играми.


Archive
An archive room with hundreds of old books, parchments, and scrolls. Writings of long-dead heretics, doings of ancient kings, arcane knowledge - everything is destroyed by time and mold.
You see nothing of interest.
You hear nothing but your own footsteps.
You have learned the fire



Время волшебного апдейта, в прямом смысле. Версия 0.15.


В игру пришла магия. Так как эта часть движка была не готова от слова совсем, обновление снова сосредоточено больше на внутренних изменениях и механиках, чем на контенте, но кое-что есть. В комнатах-архивах игрока ждут шесть заклинаний. Я сомневаюсь, что они останутся (по крайней мере, в неизменном виде) в финальной версии, но пока так. Кроме того, полностью переработана механика яда, подправлен баланс, исправлены некоторые баги и для удобства в меню персонажа добавлен экран с действующими эффектами. Подробный список изменений будет в конце поста.


=========ROUND RESULTS===
rotten beast prepares to attack An invisible protective barrier forms around
you.,gamedev,Игры,дневники разработчиков,Roguelike



Несколько мыслей о текущей и будущей версиях. Я расстроен, что опять не успел заняться основным квестом и сюжетным контентом, но допилить недостающие механики, хотя бы в сыром виде, кажется мне важнее. Представленный сейчас в игре набор заклинаний работает не идеально. Вся атакующая магия наносит одинаковый, зависящий от уровня, урон, так как у врагов ещё нет резистов. Нет и эффектов типа заморозки, горения, отравления. Возможно, в следующей версии я займусь ими. Или добавлю позиционирование в схватки, чтобы слабые стрелки и маги прятались за спинами более сильных коллег, а летающих врагов можно было достать только колдовством или стрелковым оружием (которого, кстати, тоже пока нет). Или начну вводить боевые скиллы и продвинутые атаки для персонажа. Или сделаю наконец стелс, которым уже давно следовало заняться. Сейчас, кстати, магия Chameleon, которая должна по идее делать героя менее заметным, не работает в силу отсутствия самой механики скрытности. А ещё моего внимания ждут крафт, ремонт и апгрейд снаряжения, события, иллюзии, трейты, открывающиеся за прокачку параметров... Как видите, есть из чего выбрать. И да, конечно, основной и побочные квесты, лор и украшательство.


ROUND RESULTS
automaton swings its' fist but misses
Lightning bolt strikes automaton
automaton takes 13 points of electric damage
automaton dies,gamedev,Игры,дневники разработчиков,Roguelike


Засим, наверное, попрощаюсь. Эта версия принесла не так много нового, как мне бы хотелось, и дело тут в общем во мне. Интенсивно работал полтора года без отпуска, устал. Повосстанавливаюсь пару недель и навалюсь с новыми силами. Да, чуть не забыл: список изменений и ссылки на bochs и игру. Если есть желание пощупать, за инструкциями обращайтесь в личку или пробегитесь по старым моим постам.


Игра

bochs


v. 0.15

Меxаника.

- меню магии работает.

- пункт magic добавлен в боевой режим.

- готов магический фреймворк.

- уровень заклинаний растёт от использования.

- в архивах можно учить и повышать заклинания.

- новый параметр, energy.

- добавлена подсказка на экран персонажа.

- выход из экрана персонажа теперь по клавише C.

- в меню персонажа добавлен экран эффектов, вызывается клавишей E.

- полностью переработана механика яда.


Контент.

- добавлено заклинание acid spray.

- добавлено заклинание arcane barrier.

- добавлено заклинание chameleon.

- добавлено заклинание fire breath.

- добавлено заклинание ice spears.

- добавлено заклинание lightning bolt.

- добавлен навык arcane.

- новый тип доспехов, leather armor.


Баланс.

- у dog skeleton усилены боевые навыки.


Исправленные баги.

- некоторые существа не отображались на карте. Исправлено.

- комната писца теперь появляется в случайном месте, а не верxней левой клетке.

- для расчёта очередности ходов в бою использовалась сила вместо ловкости.

- неправильный указатель на переменные, хранящие флаги ловушек.


Известные баги.

- Если в комнате есть контейнер и ловушка, ловушка не срабатывает.

- Иногда предметы генерируются с 0 прочности.

- Сообщение о повышении атрибута не очищает строку полностью.

- Персонаж не перестает гореть по окончании боя если загорелся в финальном раунде.

- Горение наносит урон при открывании/закрывании окна персонажа в бою.

- Нет сообщения "You see nothing of interest" если в комнате есть скрытый предмет.

- Некорректная работа отмычек на замкаx с ловушкой.

- Персонаж "видит" интерьер запертых комнат.


Poisoning
6 damage per turn for 2 turns.
No health regeneration.
Arcane Barrier
Absorbs 6 damage up to 26 total for 5
turns.,gamedev,Игры,дневники разработчиков,Roguelike


Развернуть

Игры старые игры игровой автомат обзор 

История видеоигр, часть 15: Western Gun (A.K.A. Gun Fight) (1975)

NEW FR°M MIDWAY
A TWO PLAYER SHOOT OUT
"'O'*AY MFC.
CO.-




•Mâ,Игры,старые игры,игровой автомат,обзор


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


Western Gun - игра для тех, кто хотел бы примерить на себя роль дуэлянта с Дикого Запада. Весь игровой процесс, в принципе, я описал в предыдущем абзаце. Два управляемых игроками ковбоя встречаются на ограниченном экраном пространстве. У каждого - верный револьвер и шесть пуль. Тут и там линию огня прерывают кактусы и деревья. На поздних этапах снизу вверх через весь экран катаются дилижансы. Задача игроков - за отведённое время поразить соперника как можно больше раз. После каждого попадания игроки возвращаются на исходные позиции, а рельеф поля боя усложняется.


пип
пип
1
0
¿9
0,Игры,старые игры,игровой автомат,обзор

Раунд 1. Кактусы и деревья можно разрушать выстрелами.


Томохиро Нишикадо разработал игру для компании Taito в 1975 году. Автоматы продавались в Японии, Европе и Северной Америке (с названием Gun Fight). В отличие от более ранних игр, использовавших простые формы для символического изображения персонажей, в Westren Gun по экрану перемещаются полноценные анимированные спрайты - не буду вдаваться в тонкости реализации, но подобный эффект в играх ранее, насколько мне известно, не использовался.


H
22
3
t
t
t
t
GOT ME
11111
lililí,Игры,старые игры,игровой автомат,обзор

Поздний этап. Кактусовая роща и дилижанс не спасли игрока 2


Оригинал

Развернуть

Фильмы Джокер (фильм) мнение песочница 

Мысли о Джокере

Фильмы,Джокер (фильм),мнение,песочница


С утра под кофеёк почему-то начал думать про фильм "Джокер". И вот до чего додумался: свою волну хайпа фильм получил не вполне заслуженно. Да, фильм хорош. История про маленького человека и его тяжёлую жизнь - это всегда трогает. Феникс великолепен, он один тащит на себе всю картину до такой степени, что я бы назвал "Джокер" фильмом одного актёра.


И всё-таки вот эти льющиеся отовсюду новости про первый фильм по комиксу, получивший приз на серьёзном кинофестивале. Серьёзно? "Хранители" - это фильм по комиксу. Его история намертво завязана на вселенной и персонажах графического романа. А вот если мы перенесём действие "Джокера" из Готэма в какой-нибудь Детройт, назовём героя Паяцем, Фигляром или Клоуном - что-нибудь изменится? Нет. Я не эксперт по комиксам про Бэтмена, но, кажется, никакой драматической предыстории и глубины у персонажа Джокера там не было. По крайней мере, в старых. Отвлёкся, к чему я? К тому, что идея связать белыми нитками драму про то, как забитый жизнью доходяга слетел с катушек, и комиксы про Бэтмена - выглядит как дешёвый пиар-ход, на который все купились. Тред, гоу.

Развернуть

Игры старые игры обзор 

История видеоигр, часть 14: Pong (1973)

Игры,старые игры,обзор


Последняя серия приключений Atari закончилась драматично: Н. Бушнел, тряся воздетыми кулаками, кричал "Шакалы!" в адрес подражателей, заполнивших рынок клонами сверхуспешного Pong. Методом борьбы с недобросовестной конкуренцией было выбрано повышение планки качества и оригинальности собственных продуктов. Затемнение, титры, новый эпизод.


Игры,старые игры,обзор

Финальный вариант корпуса автомата.


Gotcha стала четвёртой игрой молодой компании, и на этот раз разработчики решили, что хороши все средства. Наверху можно увидеть флаер игры, где некий весёлый молодой человек держит за талию девушку. Должно быть, свою подругу? Разберёмся.


Игры,старые игры,обзор


Преследователь, обозначенный квадратом, должен настигнуть Преследуемого (Преследуемую!), представленного как знак плюс. Погоня происходит в меняющемся лабиринте, который, если пофантазировать, вполне может изображать движение равнодушной толпы, спешащей по своим делам и игнорирующей драму, которая происходит прямо на её глазах. Усиливает ощущение загнанности и звуковое сопровождение: ритмичный писк, издаваемый игрой, учащается, когда преследователь приближается к жертве: несомненно, это бешено колотящееся сердце девушки, понимающей, что она не сможет уйти от нежеланного ухажёра. Звучит как бред, достойный РенТВ? А что вы скажете, когда узнаете, что в первом прототипе джойстики были скрыты в розовых резиновых куполах, изображающих женскую грудь? Вскоре после релиза их заменили на обычные. Возможно, это как-то связано с основанием в США Ассоциации Либертарианских Феминисток в 1973 году. Десять симуляторов сталкинга из десяти!


Игры,старые игры,обзор


Ладно, шутки в сторону. Игра выполнена вполне добротно для своего времени, а меняющий конфигурацию лабиринт - неплохая идея. Контакт со стенами заставляет игроков рикошетить, затрудняя передвижение. Единственный существенный недостаток, который я заметил - это то, что игра не всегда фиксирует столкновения при движении по диагонали. Таким образом игроки иногда проходят сквозь стены и даже могут выйти за пределы игрового поля! При этом, что интересно, цифры таймера и счёта игра также считает элементами лабиринта. На скриншоте выше видно, что Преследуемый находится за границами лабиринта, рядом с цифрой ноль.


Игра ведётся определённое время (от 30 секунд до 2 минут), после чего переходит в режим демонстрации. За это время Преследователь должен как можно больше раз поймать свою жертву, зарабатывая очки. Каждый раз после поимки лабиринт на секунду исчезает, а Преследователь перемещается в случайную точку. Немного обидно за Преследуемого, у которого нет своего счёта и который может только снизить число очков, полученных Преследователем.


Развернуть

Игры старые игры обзор 

История видеоигр, часть 13: Pong (1972)

Игры,старые игры,обзор

Прототип игрового автомата Pong.


В 1971 году Нолан Бушнел зарегистрировал компанию Syzygy Engineering для выпуска одной единственной игры, Computer Space. Успех был умеренным, но вдохновил авторов идти этой стезёй дальше. Бушнел и Дабни решили основать контору, продающую "идеи" игр другим компаниям. Новые задачи требовали новых специалистов и новоиспечённая Atari приняла на работу инженера Алана Алкорна. В качестве "разминочного" задания Алкорна попросили спроектировать простую игру с движущейся точкой, двумя "ракетками" и возможностью ведения счёта.


Игры,старые игры,обзор

Алан Алкорн


Поразмыслив, Алан решил, что с описанным боссом функционалом игра будет скучной и добавил несколько фич от себя. Ракетки были разделены на 8 частей, при попадании в которые мяч отскакивал под разными углами: две центральные части отбивали мяч перпендикулярно ракетке, а крайние - под острым углом. Скорость полёта мяча нарастала с каждым ударом и возвращалась к исходному значению, когда один из игроков промахивался.


В августе 1972 прототип был установлен в баре, с хозяевами которого у Бушнела были хорошие отношения. Игра имел успех и несколько недель привлекала всё новых поклонников. Когда хозяин бара обратился к Atari с просьбой проверить происходящие с автоматом сбои, оказалось, что их причиной был переполненный монетоприёмник.


Узнав о случившемся аншлаге, авторы решили не продавать права на игру, а начать самостоятельное производство.


Игры,старые игры,обзор

Pong в режиме демонстрации.


Пройдя все семь кругов ада, компания всё-таки нашла деньги и сотрудников для сборочной линии. Как и прошлое начинание Бушнела, выглядело всё это чудовищной авантюрой, которая выгорела лишь чудом. Автоматы с Понгом продавались как пирожки, и Atari не успевала подсчитывать прибыли. Как водится, всё пошло наперекосяк из-за одного маленького упущения: авторы не запатентовали технологию и вскоре практически затерялись в море клонов. "Шакалы!" - говорил Бушнел о подражателях, хотя его собственный первый игровой проект начинался как калька со Spacewar! Да и Pong, чего скрывать, была доработанной версией настольного тенниса с Magnavox Odyssey.


3
ID
I,Игры,старые игры,обзор

Типичный кадр из игры.


В исторической перспективе этот Pong-бум имел положительный эффект: множество компаний, продававших его копии, позже перешли к разработке уникальных игровых проектов. Таким образом, Бушнел и компания невольно дали толчок аркадной революции. Лучшим методом борьбы с подражателями сам Бушнел считал повышение качества и оригинальности собственного продукта. Так, вскоре появились вариации понга для четверых игроков - в командах по двое и каждый за себя, а затем и домашние консоли, подключавшиеся к телевизору.

Устроив этот исторический обзор, я совсем забыл о главном: что, собственно, представляла из себя Pong? Если вдруг кто-то среди читателей с ним не знаком, кратко опишу: Pong - это имитация настольного тенниса для двух игроков, управляющих "ракетками", которые могут двигаться вверх и вниз, но фиксированы по горизонтали. Задача игроков - отбивать мяч до тех пор, пока противник не пропустит подачу. В оригинальной версии счёт идёт до 11 очков, но в многочисленных инкарнациях игры правила неоднократно менялись.


Игры,старые игры,обзор


Развернуть

Игры старые игры обзор 

История видеоигр, часть 12: Hunt the Wumpus (1972)

Texas Instruments
Home Computer
Г------к
Hunt the
Wumpus
SOFTWARE'” COMMAND MODULE
An exciting simulated hunt in a hidden maze ot caverns and twisting tunnels! Seek out the lair of the Wumpus, while avoiding perils along the wayl
Application? Software ^
Application programs for


     Огромный дурнопахнущий зверь затаился в одной из комнат подземелья. Он тяжёл как слон, а его ноги покрыты присосками. Он ничего не видит, но обладает острым слухом. Он - вумпус (некоторые предлагают звать его вампусом, но мой вариант мне нравится больше). Игрок в роли вооружённого луком героя должен победить чудовище, но вот беда: оказаться с вумпусом в одной комнате - верная смерть. Единственная надежда - на выстрел вслепую из соседней комнаты, благо присутствие вумпуса можно издалека определить по запаху. Такова в общих чертах суть игры Hunt the Wumpus. Конечно же, не всё так просто. Кроме вумпуса в подземелье есть и другие опасности - летучие супермыши (superbats) и бездонные пропасти. Как и вумпуса, их можно определить, находясь в соседней комнате: первых - по хлопанью крыльев, вторые - по сквозняку. Подземелье организовано таким образом, что каждая из 20 его комнат соединяется с тремя другими наподобие вершин додекаэдра. Каждый ход игрок может выстрелить или переместиться в одну из примыкающих комнат. Стрелять следует осмотрительно: во-первых, стрел всего пять, во-вторых - выстрел в соседнюю с вумпусом комнату может разбудить его, после чего он перейдёт в другое помещение. Перемещаться  стоит осторожно. Попадание в комнату с колодцем грозит немедленным проигрышем, а летучие мыши переносят игрока в случайную область подземелья. Вумпусу, кстати, эти напасти не страшны: он слишком тяжёл для мышей и оснащён присосками, чтобы выбираться из провалов.


Оригинальная игра была написана на BASIC и вошла в несколько книг в качестве демонстрационной программы. Благодаря этому Hunt the Wumpus была портирована на множство платформ. Версия Йоба имела текстовый интерфейс, но со временем появились и графические варианты. Так, здесь можно поиграть в браузерную графическую версию.


Hunt the Wumpus
Arrows remaining: 5
About Hunt the Wumpus
You are at 2?3 You hear flapping You feel a breeze
Move (ctrl+arrow)	Shoot (alt+arrow)
The original version of Hunt the Wumpus was created by Gregory Yob in 1972. The original version was quite a 3 others (rather than four). You can


Грегори Йоб позже разработал Wumpus 2 и Wumpus 3 с более сложными пещерами и бОльшим набором опасностей.


Оригинал статьи

Развернуть

программирование geek OSDev Операционная система разработка ассемблер длиннопост песочница 

Урок ОСдева №6: минидрайвер флоппи-привода.

В предыдущем посте мы вычислили значения, нужные для работы с FAT12. Пора писать драйвер!

Начнём с постановки задачи. Что должен уметь драйвер FAT12 для первичного загрузчика?

Очень просто: загружать файлы. Больше ничего.


Для этого мы будем использовать прерывание BIOS. Кстати, про прерывания мы ещё не

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

BIOS. Подробно об этом говорить будем позднее, так как тема очень большая. Кроме того,

позже мы напишем полноценный драйвер, который будет работать с флоппи-приводом напрямую,

без посредства BIOS. Сделать это прямо сейчас мы не можем из-за ограничения по размеру

программы: первичный загрузчик должен занимать не больше 512 байт - полновесный драйвер

флоппи-привода в такой объём не влезет.


Прерывания вызываются командой int, после которой идёт номер. Стандартное

прерывание BIOS для работы с дисками - 13h. Соответственно, команда выглядит так: int 13h.

Как правило прерывания требуют передачи параметров через определённые регистры. Так,

int 13h нужен номер функции в AH. Прерывание 13h - это целый набор функций для работы

с различными видами съёмных и постоянных носителей. Нас интересует функция 2, чтение

секторов с диска. Она в свою очередь требует указать количество считываемых секторов в AL,

номер цилиндра в CH, номер начального сектора в CL, головку в DH, привод в DL и адрес

в памяти, куда будут считаны данные, в ES:BX.


Итак, ещё раз: в нашем случае int 13h вызывается со следующими параметрами:

AH = 2 (номер функции)

AL = число секторов

CH = номер цилиндра

CL = номер начального сектора

DH = номер головки

DL = 0 (номер привода)

ES:BX = сегмент:смещение области для загрузки


Прерывание int 13h у нас будет вызываться в процедуре read_sectors. Этой последней нужно

будет передать три параметра: LBA в AX, число секторов в CX и адрес для загрузки в ES:BX.

Что такое LBA мы уже знаем: это более современная линейная схема адресации секторов. К сожалению,

прерывание 13h работает с устаревшим форматом CHS, так что придётся делать конверсию

внутри процедуры.


Кстати, стоит сразу остановиться на том, как оформляются и что представляют собой процедуры

в TASM. В коде процедура выглядит так:


(имя процедуры) proc

     (тело процедуры)

(имя процедуры) endp


Обе эти инструкции нужны только компилятору и в исполняемый файл не попадают. В случае

"плоского" бинарного файла процедура окажется именно там, где она расположена в тексте

программы - никакой отдельной области памяти для неё создаваться не будет. Процедура

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

нужные параметры в нужные регистры.


Теперь немного о внутреннем устройстве FAT12. Для того, чтобы загрузить файл в память,

нам нужно проделать следующие вещи:


1. Загрузить в память Корневую Директорию диска.

2. Найти в КД запись, соответствующую файлу.

3. Считать из записи номер первого кластера файла в FAT.

4. Загрузить в память FAT.

5. Загрузить в память цепочку кластеров, которую занимает файл.


В этот раз мы ограничимся только первым пунктом, всё остальное будет в финальной статье

про первичный загрузчик. Давайте вспомним, как выглядела программа в конце прошлого поста:


.386p

CSEG segment use16

ASSUME cs:CSEG, ds:CSEG, es:CSEG, fs:CSEG, gs:CSEG, ss:CSEG

begin:                              jmp short execute;Точка входа. Перейти к исполняемой части.

                                       nop;Пустой оператор. Заполняет 3-й байт перед BPB.




;БЛОК ПАРАМЕТРОВ BIOS==========================================================;


     ;=======================================;

     ;Блок параметров BIOS, 33 байта.                                         ;

     ;Здесь хранятся характеристики                                            ;

     ;носителя. Должен быть в 3 байтах                                       ;

     ;от начала загрузочного сектора.                                          ;

     ;=======================================;

     BPB_OEMnamedb 'BOOTDISK';0-7. Имя производителя. Может быть любым.

     BPB_bytespersecdw 512;8-9. Размер сектора в байтаx.

     BPB_secperclustdb 1;10. Количество секторов в кластере.

     BPB_reserveddw 1;11-12. Число зарезервированныx секторов (1, загрузочный).

     BPB_numFATsdb 2;13. Число FAT.

     BPB_RDentriesdw 224;14-15. Число записей Корневой Директории.

     BPB_sectotaldw 2880;16-17. Всего секторов на носителе.

     BPB_mediatypedb 0F0h;18. Тип носителя. 0F0 - 3,5-дюймовая дискета с 18 секторами в дорожке.

     BPB_FATsizedw 9;19-20. Размер FAT в сектораx.

     BPB_secpertrackdw 18;21-22. Число секторов в дорожке.

     BPB_numheadsdw 2;23-24. Число головок (поверxностей).

     BPB_hiddensecdd 0;25-28. Число скрытыx секторов перед загрузочным.

     BPB_sectotal32dd 0;29-32. Число секторов, если иx больше 65535.


     ;===============================================;

     ;Расширенный блок параметров BIOS, 26 байт.                                         ;

     ;Этот раздел используется в DOS 4.0.                                                       ;

     ;===============================================;

     EBPB_drivenumdb 0;0. Номер привода.

     EBPB_NTflagsdb 0;1. Флаги в Windows NT. Бит 0 - флаг необxодимости проверки диска. Бит 1 - флаг необходимости диагностики             поверхности.

     EBPB_extsigndb 29h;2. Признак расшренного BPB по версии DOS 4.0.

     EBPB_volIDdd 0;3-6. "Серийный номер". Любое случайное число или ноль, без разницы.

     EBPB_vollabeldb 'BOOTLOADER ';7-17. Название диска. Устарело.

     EBPB_filesysdb 'FAT12   ';18-25. Имя файловой системы.




;ИСПОЛНЯЕМЫЙ БЛОК===============================================================;


;Шаг 1. Исправить значения сегментных регистров.

execute:

                    ;DS, ES, FS, GS.

                              mov ax,07C0h;Сегмент загрузчика.

                              mov ds,ax;Поместить это значение во все сегментные регистры.

                              mov es,ax

                              mov fs,ax

                              mov gs,ax


                    ;СЕГМЕНТ СТЕКА.

                              cli;Запретить прерывания перед переносом стека.

                              mov ss,ax;Поместить в SS адрес сегмента загрузчика.

                              mov sp,0FFFFh;Указатель стека - на конец сегмента.

                              sti;Разрешить прерывания.


                    ;СЕГМЕНТ КОДА.

                              push ax;Поместить в стек сегмент.

                              mov ax,offset jump;Указатель на инструкцию после retf.

                              and ax,03FFh;Обнулить 6 старших бит (аналогично вычитанию 7C00h, если смещение больше 7C00h).

                              push ax;Поместить в стек смещение.

                              retf;Дальний возврат для смены CS.


jump:                     mov byte ptr EBPB_drivenum,dl;BIOS должен вернуть номер загрузочного устройства в DL. Сохранить его в BPB.


                             mov ax,BPB_RDentries;Число записей КД

                             shl ax,5;*32 (размер записи в байтах) = размер КД в байтах.

                             div BPB_bytespersec;AX/размер сектора в байтах = размер КД в секторах.

                             mov cx,ax;Поместить его в CX (будет счетчиком для загрузки КД).

                             xor ax,ax;Обнулить AX.

                             mov al,byte ptr BPB_numFATs;Число FAT

                             mul BPB_FATsize;*размер FAT в секторах = общий размер всех FAT в секторах.

                             mov total_FATs_size,ax;Сохранить результат в переменной.

                             add ax,BPB_reserved;AX+число зарезервированных секторов = стартовый сектор КД.

                             mov datasector,ax;Стартовый сектор КД + размер КД в секторах =

                             add datasector,cx;= стартовый сектор области данных. Сохранить его в переменной.


                             cli

                             hlt


;ПЕРЕМЕННЫЕ==================================================================;

     total_FATs_size dw ?;Переменная для хранения общего размера FAT в секторах.

     datasector dw ?;Переменная для хранения номера стартового сектора области данных.


     org 1FEh;Заполняет память нулями до 511-го байта.

     dw 0AA55h;Байты 511 и 512. Признак загрузочного сектора.


CSEG ends

end begin


Добавим следующий код между add datasector,cx и cli:


                              mov bx,0200h

                              call read_sectors


Теперь загрузчик перед тем, как остановить процессор, вызывает процедуру read_sectors. Но передали ли

мы все нужные параметры? Напоминаю, в AX должен быть LBA первого загружаемого сектора. И в AX у нас

как раз номер первого сектора КД! CX должен содержать число загружаемых секторов. И, большая удача,

именно оно в CX и есть. Сегмент в ES у нас уже установлен, а смещение в BX мы явно задали перед

вызовом процедуры. Всё отлично! Осталась самая малость: написать саму процедуру.


Где-нибудь между hlt и переменными сделайте шаблон:


read_sectors proc

                              ;ПУСТО

read_sectors endp


Алгоритм работы в общих чертах представляется нам как-то так: перевести LBA в CHS, установить

значения регистров для int 13h, вызвать прерывание... Профит! Не будем медлить. Пишите:


read_sectors proc

                              div BPB_secpertrack;Разделить LBA в AX на число секторов в дорожке.

                              inc dl;Остаток + 1 = номер сектора, т.к. нумерация с 1.

                              mov cl,dl;Поместить номер сектора в CL для int 13h

                              xor dx,dx;Обнулить перед делением.

                              div BPB_numheads;Разделить результат на число головок.

                              shl dx,8;Остаток = номер головки, сдвинуть его в DH.

                              mov ch,al;Частное = номер дорожки, его поместить в CH для int 13h.

                              mov dl,0;DL = 0, флоппи-диск А.

                              mov ax,0201h;Функция 2 int 13h, загрузка секторов с диска. В AL - число секторов.

                              int 13h

                              ret

read_sectors endp


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

флоппи-диски! - имеют свойство не читаться с первого раза. На этот случай int 13h возвращает

статус операции в CF: если флаг обнулён - всё хорошо, если установлен - была ошибка чтения.

Во-вторых, даже в случае успеха мы загрузили только один сектор: значение в CX до сих пор не

используется. Начнём со второй проблемы:


read_sectors proc

                              mov bp,BPB_bytespersec;Размер сектора, понадобится внутри цикла.


main:                      pusha;Сохранить регистры общего назначения.

                              div BPB_secpertrack;Разделить LBA в AX на число секторов в дорожке.

                              inc dl;Остаток + 1 = номер сектора, т.к. нумерация с 1.

                              mov cl,dl;Поместить номер сектора в CL для int 13h

                              xor dx,dx;Обнулить перед делением.

                              div BPB_numheads;Разделить результат на число головок.

                              shl dx,8;Остаток = номер головки, сдвинуть его в DH.

                              mov ch,al;Частное = номер дорожки, его поместить в CH для int 13h.

                              mov dl,0;DL = 0, флоппи-диск А.

                              mov ax,0201h;Функция 2 int 13h, загрузка секторов с диска. В AL - число секторов.

                              int 13h

                              popa;Восстановить сохраненные регистры.


                              inc ax;Увеличить LBA.

                              add bx,bp;Сместить указатель загрузки на длину сектора.

                              loop main;Продолжить цикл.

                              ret;Завершить процедуру.

read_sectors endp


Процедура теперь организована в виде цикла со счётчиком в CX. Команда loop возвращает

указатель инструкции к указанной метке при условии, что CX не равен 0. CX при этом

уменьшается на 1. Обратите внимание, что в начале процедуры мы помещаем в BP

размер сектора в байтах, а блок кода из прошлой версии теперь обрамляется инструкциями

pusha и popa. Последнее нужно для того, чтобы после выполнения шага цикла вернуть вводные

значения в соответствующие регистры. Перед началом следующего шага LBA в AX увеличивается

на 1, а смещение области загрузки увеличивается на размер сектора. Время разобраться

с возможными ошибками чтения.


read_sectors proc

                              mov bp,BPB_bytespersec;Размер сектора, понадобится внутри цикла.

main:                      mov di,5;Число попыток чтения в случае ошибки.


load_sector:            pusha;Сохранить регистры общего назначения.

                              div BPB_secpertrack;Разделить LBA в AX на число секторов в дорожке.

                             inc dl;Остаток + 1 = номер сектора, т.к. нумерация с 1.

                             mov cl,dl;Поместить номер сектора в CL для int 13h

                             xor dx,dx;Обнулить перед делением.

                             div BPB_numheads;Разделить результат на число головок.

                             shl dx,8;Остаток = номер головки, сдвинуть его в DH.

                             mov ch,al;Частное = номер дорожки, его поместить в CH для int 13h.

                             mov dl,0;DL = 0, флоппи-диск А.

                             mov ax,0201h;Функция 2 int 13h, загрузка секторов с диска. В AL - число секторов.

                             int 13h

                             jnc sector_loaded;Если CF не установлен, сектор загружен успешно.


                             xor ax,ax;Функция 0 int 13h, сброс головок.

                             xor dl,dl;DL = номер привода, флоппи-диск А.

                             int 13h

                             popa;Восстановить сохраненные регистры.

                             sub di,1;Уменьшить счетчик попыток.

                             jnz load_sector;Если счетчик не обнулился, перейти к загрузке сектора.

                             ret


sector_loaded:        popa;Восстановить сохраненные регистры.

                             inc ax;Увеличить LBA.

                             add bx,bp;Сместить указатель загрузки на длину сектора.

                             loop main;Продолжить цикл.

                             ret;Завершить процедуру.

read_sectors endp


После вызова прерывания у нас теперь стоит jnc sector_loaded. Эта инструкция делает переход к

указанной метке, но только если флаг CF не установлен. Таким образом, к инициализации переменных

для следующего шага цикла мы попадаем только если предыдущий завершился успешно. Если же CF

установлен, начинается обработка ошибки. Функция 0 int 13h возвращает читающие головки привода к

0 сектору 0 дорожки, это должно уменьшить вероятность ошибки при следующем чтении. После

этого мы уменьшаем счётчик попыток на 1 и, если он не обнулился (инструкция jnz), делаем повторную

попытку. Теперь процедура почти готова. Остались финальные штрихи. Во-первых, сброс головок

тоже может пойти с ошибкой, и для пущей уверенности операцию стоит повторить несколько раз.

Во-вторых, было бы неплохо, если бы процедура обрабатывала ситуацию, когда все попытки чтения

завершились неудачей. Сейчас она просто завершается, как и в случае успеха. Начнём опять со второй задачи.


read_sectors proc

                             mov bp,BPB_bytespersec;Размер сектора, понадобится внутри цикла.

main:                     mov di,5;Число попыток чтения в случае ошибки.


load_sector:            pusha;Сохранить регистры общего назначения.

                             div BPB_secpertrack;Разделить LBA в AX на число секторов в дорожке.

                             inc dl;Остаток + 1 = номер сектора, т.к. нумерация с 1.

                             mov cl,dl;Поместить номер сектора в CL для int 13h

                             xor dx,dx;Обнулить перед делением.

                             div BPB_numheads;Разделить результат на число головок.

                             shl dx,8;Остаток = номер головки, сдвинуть его в DH.

                             test ah,ah;Проверить AH. Если больше нуля, что-то пошло не так.

                             jnz error;Т.к. на диске не может быть больше 255 дорожек, завершить с ошибкой.

                             mov ch,al;Частное = номер дорожки, его поместить в CH для int 13h.

                             mov dl,0;DL = 0, флоппи-диск А.

                             mov ax,0201h;Функция 2 int 13h, загрузка секторов с диска. В AL - число секторов.

                             int 13h

                             jnc sector_loaded;Если CF не установлен, сектор загружен успешно.


                             xor ax,ax;Функция 0 int 13h, сброс головок.

                             xor dl,dl;DL = номер привода, флоппи-диск А.

                             int 13h

                             popa;Восстановить сохраненные регистры.

                             sub di,1;Уменьшить счетчик попыток.

                             jnz load_sector;Если счетчик не обнулился, перейти к загрузке сектора.

                             ret


sector_loaded:        popa;Восстановить сохраненные регистры.

                             inc ax;Увеличить LBA.

                             add bx,bp;Сместить указатель загрузки на длину сектора.

                             loop main;Продолжить цикл.

                             ret;Завершить процедуру.


error:                     popa;Попытки кончились. Восстановить сохраненные регистры.

                             mov ax,07c0h;Сегмент загрузчика

                             mov es,ax;поместить в ES для int 10h.

                             mov ah,03h;Функция 3 прерывания 10h, получить позицию курсора в DH, DL.

                             xor bh,bh;BH = номер видеостраницы.

                             int 10h;DH = строка, DL = столбец.


                             mov ax,1300h;Функция 19 прерывания 10h, вывод строки. AL = режим вывода.

                             mov bx,0007h;BH = страница, BL = атрибуты символа.

                             mov cx,0010h;CX = длина строки.

                             mov bp,offset msg_DRE;ES:BP = указатель на строку.

                             int 10h;Вывести строку в DH,DL без обновления курсора.

                             cli;Запретить прерывания

                             hlt;и остановить процессор.

read_sectors endp


В первом сегменте кода после shl dx,8 у нас появилась проверка на ошибочность результата. Она

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

255, то что-то пошло не так. Программа переходит к метке error, после которой происходит

следующее: первый сегмент кода опустошает стек, а потом с помощью прерывания 10h

(прерывание для работы с дисплеем) считывает положение курсора на экране, а второй выводит сообщение

об ошибке и останавливает процессор. Строку с сообщением можно хранить рядом состальными переменными,

выглядит она так:


msg_DRE db 'Disk read error.' ;Сообщение об ошибке чтения с диска.


Осталась самая малость. Обработать повторные попытки сброса головок. Финальная версия прецедуры

будет выглядеть так:


read_sectors proc

                             mov bp,BPB_bytespersec;Размер сектора, понадобится внутри цикла.

main:                     mov di,5;Число попыток чтения в случае ошибки.


load_sector:            pusha;Сохранить регистры общего назначения.

                             div BPB_secpertrack;Разделить LBA в AX на число секторов в дорожке.

                             inc dl;Остаток + 1 = номер сектора, т.к. нумерация с 1.

                             mov cl,dl;Поместить номер сектора в CL для int 13h

                             xor dx,dx;Обнулить перед делением.

                             div BPB_numheads;Разделить результат на число головок.

                             shl dx,8;Остаток = номер головки, сдвинуть его в DH.

                             test ah,ah;Проверить AH. Если больше нуля, что-то пошло не так.

                             jnz error;Т.к. на диске не может быть больше 255 дорожек, завершить с ошибкой.

                             mov ch,al;Частное = номер дорожки, его поместить в CH для int 13h.

                             mov dl,0;DL = 0, флоппи-диск А.

                             mov ax,0201h;Функция 2 int 13h, загрузка секторов с диска. В AL - число секторов.

                             int 13h

                             jnc sector_loaded;Если CF не установлен, сектор загружен успешно.


                             mov cx,0003h;Счетчик попыток сброса головок.

reset:                     xor ax,ax;Функция 0 int 13h, сброс головок.

                             xor dl,dl;DL = номер привода, флоппи-диск А.

                             int 13h

                             jnc reload;Если не было ошибки - повторить попытку чтения сектора.

                             loop reset;Попробовать сбросить головки еще раз, если CX не обнулился.

error:                     popa;Попытки кончились. Восстановить сохраненные регистры.

                             jmp short disk_read_error;Сообщить об ошибке и завершить программу.


reload:                   popa;Восстановить сохраненные регистры.

                             sub di,1;Уменьшить счетчик попыток.

                             jnz load_sector;Если счетчик не обнулился, перейти к загрузке сектора.

                             jmp short disk_read_error;Сообщить об ошибке и завершить программу.


sector_loaded:        popa;Восстановить сохраненные регистры.

                             inc ax;Увеличить LBA.

                             add bx,bp;Сместить указатель загрузки на длину сектора.

                             loop main;Продолжить цикл.

                             ret;Завершить процедуру.


disk_read_error:      mov ax,07c0h;Сегмент загрузчика

                             mov es,ax;поместить в ES для int 10h.

                             mov ah,03h;Функция 3 прерывания 10h, получить позицию курсора в DH, DL.

                             xor bh,bh;BH = номер видеостраницы.

                             int 10h;DH = строка, DL = столбец.


                             mov ax,1300h;Функция 19 прерывания 10h, вывод строки. AL = режим вывода.

                             mov bx,0007h;BH = страница, BL = атрибуты символа.

                             mov cx,0010h;CX = длина строки.

                             mov bp,offset msg_DRE;ES:BP = указатель на строку.

                             int 10h;Вывести строку в DH,DL без обновления курсора.

                             cli;Запретить прерывания

                             hlt;и остановить процессор.

read_sectors endp


Поздравим себя! Теперь у нас есть процедура, считывающая данные с диска. Добавленный нами

вызов read_sectors в конце программы помещает КД диска в память сразу после самого

загрузчика. Следующий пост будет последним на тему первичного загрузчика. В нём мы научимся

пользоваться КД и FAT и загружать файлы.


Развернуть

gamedev Игры игрострой дневники разработчиков Roguelike 

Олдфажного геймдева пост номер 6

Самоизоляция, COVID-19, - отличное время, чтобы поработать над своим рогаликом. В конце как всегда ссыль для желающиx.


Archive
An archive room with hundreds of old books, parchments, and scrolls. Writings of long-dead heretics, doings of ancient kings, arcane knowledge - everything is destroyed by time and mold.
You see rotten beast.
You hear nothing but your own footsteps.
There are hostile creatures in this



Для теx, кто не в курсе, продублирую часть вступления из прошлого поста:


Итак, что такое Citadel? Одскульная текстовая RPG/roguelike. И, говоря "олдскульная", я имею в виду рили олд. Вспоминайте не эти ваши новомодные Wizardry I, а Eamon и всякое такое из второй половины семидесятых. При этом я, конечно, не ставлю себе цели мучить игрока и стараюсь сделать интерфейс и управление максимально простыми и понятными. Нужные подсказки и требующая внимания информация всегда отображаются в нижней части экрана, так что Citadel можно просто запустить и начать играть, не вникая в многостраничный мануал, как это бывало со старыми играми.


Что появилось в новой версии 0.14?


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

- Новый враг, automaton, умеющий ломать снаряжение.

- По одному новому типу сундуков, дверей и замков.

- Меxаника звука теперь работает: по команде Listen игрок получает аудиальную информацию из соседниx комнат и может на ее основании принять решение, стоит ли туда идти. Соответственно, существа теперь издают звуки. Комнаты, из которыx герой услышал какой-либо звук, помечаются на карте.

- Самое главное: на 1 и 2 этаже готовы этапы основного квеста для некоторыx концовок. Значит, теперь в игре есть цель! Пусть, она пока заключается всего лишь в том, чтобы спуститься на 3 уровень.


ROUND RESULTS
automaton does a crushing blow
you take 9 points of physical damage
cloth armor damaged
With a lion's roar you attack an empty space,gamedev,Игры,игрострой,дневники разработчиков,Roguelike



https://drive.google.com/file/d/1vyyn4Pkn_JsvKxFUXXeoz19Xrk-bRbvk/view?usp=sharing

https://drive.google.com/file/d/16k2Gpr7oPSekq4rAhmtBV0IPnIteDLlE/view?usp=sharing


Как и в прошлый раз, предлагаю желающим скачать и пощупать игру. Напоминаю, что для запуска нужен будет эмулятор bochs. И игра и эмулятор лежат по ссылкам выше. За инструкциями  по запуску обращайтесь в личку или в комментаx.


ritual dagger
Intricately decorated dagger with curved blade made of obsidian-1 ike material. It looks menacing but is hardly useful as a weapon.
Type: weapon Durability: 44/45 Physical damage: 6,gamedev,Игры,игрострой,дневники разработчиков,Roguelike


Развернуть

Игры старые игры обзор 

История видеоигр, часть 11: Computer Space (1971)

COMPUTER
SPACE
NA-2010,Игры,старые игры,обзор


Идея реализовать коммерческий потенциал игры Spacewar! захватила умы не только лишь авторов Galaxy Game. Мало кто мог ей противостоять. Вот и Нолан Бушнел со своим товарищем Тедом Дабни, видя, как компьютеры входят в доступный им ценовой сегмент, загорелись нажиться на популярности чужого творения. Парочка оформилась как Syzygy Engineering и работа закипела.


*»» f.A«,Игры,старые игры,обзор

Сегодня конверсия игры за авторством Майка О'Мэйли доступна здесь.


Первоначальным планом было портировать игру на популярный миникомпьютер Data General Nova. Предполагалось, что компьютер будет контролировать несколько параллельных игр на подключенных к нему консолях, однако, оказалось, что маломощный DGN не тянет даже одну. Попытки разгрузить процессор, переложив просчёт звёздного фона на специализированный ускоритель не помогли, и на некоторое время проект был заброшен.


Игры,старые игры,обзор

Нолан Бушнел, 2013 год.


Упорный Бушнел не смог выбросить идею из головы и придумал следующий ход: исключить из уравнения компьютер и собрать автомат целиком из специализированных контуров, отвечающих за разные аспекты геймплея и графики. Это не только позволило бы реализовать наконец игру, но и сильно удешевило бы производство. План удался частично: состоящий из праха и палок аппарат не поддерживал сеансы параллельной игры, режим для двух игроков, и не мог просчитывать гравитацию звезды в центре экрана. Отсюда выросли изменения в геймплее, благодаря которым опознать в Computer Space клон Spacewar! стало сложно. Корабль игрока лишился шкалы топлива и функции прыжка в гиперпространство, а вместо второго игрока появились два управляемых программой НЛО. Управлялась, строго говоря, одна, а вторая просто находилась на некотором расстоянии от первой и повторяла её движения. Время от времени то одна, то другая тарелка делали случайный выстрел в ту четверть экрана, где находился корабль игрока. Был введён таймер, по окончании которого подсчитывались очки игрока и компьютерного оппонента (наследие мультиплеера). Побеждал тот, кто за отведённое время успевал сбить противника большее число раз. Разработчики даже добавили в игру звуковое сопровождение, настолько высокочастотное, что уши игроков наверняка кровоточили.


■л H CAW,Игры,старые игры,обзор


Основанная в январе 1971-го Syzygy Engineering имела в активе 350 долларов и штат в два человека. Счастливый случай свёл Нолана с человеком из Nutting Associates, которым, как оказалось, позарез нужна была хитовая игра. Компания разглядела в проекте потенциал и Syzygy были предоставлены помещение и мощности для запуска производства. Тесты игры в публичных местах были успешными.

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

Как бы то ни было, Computer Space имела успех и обозначила начало эры коммерческих видеоигр. Бушнел и Дабни покинули Nutting Associates и продолжили игровую карьеру, переименовавшись из Syzygy в Atari. Моей первой приставкой, кстати, была Atar 2600. Родители подарили, кажется, на день рождения. Забавно, что всё детство мне не давал покоя слот для картриджей: ни одного из них я вживую так и не увидел.


т*»г cam,Игры,старые игры,обзор


Оригинал статьи

Развернуть

Игры старые игры обзор 

История видеоигр, часть 10: Galaxy Game (1971)

Игры,старые игры,обзор


 В 1971 году компьютерные игры были редкими диковинами, которые передавались от программиста программисту и кочевали из одного НИИ в другой, оставаясь неизвестными широкой публике. Было только одно исключение: Spacewar! Эта написанная в 1962 году игра стала настолько популярной, что по словам Алана Кэя цвела пышным цветом везде, где был компьютер с подключенным монитором. Её авторы не искали коммерческой выгоды, поэтому исходный код Spacewar! был доступен всем желающим. Да и невозможно было окупить игру, железо для которой стоило по тем временам 120 000$.


Игры,старые игры,обзор


В 1966 году студент Стэнфордского университета Билл Питтс познакомился со Spacewar! на университетском PDP-6. Там же на почве любви к игре он подружился с Хью Таком. Время шло, баснословно дорогие PDP-1 (которых, кстати, было продано всего 55 штук) сменились относительно дешёвыми PDP-11 (14 000$). Глядя на быстрое удешевление компьютерной техники, Питтс, который тогда уже выпустился и работал программистом, подумал, что было бы здорово и экономически привлекательно дать возможность простым людям за символическую плату приобщиться Spacewar!


1.	POSITIVE GRAVITY
2.	SUN C& GRAVITY)
3.	SLOW SPEED
4.	TWO PLAYERS
HOVE EITHER CONTROL STICK TO INITIATE GAME.
5
GAMES LEFT
0,Игры,старые игры,обзор


PDP-11 был всё ещё слишком дорог по сравнению со стоившими около 1000$ механическими аркадными автоматами, но идея начинала выглядеть достаточно заманчивой для сборки прототипа и оценки с помощью него интереса и платёжеспособности публики. Питтс адаптировал код к PDP-11 и, объединив финансовые резервы с Таком и его семьёй, приобрёл компьютер. Производство одного игрового автомата обошлось товарищам примерно в 20 000$.
Выглядело это так: PDP-11 кабелем соединялся с деревянной консолью, снабжённой дисплеем, контроллерами для двух игроков, сиденьями и монетоприёмником. Игру переименовали в Galaxy Game и выставили в здании студенческого союза Стэнфордского университета. Из-за низкой стоимости игры (10 центов за партию) Spacewar! даже близко не отбила собственную стоимость, но парочку это не огорчало: окрылённые популярностью игры, они начали работать над улучшенной версией автомата. Вместо того, чтобы снижать затраты на производство, они решили сделать убер-лакшери-версию. Компьютер был снабжён новым графическим процессором, который мог обрабатывать до четырёх игр на разных дисплеях одновременно. Корпусы четырёх консолей выполнили из голубого плексигласа, а сам PDP-11 спрятали в одну из них, чтобы не мозолил глаза. Результат выставили в кафетерии того же здания, где стоял оригинальный автомат (правда, в урезанном 2-консольном варианте). Игроки валили валом, однако увлёкшиеся друзья к тому времени потратили на своё детище более 65 000$ и потеряли даже малейший шанс вернуть вложенное, как и возможность развивать проект дальше.


Игры,старые игры,обзор


Автомат стоял на своём месте до тех пор, пока не вышел из строя графический процессор. Сейчас он в добром здравии и установлен в Музее Истории Компьютера в Калифорнии.

А что же насчёт самой игры? Она почти не отличалась от оригинала. Добавились опции включения\выключения центральной звезды и гравитации, настройка скорости, выбор режима для одного или двух игроков и возможность включить "отрицательную" гравитацию, при которой крабли игроков не притягивались к звезде, а отталкивались от неё. Всё те же два звездолёта, "Игла" и "Клин", сражались на фоне чёрно-белого космоса, маневрируя в гравитационном колодце местного солнца и уворачиваясь от пущенных друг в друга торпед. Игровые принципы и управление остались без изменений. Крутя джойстик, игрок направлял корабль в нужную сторону и при помощи специальной кнопки придавал ему ускорение. Ещё две кнопки отвечали за пуск торпед и прыжок в гиперпространство, который переносил корабль игрока в случайную точку на экране, но мог привести к взрыву. Игровая партия длилась до тех пор, пока один из игроков не нарывался на торпеду или не терял весь запас топлива.

Развернуть