|
Raven
Пользователь
Откуда: Владик Регистрация: Февр. 2004
Всего: 408 сообщений
|
to Garold По поводу битов: молодец, растёшь. :-) Я использовал битовую запись в LVARы при написании скрипта игры в пятикарточный покер на троих. В 6 LVAR-ов удалось запихнуть почти 100 переменных - информацию о наличии/отсутствии в колоде каждой из 52 карт, информацию о картах на руках у каждого из трёх игроков, информацию о наличии комбинаций у текущего игрока. Возможно, ты видел мой постинг с вопросом о структуре save-файлов. Мы с Абелем продолжили разговор по почте. И буквально два дня назад я предложил ему идею побитовой записи в неиспользованные в игре, но прописанные в vault13.gam GVARы. В три GVARы можно записать 90 битовых (1/0) значений, т.е. информацию о 45-ти небольших простых квестах (1/0 - взят/не взят, 1/0 - выполнен/не выполнен). Для квестов с многочисленными исходами или временным лимитом потребуеться, конечно, больше битов - но ведь и свободных GVARов, если поискать, можно найти побольше. Причём тут сейвы? Дело в том, что при добавлении нового квеста (и, соответственно, новых GVARs) в игру необходимо занести GVARы в файл vault13.gam. Все GVARы оттуда пишутся в сейв-файл. И сейвы становятся несовместимыми. Но если мы пишем в вары прописанные в vault13.gam, но не используемые в игре - то сейвы будут совместимы! А побитовая запись позволяет записать в несколько варов большое количество информации. Т.е. если разработать соответствующее API (в виде процедур побитовой записи) и задокументировать соответствующие свободные вары - то можно будет делать полноценные моды, совместимые с сейвами оригинального Фола (а при договорённости между модерами об использовании разных GVARs - и совместимые между собой моды!). Представь себе - выходит новый оружейный мод. Меняет в основном стволы, добавляет квестов, сейвы не совместимы. Что ты будешь делать? Начинать играть по новой? А так - загрузил свой СТАРЫЙ сейв и наслаждаешься НОВЫМ оружием и предметами... Такой подход не потребут перекомпиляции оригинальных скриптов из Фола или подобных трудоёмких операций. Авторы новых модов - возьмите на заметку. К сожалению, реализовать такое в "Новом Взгляде" мы уже не успеем :-( Но "Новый Взгляд" как раз и предполагает пролхождение игры с самого начала. Теперь, по традиции, полезная часть. Два куска кода из моего покера с реализацией побитовой записи/чтения (я использовал LVAR, а не GVAR - но никакой разницы, как понимаете, нет). О-о-чень рекомендую уж если не изучить код - то ознакомиться с комментариями. ----poker_bits.ssl---- //Работа с битовыми массивами ( в смысле, с LVARS :-) //Возвращает 1/0 - есть/нет карта с UID x (1-52) в колоде //Возвращат значение бита x из одной из двух пременных, отведённых под колоду procedure get_deck(variable x) begin if (x < 31) then return lvar_bit(LV_DECK1,pow(2,x-1)); else return lvar_bit(LV_DECK2,pow(2,x-31)); end /* lvar_bit(x,2^y) - возвращает значение бита номер y из переменной x Для использования процедуры очень желательна ф-ия возведения в степень pow(x,y) - возвращает x^y */ <...> //Для работы с .. гм .. руками. //Процедура записывает число от 1 до 52 в переменную hand (hand хранит значение LVAR руки текущего игрока) //для представления числа 52 необходимо 6 бит, т.е. в переменную записывается пять блоков по 6 бит //num определят смещение tmp для записи значения карты номер num (1-5) //--------------------------------------------------- procedure set_hand(variable num,variable value) begin variable i:=5;variable tmp;variable tmp1:=32; tmp:=6*num-1;//6*(num-1)+(5-i); while i>=0 do begin if value/tmp1!=0 then begin set_lvar_bit_on(hand,pow(2,tmp-i)); value-=tmp1; end else set_lvar_bit_off(hand,pow(2,tmp-i)); tmp1/=2; i-=1; end end /* to Garold Принцип работы процедуры set_hand на примере. Пусть мы хотим записать в hand информацию о том, что карта номер 4 в руке имеет номер 51. num:=4;value:=51;tmp1:=32; tmp:=23; Первый проход цикла: Срабатывает условие if (51 больше-равно 32) - мы устанавливаем бит номер tmp-i=23-5=18 - первый в 4-ом 6-и битовом блоке. value=51-32=19 tmp1:=tmp1/2=16; i:=4; Второй проход: if (19 больше-равно 16) == true => устанавливаем второй бит в блоке value:=3;tmp1:=8;i:=3; Третий проход: if ( 3 больше-равно 8 ) == false => третий бит в 0 value:=3;tmp1:=4;i:=2; Четвёртый проход: if ( 3 больше-равно 4 ) == false => четвёртый бит в 0 value:=3;tmp1:=2;i:=1; Пятый проход: if ( 3 больше-равно 2 ) == true => пятый бит в 1 value:=3-2=1;tmp1:=1;i:=0; Шестой проход: if ( 1 больше-равно 1 ) == true => шестой бит в 1 В конечном итоге имеем запись 110011 - двоичное значение 51 (вообще говоря, "перевёрнутое") со смещения 18-1=17 В принципе, стандартнаz процедура конвертации dec->bin, только bin записывается задом наперёд */ //Разбери сам (лучше на примере). procedure get_hand(variable num) begin variable i:=0;variable tmp:=0; variable tmp1;variable tmp2:=1; tmp1:=6*num-1; while (i<=5) do begin if lvar_bit(hand,pow(2,tmp1-i)) then tmp+=tmp2; tmp2*=2; i+=1; end return tmp; end <...> ----poker_bits.ssl---- Листинг процедуры pow(x,y) -------- //возведение в степень. x - показатель, y - степень procedure pow(variable x,variable y) begin /* Степени разбиты по категориям для ускорения, т.к. при линейной структуре процедура возврата работает ОЧЕНЬ медленно, не говоря уже об универсальном возведении в степень (см. конец процедуры) */ variable i:=1;variable tmp; if y==1 then return x; if y==0 then return 1; if y==-1 then return (1/x); //Ускоряем возврат степеней двойки. Вплоть до 2^30 //на 2^31 наступает переполнение, мы можем писать/читать только 30 бит в варе if (x==2 and y < 31) then begin if (y<10) then if (y<6) then begin if (y==2) then return 4; if (y==3) then return 8; if (y==4) then return 16; if (y==5) then return 32; end else begin if (y==6) then return 64; if (y==7) then return 128; if (y==8) then return 256; if (y==9) then return 512; end if (y<20) then if (y<16) then begin if (y<13) then begin if (y == 10) then return 1024; if (y == 11) then return 2048; if (y == 12) then return 4096; end else begin if (y == 13) then return 8192; if (y == 14) then return 16384; if (y == 15) then return 32768; end end else begin if (y == 16) then return 65536; if (y == 17) then return 131072; if (y == 18) then return 262144; if (y == 19) then return 524288; end if (y<31) then if (y<26) then begin if (y<23) then begin if (y == 20) then return 1048576; if (y == 21) then return 2097152; if (y == 22) then return 4194304; end else begin if (y == 23) then return 8388608; if (y == 24) then return 16777216; if (y == 25) then return 33554432; end end else begin if (y == 26) then return 67108864; if (y == 27) then return 134217728; if (y == 28) then return 268435456; if (y == 29) then return 536870912; if (y == 30) then return 1073741824; end end tmp:=x; if y>1 then begin while(i<y) do begin tmp*=x;i+=1; end return tmp; end if y<0 then begin while(i<=0-y+1) do begin tmp*=x;i+=1; end return (1/tmp); end end -------- to Garold Если нужен скрипт Покера - пиши на мыло. (Отредактировал(а) Raven - 13:19 - 30 Апр., 2004)
|
Отправлено: 6:14 - 30 Апр., 2004
|
|
Jo Jim
Пользователь Регистрация: Март 2004
Всего: 14 сообщений
|
А если без "наверное". Тут, я так понимаю, отвечают на вопросы новичков. Ничего сложного я не спросил, а ответа так и не получил Итак, где можно посмотреть, какими значениями инициализируются LVAR для определенного скрипта. Пример: dclara.ssl Какие значения у переменных LVAR_Home_Tile LVAR_Home_Rotation
|
Отправлено: 10:32 - 30 Апр., 2004
|
|
Raven
Пользователь
Откуда: Владик Регистрация: Февр. 2004
Всего: 408 сообщений
|
to Jo Jim Извини за задержку :-) Если явной инициализации нет, то смотри все вызываемые в скрипте макросы (в процедурах start, map_enter, timed_event, critter_p_proc и т.п.) - LVAR инициализируется в одном из них. Т.к. в Фолаутовских скриптах вложенность макросов велика (один макрос может быть надстройкой для другого, который построен на базе третьего и т.д.), то найти точное место инициализации довольно сложно. Для твоего примера. dclara.ssl = Den Critter Lara Следовательно, критер "прописан" в Дэне. Открываем headers\den.h , ищем строчку set_local_var(LVAR_Home_Tile Находим строчку в макросе gang_member_map_enter Теперь открываем скрипт Лары и ищем gang_member_map_enter: ------------------- procedure map_enter_p_proc begin gang_member_map_enter flush_add_timer_event_sec(self_obj, 1, timed_event_float); end ------------------- Т.е. вара LVAR_Home_Tile инициализируется каждый раз при заходе на карту. Там же инициализируется LVAR_Home_Rotation. Вообще говоря, макрос не обязательно будет именно в имя_города.h, лучше делать контекстный поиск по всем файлам в headers. to Gatling А ты пробовал пользовать VDM?
|
Отправлено: 12:28 - 30 Апр., 2004
|
|
Jo Jim
Пользователь Регистрация: Март 2004
Всего: 14 сообщений
|
Спасибо, Рэйвен. Очень полезная информация оказалась, но я по- прежнему не могу найти ЗНАЧЕНИЯ которыми, скажем так, заполняются эти переменные. Опишу ситуацию подробнее. После уничтожения банды Тайлера и выхода и боевого режима банда Лары занимает церковь. В версии 1.0 (и в бисовских скриптах) Лара встает на место Тайлера, справа от входа в церковь. В Версии 1.2 Лара располагается внутри церкви вместе со своей бандой. В связи с эти у меня проблема: Действуя по описанной технолонгии, я по-прежнему не могу получить конкретно set_local_var(LVAR_Home_Tile, 23096), например. То есть я не знаю где именно эти значения и чему эти значения, извините за такое выражание, равны! Ведь для каждого скрипта каждого члена банды долже быть свой LVAR - то есть где-то должно быть систематизированное хранилище этих значений.
|
Отправлено: 15:34 - 30 Апр., 2004
|
|
GaroldPredator
Пользователь
Откуда: Military Base Регистрация: Апр. 2004
Всего: 52 сообщения
|
to Gatling Лично я леплю диалоги прямо в f-Gecke (где найти его, смотри в начале), а чтобы не запутаться, перед каждой процедурой добавляю комментарии! vsem ostalьnыm Я собственно зачем пришёл? Ах, да, хочу спросить! Я добавил несколько скриптов (XSCOMP.INT, XSCOMP1.INT, XSCOMP2.INT), причём XSCOMP2.INT последний. Когда я пытаюсь привязать эти скрипты к объектам, привязывается почему-то только последний! Если в списке выбора скриптов тыкать первый или второй, всё равно выбирается последний!!! Что делать?! (Отредактировал(а) GaroldPredator - 17:41 - 30 Апр., 2004)
----- В мире есть две точки зрения: неправильная и моя.
|
Отправлено: 17:39 - 30 Апр., 2004
|
|
Raven
Пользователь
Откуда: Владик Регистрация: Февр. 2004
Всего: 408 сообщений
|
to Garold Посмотри наличие/отсутствие в Scripts.lst пустых строк. Поменяй табы на пробелы во всех самостоятельно вписанных строках. Просмотри scripts.lst в различных текстовых редакторах. Т.е. проблема возникает из-за несоблюдения формата scripts.lst to Jo Jim Ответ уже готов. В голове. Перевожу в текстовый формат - как закончу - сделаю пост.
|
Отправлено: 3:25 - 1 Мая, 2004
|
|
Raven
Пользователь
Откуда: Владик Регистрация: Февр. 2004
Всего: 408 сообщений
|
to Jo Jim Если тебе нужен только ответ - смотри в конец поста. Если хочешь понять, как я его нашёл - смотри ход мысли с самого начала. Итак, мы ищем координаты хексов на которые встают члены банды Лары после боя с бандой Тайлера. Начнём с начала. Ищем в dclara.msg номер строки, начинающей атаку на Тайлера: ---dclara.msg line:158--- {490}{}{I don't think so. You'll have to come with us if you want your money. You won't have to fight but just to be sure it's not a trap. We'll give you $300 total.} {491}{}{You ready?} {492}{}{Okay, let's do it.} <--- То, что нам надо. ------------------------- Ищем номер 492 в dclara.ssl: ---dclara.ssl line:450--- NOption(492, Node990, 004); ------------------------- Ищем Node990: ---dclara.ssl line:277--- procedure Node990 begin setup_gang_fight; end ------------------------- Открываем den.h и изучаем макрос setup_gang_fight: ---den.h line:583--- <...> set_gangwar(state_gangwar_in_fight); <--- устанавливает GVAR_DEN_GANGWAR=state_gangwar_in_fight <...> load_map(MAP_DEN_BUSINESS,0) <--- грузим карту denbus2.map (см. -------------------- Открываем maps\denbus2.ssl и видим следующее: ---denbus2.ssl line:58--- procedure map_enter_p_proc begin <...> if (gangwar(state_gangwar_in_fight)) then begin override_map_start_hex(21945,0,2); <--- закидываем Чузена поближе к церкви <...> ------------------------- Одновременно у всех критеров из банды Лары срабатывает map_enter_p_proc. Это просто вызов макроса gang_member_map_enter из den.h. Смотрим только те ветки if-ов, которые срабатывают для gang2, т.к. у Лары в скрипте написано #define self_gang gang_2 Итак, смотрим: ---den.h line:798--- <...> end else if (self_gang == gang_2) then begin if (NAME == SCRIPT_DCLARA) then gang_2_member_1 := self_obj; <...> end -------------------- Здесь переменные вида gang_x_member_y заполняются указателями на членов банд. Для Лары и Марка всегда y:=1, для остальных - как придётся. Эти вары импортируются в скрипте Лары и остальных критеров (про импорт/экспорт можешь прочесть в моём предыдущем посте. Если не поймёшь - спрашивай, объясню подробнее). Дальше: ---den.h line:798--- <...> end if (gangwar(state_gangwar_in_fight)) then begin <...> end else if (self_gang == gang_2) then begin if (gang_trap(state_gang_trap_no)) then begin critter_add_trait(self_obj,TRAIT_OBJECT,OBJECT_TEAM_NUM,TEAM_PLAYER); <...> -------------------- Лара загоняется в команду к игроку. Теперь смотрим gang_critter_p_proc: ---den.h line:777--- <...> if (gangwar(state_gangwar_in_fight)) then begin if (self_gang == gang_2) then begin gang_2_follow_to_attack <...> -------------------- Смотрим gang_2_follow_to_attack -> set_gang_2_follow - видим, что каждому мемберу Лариной банде приказывается долбить мембера опозиционной банды с минимальным номером (начиная с Марка, для которого, как помнишь x:=1). Начинается резня. При убийстве членов gang1 срабатывает dest_gang_member, который обнуляет указатель gang_1_member_x и вызывает dec_gang_counter(self_gang). Когда банда перебита, срабатывает set_gang_1_dead -> set_gangwar(state_gangwar_2won). Всё - война закончилась, Лара победила, все указатели на gang_1_member_x обнулены. Теперь, собственно, ответ на твой вопрос :-) Смотрим gang_map_update_p_proc: ---den.h line:863--- if (local_var(LVAR_Home_Tile) == 0) then begin if (self_gang == gang_2) then begin check_take_home_tile(1) else check_take_home_tile(2) else check_take_home_tile(3) else check_take_home_tile(4) else check_take_home_tile(5) if (local_var(LVAR_Home_Tile) == 0) then begin random_tile_in_box(22340, 22332, 24132, 23940); set_local_var(LVAR_Home_Tile, global_temp); set_local_var(LVAR_Home_Rotation, random(2,4)); end end else begin set_local_var(LVAR_Home_Tile, self_tile); end end -------------------- check_take_home_tile(x) устанавливает LVAR_Home_Tile мембера Лариной банды номер x равному текущему положению соответствующего по номеру мембера банды Тайлера. Когда бой закончен - check_take_home_tile перестаёт работать, а переменным LVAR_Home_Tile присваивается случайное значение из квадрата с координатами (22340, 22332, 24132, 23940) LVAR_Home_Rotation присваивается случайное значение от 2 до 4 включительно. После установки этих значений критер идёт куда надо и поворачивается благодаря следующим строчкам из gang_critter_p_proc: ---den.h line:777--- <...> end else if (self_tile != local_var(LVAR_Home_Tile)) then begin animate_move_to_tile(local_var(LVAR_Home_Tile)); end else if (self_cur_rot != local_var(LVAR_Home_Rotation)) then begin animate_rotation(local_var(LVAR_Home_Rotation)); end --------------------
|
Отправлено: 8:14 - 1 Мая, 2004
|
|
GaroldPredator
Пользователь
Откуда: Military Base Регистрация: Апр. 2004
Всего: 52 сообщения
|
Спасибо, конечно, но я забыл написать, что уже разобрался !
----- В мире есть две точки зрения: неправильная и моя.
|
Отправлено: 9:24 - 1 Мая, 2004
|
|
GaroldPredator
Пользователь
Откуда: Military Base Регистрация: Апр. 2004
Всего: 52 сообщения
|
to Raven Меня давно мучает такой вопрос: Как воспроизвести анимацию, не используя объект? Т.е, я использую компьютер, и из-за этого где-то открывается дверь. И второй вопрос вдогон: Я нарисовал анимацию опсукания шлагбаума (такого, как в Военной базе). Как мне её привязать к этому шлагбауму. Шлагбаум в закрытом положении. Я использую комп. Вызывается анимация поднимания (или поднятия?) шлагбаума. Шлагбаум в поднятом положении. Как всё это провернуть?
----- В мире есть две точки зрения: неправильная и моя.
|
Отправлено: 17:34 - 1 Мая, 2004
|
|
Raven
Пользователь
Откуда: Владик Регистрация: Февр. 2004
Всего: 408 сообщений
|
Для воспроизведения произвольной анимации используй команду ---------------------------------------------------------- #include <animcomd.h> anim(obj_ptr,anim_index,direction); ---------------------------------------------------------- ,где obj_ptr -указатель на анимируемый объект, anim_index - из списка ANIM_ в animcomd.h, direction - 0-5 Это работает, в основном, для критеров. Для твоего случая этого не надо. Более того, простое проигрывание анимации открытия двери не сделает эту дверь открытой - ты получишь закрытую дверь с анимацией "открытой" двери. Для это лучше использовать процедуру ---------------------------------------------------------- obj_open(obj_ptr); ---------------------------------------------------------- Для получения указателя на дверь можно использовать импорт переменных. Но не нужно. Лучше: ---------------------------------------------------------- tile_contains_pid_obj(int tile, int elev, int pid); ---------------------------------------------------------- Tile - координата двери. Берёшь из Мапера - просто выбери дверь и запомни пятизначное число в левом нижнем углу. Elevation - без комментариев. С pid`ом сложнее. Можешь написать простенький скриптик: ---------------------------------------------------------- procedure look_at_p_proc begin display_msg("PID:"+obj_pid(self_obj); end ---------------------------------------------------------- и повесить на дверь (или что у тебя там). Если ты настроил Мапер на редактирование прототипов - то можешь просто выбрать прото своей двери, нажать E, поменять что-нибудь и сразу вернуть изменения, нажать Done. Теперь в C:\Fallout2\dev\proto\scenery у тебя появится что-то типа 00000022.txt и в нём будет указана разная информация об объекте - в т.ч. и pid. В конечном итоге у тебя получится что-то подобное: ---------------------------------------------------------- obj_open(tile_contains_pid_obj(20301,0,33554454)); ---------------------------------------------------------- Прописываешь это в нужном ноде или use_p_proc - и всё. Второй вопрос: тебе нужно заделать шлагбаум под дверь и сопоставить стандартным frm-кам двери твои анимации (открыт, закрывается, закрыт;открывается = закрывается наоборот, ей рисовать не надо). Т.е., насколько я понял, у тебя есть три frm-ки? Одна анимированная и две статичных? Расскажи, пожалуйста, поподробнее.
|
Отправлено: 5:59 - 2 Мая, 2004
|
|
|
|