[lua]모딩 일단 따라하기 - 1
https://gall.dcinside.com/mgallery/board/view/?id=factorio&no=23583
1에서 불갑옷예제 프로토타입을 만들고 한글이름을 붙이고 모드 패키징 하는것까지 알려줬음.
내일 쓰려고 준비했는데 준비하고보니 얼마안걸려서(내일까지 반나절넘게 남았다)
그냥 씀.
위키의 불갑옷예제에는 입고 걸어댕기면 바닥에 불이 붙는 효과가 있는데,
https://wiki.factorio.com/Tutorial:Modding_tutorial/Gangsir#The_control_scripting
이 코드 해설을 좀 하겠음.
따라하는건 그냥 복붙해서 control.lua파일을 하나 만들면 되니까 쉽다.
도대체 왜 이거시 이런 효과가 나는지 이해하는게 중요하니까 설명을 하겠어.
control.lua 내용을 작성하려면,
https://lua-api.factorio.com/latest/
이 홈페이지를 사전마냥 코딩 내내 켜놓고 봐야한다.
검색기능이 없기 때문에 구글에 캐시된 내용을 검색하는 식으로 필요한 내용을 찾아가야함.
---------------------------
--control.lua
script.on_event(defines.events.on_player_changed_position,
function(event)
local player = game.get_player(event.player_index) -- get the player that moved
-- if they're wearing our armor
if player.character and player.get_inventory(defines.inventory.character_armor).get_item_count("fire-armor") >= 1 then
-- create the fire where they're standing
player.surface.create_entity{name="fire-flame", position=player.position, force="neutral"}
end
end
)
---------------------------
◆ --control.lua
--는 lua의 코멘트 시작 표현임. 뒤에 적어둔건 걍 메모끄적여둔거다.
◆ script.on_event(☆1,☆2,☆3)
script는 팩토리오의 전역변수임. https://lua-api.factorio.com/latest/LuaBootstrap.html
.on_event는 그것의 메소드 함수. https://lua-api.factorio.com/latest/LuaBootstrap.html#LuaBootstrap.on_event
이 함수 설명을 읽어 봐야 인수로 어떤 값을 넘겨야하는지 알 수 있다.
예제에는 이 함수의 인수로
첫째 인수 ☆1 : defines.eve...
둘째 인수 ☆2 : function(eve...
두 개의 인수가 쓰였다.
세번째 인수 ☆3 자리는 옵션(optional, 안넣어도 상관없음)이라 안넣은듯함.
이 함수는 이벤트를 등록해주는 함수다. ☆1이벤트가 발생하면 ☆2가 자동으로 실행되게끔 만들어준다.
☆3는 필터인데, 이벤트를 일으킨 주체를 가려받는 용도로 사용하고, 여기선 안쓰임.
한가지의 이벤트에 발생시킬 함수를 여러개 등록해주려면 이걸 중복해서 사용하면 절대 안되고 다른 방법이 있다.
이 on_event함수를 같은 이벤트 종류에 그대로 중복해서 쓰면 전에 등록된건 지워지기 때문.
그건 다음에 기회되면 알려줌.
◆ defines.events.on_player_changed_position
defines들은 내부적으로는 숫자 값인데, 인지하기 편하도록 이렇게 defines테이블의 키값의 이름으로 표현되어 있음.
defines는 다른 프로그래밍 언어의 상수 치환 같은 기능을 한다고 보면 됨.
숫자를 넣어도 동작하긴 하는데 그럼 뭔지 모르잖아.
이 표시는 이벤트를 나타냄. 아래 내용을 찾아서 참고할 수 있도록 키값을 적어둔거임.
https://lua-api.factorio.com/latest/events.html#on_player_changed_position
그리고 이 이벤트 정보를 보면 이벤트가 발생했을 때, player_index라는 키값을 가진다고 설명이 되어있어.
그니까 플레이어가 움직이면 이 이벤트가 발생한다는 뜻이지.
그럼 다음 script.on_event의 두번째 인수를 보자.
◆ function(eve... 으로 시작해서 몇줄을 적힌 다음에 )괄호 앞의 ... end로 끝나는 블럭
lua의 함수블럭 표현방식인데, 이렇게 표현하는건 익명함수 표현방법이다.
함수를 선언했는데 함수가 어디 안가고 바로 script.on_event의 두번째 인수자리로 return되기 때문에 따로 함수이름도 필요없는 것.
◆ function(event)
이 함수는 인수를 한개를 받을 건데, 첫째 인수는 함수내부에서 event라는 local변수로 사용될거다. 라고 나타낸거.
이벤트 발생시 실행되는 함수는 죄다 약속이라도 한듯 인수 이름을 event로 사용한다.
◆ local player = game.get_player(event.player_index) 코멘트 빼고.
코멘트 -- 는 구분이 가지. 이 뒤에 있는건 실행이 되지않는 메모내용임.
local은 지역변수 선언을 나타내고, 해당 블럭 안에서만 player라는 값을 액세스 할 수 있게 될 거라는 내용임.
그리고 player에 값을 대입하기 시작함.
변수 선언시, 아무것도 안붙이면 상위 지역변수를 조작하거나, 전역변수를 만드는 일이된다.
근데 팩토리오에서는 절대로 무표기 전역변수를 만들면 안된다.
그 값은 save를 못하게 되고,
save를 못하기 때문에 멀티플레이어에서는 "참가자를 위해 save를 했는데 참가자랑 너의 맵 상태가 일치가 안되서" desync가 일어나서 참가자나 너는 서버에서 쫒겨난다.
무표기 전역변수는 혼자서 lua 코드 테스트 할 때나 쓰는거임.
팩토리오 전역변수 선언은 팩토리오 전역변수인 global이라는 테이블 안에 키값으로써 입력해주면 안전하게 save가능한 값이 된다.
전역변수 관련 : https://lua-api.factorio.com/latest/Global.html
game은 팩토리오 전역변수임. https://lua-api.factorio.com/latest/LuaGameScript.html
.get_player(☆1)는 game의 메소드 함수. https://lua-api.factorio.com/latest/LuaGameScript.html#LuaGameScript.get_player
함수 설명을 보면 인수를 뭘 던져넣어야하고, 어떤 값을 return하는지 설명이 나온다.
링크 타서 보면 The player index or name 을 인수로 받아서 LuaPlayer클래스를 return한다는 내용이 있다.
짧게 쓰면 game.players[event.player_index] 라고 쓰라고 부연설명도 있네. 친절해라.
그리고 .get_player의 인수로 던져진게, event.player_index이다.
여기서 event는 윗줄에 function(event)라고 해서 받은 첫번째 인수를 event라고 부르라고 했기 때문에 event인 것이고 미리 등록된 변수명같은건 아니다.
그리고 on_player_changed_position 이벤트의 설명에, 이벤트가 발생하면 player_index라는 키값을 던져준다고 했기 때문에,
함수 내부로 들어온 event는 테이블값이 되고, 키값으로 player_index를 가지고 있게 된다.
json 형식으로 표현하면 이런거임.
event = {
player_index = 숫자값
}
이 player_index를 읽는거임.
◆◆ if player.character and player.get_inventory(defines.inventory.character_armor).get_item_count("fire-armor") >= 1 then
존나기네. 좀 짜르자. if ... then 은 if문을 시작하는 구문이고,
◆ player.character
위에 local player로 정의한 player는 game.get_player가 LuaPlayer클래스를 return 했기 때문에 아마도 LuaPlayer가 들어가 있을 것이다.
그럼 여기를 참고해야한다.
https://lua-api.factorio.com/latest/LuaPlayer.html
LuaPlayer에서 character라는 키값을 호출하면 뭐가 나오냐...
https://lua-api.factorio.com/latest/LuaPlayer.html#LuaPlayer.character
플레이어가 소유한 캐릭터를 return한다고 되어있네. 캐릭터의 원형 클래스는 LuaEntity임.
player.character 라고 쓰고 그다음에 바로 and 로 가는데, 비교문 조합하는 거임.
player.character가 nil(값 없음)이면 false, 아무튼 뭔가가 return되어서 존재한다면 true로 인식되는 것임.
◆ player.get_inventory(defines.inventory.character_armor).get_item_count("fire-armor")
그리고 아 이거 존나 기네.
위에 적어놓은 LuaPlayer 클래스의 설명페이지에 가보면 get_inventory 메소드 함수가 있음.
문자열 검색으로 찾아보면 이렇게 LuaControl에서 상속되었다고 나와있는데,
이런식으로 상속으로 정의된 메소드나 키가 많으니 좀 주의깊에 볼 필요가 있다.
아무튼간에 누르면 설명이 나옴.
https://lua-api.factorio.com/latest/LuaControl.html#LuaControl.get_inventory
파라메터로 defines.inventory 종류를 던지라고 나오지. 그러면 LuaInventory를 return한다고 나와있다.
그럼
player.get_inventory(defines.inventory.character_armor)
여기까지 실행되면 LuaInventory임. 그것도 캐릭터의 아머슬롯 인벤토리를 나타내겠네.
그리고 그 뒤에 .(점)이 붙고 뭐가 또 호출되었으니 그놈은 LuaInventory소속임.
그니까 .(점) 바로 뒤에 있는 get_item_count함수는 LuaInventory소속임.
https://lua-api.factorio.com/latest/LuaInventory.html#LuaInventory.get_item_count
item을 문자열로 받고, 갯수를 숫자로 return한다고 적혀있다.
"fire-armor" : 프로토타입으로 열심히 만들었던 그 아이템의 이름이다. 프로토타입 만들면서 만든사람이 지어준거지.
그래서 이게 다 실행되면 최종적으로 갯수값이 나오는거임.
◆◆
그럼 on_player_changed_position 이벤트를 일으킨 주체인 플레이어가 멀쩡한 캐릭터를 조작중이면,(캐릭터 없는 에디터 상태같은게 아니라면)
player.character 는 어떤 값이 나오고 and로 합쳐질 예정이기 때문에 boolean값인데 true일테고,
그 캐릭터의 갑옷 슬롯에 fire-armor가 들어있으면 아이템 갯수값은 1이 될테니
if ... then 구문은
if true and 1 >= 1 then이 되는거야.
만약 그렇지 않다면 이 if문의 내용은 실행되지 않고 다음으로 넘어가겠지.
◆ player.surface.create_entity{name="fire-flame", position=player.position, force="neutral"}
이건 자주쓰이는건데,
LuaPlayer는 surface라는 키값을 가지고 있어.(LuaControl로부터 상속됨) 그 플레이어가 서있는 지면(surface)의 LuaSurface를 return하지.
https://lua-api.factorio.com/latest/LuaControl.html#LuaControl.surface
https://lua-api.factorio.com/latest/LuaSurface.html
create_entity{...}는 LuaSurface클래스의 메소드 함수인데,
https://lua-api.factorio.com/latest/LuaSurface.html#LuaSurface.create_entity
함수이름{...} 이렇게 중괄호{}로 된건 받는 인수가 하나이고 그 인수는 그 자리에서 만들어진 table이라는 뜻임.
함수이름(...) 이렇게 괄호()로 된건 받는 인수가 그 자리에서 만들어진 테이블이 아니거나, 인수가 필요없는 함수거나, 인수가 여러개 라는 뜻.
함수이름{...} 이 표현은 함수이름({...}) 표현의 약식표현임. 둘이 같아. 유일한 인수가 table이라는 거지.
local sometable = {...}
surface.create_entity(sometable)
이렇게 쓰든가
surface.create_entity{...}
이렇게 쓰든가
surface.create_entity({...}) 이렇게 쓰든가 맘대로...
보면 3개의 키값을 가진 테이블 1개가 create_entity의 인수로 들어가는 모양인데,
{
name = "fire-flame",
position = player.position,
force = "neutral",
}
함수 설명 페이지 보면 각각 뭔지 대충 알 수 있을테니 넘김.
lua 테이블 표현에서 마지막 키값의 끝에 ,콤마를 넣어도 문법상 문제없다. 줄 단위로 복붙하기 편하라고 그렇게 한듯.
◆◆ 마지막 블럭닫는구문
end
end
)
첫째 end는 if블럭을 닫고, 둘째 end는 function(event)를 닫고, 셋째 )괄호는 script.on_event의 인수입력을 닫는다.
이걸로 script.on_event라는 이벤트 등록 함수 하나의 실행이 끝난거임.
얘가 한번 등록해줬으면, 해당 이벤트가 일어날 때마다 몇번이고 계속해서 등록된 함수가 실행이 된다.
이걸로 캐릭터가 움직여서 위치가 변할 때마다, 캐릭터의 위치에 중립세력 소속의 화염 엔티티를 만드는 기능이 되었다.
◆ 프로토타입 참고
참고로 fire-flame 엔티티는
팩토리오 설치폴더/data/base/prototypes/entity/fire.lua의 334번째 줄에 프로토타입이 입력되있는거 같네.
설치폴더/data/base/prototypes/fire-util.lua에 적어둔 함수를 사용하는걸 보면 화염 프로토타입 만드는 과정 자체를 함수화 해둔거 같다.
프로토타입 입력구문 살펴보면, type = "fire" 라고 했으므로 바닐라 data.raw리스트에서는 fire를 찾아가면 됨
https://wiki.factorio.com/Data.raw#fire
링크따라가면 이 화염의 프로토타입의 프로토타입(클래스)은
https://wiki.factorio.com/Prototype/FireFlame
이런식으로 기존에 바닐라나 다른 모드에서 만들어진 프로토타입이 어떤 프로토타입의 프로토타입(클래스=type)...를 참조하고 있는지 추적이 가능함.
이것저것 보면서 내가 원하는 프로토타입을 만드는데 참고할 수 있다.
◆ 암튼 됨.
아무튼,
그래서 이걸로 캐릭터가 움직여서 위치가 변할 때마다, 캐릭터의 위치에 중립세력 소속의 화염 엔티티를 만드는 기능이 되었다.
fire-flame엔티티는 화염속성 틱뎀을 주는 놈인데,
fire-armor만들 때 화염저항 100% 했기 때문에 착용자는 뜨겁지 않아. 기지를 다 불태울 뿐.
다음 예제 예약받는다. 뭐가 만들고싶어? 마법지팡이? 레벨업하는 캐릭터? GUI? 등등...?
해당 댓글은 삭제되었습니다.
https://wiki.factorio.com/Prototype/Car
그거 가능성을 보려면 이걸 잘 살펴봐야하는데, 내가보기엔 속도제한같은건 안보여
애초에 속도제한이 어떤 속도수치로 제한한게 아니라, 마찰력(지면따라 마찰이 달라), 가속력, 지면의 속도뽀너스(콘크리트), 연료효율, 연료출력, 차량무게, 연료의 최대속도보너스같은게 복합적으로 작용해서 나오는 속도인걸로 알고있음
정신나간 차를 만들려면 정신나간 연료도 필요하겠지. 연료는
https://wiki.factorio.com/Prototype/Item#fuel_acceleration_multiplier
car 프로토타입에 effectivity 수치만 미친놈처럼 올려줘도 천원돌파할거같긴하다
어려워영
그래도 일단 따라해봄
바닥타일 깔면 전신주 역할 해주는거
타일하고 전신주는 프로토타입이 달라서 호환이 안되. 그래도 타일을 깔 때마다 한칸짜리 투명전신주가 같이 깔리는걸 하면 될거같긴한데, 타일 이벤트 활용하는 방법을 알려주면 직접만들 수 있겠지?
플루드필으로 인식 못함?
뭐야 그게? 맵에디터에서 타일 채우는 기능 말하는거야? 그건 API에서 LuaSurface.get_connected_tiles 이거같은데, 이거는 타일 좌표따는 기능이고, 전력공급이랑은 하등상관없음.
줌아웃멀리할때마다 콘솔창에 줌 0.1 입력해서 보는데. 모드 깔아놓으면 최대 줌아웃 한계 풀어주는거 만들어조. - dc App
비슷한거 있는거 같은데?
https://mods.factorio.com/mod/Infinizoom
형나 궁금한게 있는데, 텔레포트 기차 모드 보면 기차 속도는 솔직히 상관 없어보이는데 차량 무게가 1이니까 속도 개빨라 보임 근데 뒤에 바닐라 기차 달면 원래 속도로 감. 텔포 기차 속도는 1억 800만km 인데 ... 뭘로 계산되길래 이딴 속도가 나올까 ?
몰라 그냥 가벼우니까 빨리가는거아니야? 가볍게하고 연료효율 수치를 100% 넘게 잡아버리면 1W연료먹고 1MW출력이 나오고 뭐 이러겠지.