Important information: this site is currently scheduled to go offline indefinitely by December 1st 2023.
If you wish to donate to attempt the preservation of tools and software somewhere else before it goes down, check the GoFundMe

No More Heroes: Heroes' Paradise

Post questions about game models here, or help out others!
chrrox
Moderator
Posts: 2602
Joined: Sun May 18, 2008 3:01 pm
Has thanked: 57 times
Been thanked: 1428 times

No More Heroes: Heroes' Paradise

Post by chrrox »

Here is a 3ds max importer for the xbox 360 models of this game. Supports bones and weights.
Image

Code: Select all

if (heapSize < 20000000) then
	heapSize = 200000000 -- allow ~ 40 MB instead of just 7.5 MB. Prevents "Runtime Error: Out of scripter memory"

fname = getOpenFileName \ 
caption:"Open No More Heroes 360 Model File" \
types:"No More Heroes 360 Model File(*model)|*model" \
historyCategory:"No More Heroes 360 ObjectPresets"
f = fopen fname "rb"

fn ReadBEShort fstream = (
short = readshort fstream #unsigned
short = bit.swapBytes short 2 1
b = (bit.get short 16)
for i = 17 to 32 do short = bit.set short i b
return short
)

fn PrintOffset Var =
(
	local Var = Var
print ("This is the offset 0x" + (bit.intAsHex Var) as string)
	Var
)

fn floatSwap2 f = 
(
	i = bit.floatAsInt f
	h = bit.intashex i
	while h.count < 8 do h = "0" + h
	
	s = (substring h 7 2) + (substring h 5 2) + (substring h 3 2) + (substring h 1 2)
	bit.intAsFloat (bit.hexasint s)
)	

fn ReadBEword fstream = (
return (bit.swapBytes (readshort fstream #unsigned) 1 2)
)

 	fn convertTo32 input16 = (
 		inputAsInt = input16
 		sign = bit.get inputAsInt 16
 		exponent = (bit.shift (bit.and inputAsInt (bit.hexasint "7C00")) -10) as integer - 16
 		fraction = bit.and inputAsInt (bit.hexasint "03FF")
 		if sign==true then sign = 1 else sign = 0
 		exponentF = exponent + 127
 		--Ouput 32 bit integer representing a 32 bit float
 		outputAsFloat = bit.or (bit.or (bit.shift fraction 13) (bit.shift exponentF 23)) (bit.shift sign 31)
 		--Output Check	
 		return bit.intasfloat outputasfloat
 	)

fn ReadBEHalfFloat fstream = (
return convertTo32(ReadBEword fstream)
)

fn ReadBElong fstream = (
long = readlong fstream
long = bit.swapBytes long 1 4
long = bit.swapBytes long 2 3
return long
)

fn ReadBEfloat fstream = (
return floatSwap2(readfloat fstream)
)

fn ReadFixedString bstream fixedLen =
(
	local str = ""
	for i = 1 to fixedLen do
	(
		str += bit.intAsChar (ReadByte bstream #unsigned)
	)
	str
)

struct weight_data
(
	boneids,weights
)

struct Mesh_Info_Struct
(
	Mesh_Name,vertstart,vertend,vertcount,facecount,InfoStart,MeshGroup,FaceStart
)
MNKS0101 = ReadFixedString f 8
Version = ReadBElong f
null = ReadBElong f
Modelname = ReadFixedString f 32
total_size = getFileSize fname
RXET_array = #()
TNOJ_array = #()
ARTM_array = #()
RDHS_array = #()
KSEM_array = #()
PHSB_array = #()
struct type_Info_Struct
(
	Pos,type,typesize
)
while (ftell f) != total_size Do (
Pos = (ftell f)
type = ReadFixedString f 4
typesize = ReadBElong f
fseek f (pos + typesize)#seek_set
case of
(
(type == "RXET"): append RXET_array (type_Info_Struct Pos:Pos type:type typesize:typesize)
(type == "TNOJ"): append TNOJ_array (type_Info_Struct Pos:Pos type:type typesize:typesize)
(type == "ARTM"): append ARTM_array (type_Info_Struct Pos:Pos type:type typesize:typesize)
(type == "RDHS"): append RDHS_array (type_Info_Struct Pos:Pos type:type typesize:typesize)
(type == "KSEM"): append KSEM_array (type_Info_Struct Pos:Pos type:type typesize:typesize)
(type == "PHSB"): append PHSB_array (type_Info_Struct Pos:Pos type:type typesize:typesize)
default: print type
)
)
BNArr = #()
for a =1 to TNOJ_array.count Do (
fseek f (TNOJ_array[a].Pos + 8)#seek_set
Size1 = ReadBElong f
Null1 = ReadBElong f
SkelName = ReadFixedString f 32
BoneCount = ReadBElong f
Version = ReadBElong f
fseek f 0x8#seek_cur

for b = 1 to BoneCount do (
BoneName = ReadFixedString f 0x20
m11 = ReadBEFloat f; m12 = ReadBEFloat f; m13 = ReadBEFloat f; m14 = ReadBEFloat f
m21 = ReadBEFloat f; m22 = ReadBEFloat f; m23 = ReadBEFloat f; m24 = ReadBEFloat f
m31 = ReadBEFloat f; m32 = ReadBEFloat f; m33 = ReadBEFloat f; m34 = ReadBEFloat f
m41 = ReadBElong f; m42 = ReadBElong f; m43 = ReadBElong f; m44 = ReadBElong f
tfm = (quat m21 m22 m23 m24) as matrix3
tfm.row4 = [m11,m12,m13]

newBone = bonesys.createbone	\
				  tfm.row4	\
				  (tfm.row4 + 0.01 * (normalize tfm.row1)) \
				  (normalize tfm.row3)
			newBone.name = BoneName
			newBone.width  = 0.01
			newBone.height = 0.01
			newBone.transform = tfm
			newBone.setBoneEnable false 0
			newBone.wirecolor = yellow
			newbone.showlinks = true
			newBone.pos.controller      = TCB_position ()
			newBone.rotation.controller = TCB_rotation ()


 if (m41 != -1) then
 newBone.parent = BNArr[m41 + 1]
append BNArr newBone	
)
)

struct Mesh_Info2_Struct
(
	Vert_Start,FaceStart,VertTotal,FaceTotal,vertsize
)
Mesh_Info2_Array = #()
for a =1 to KSEM_array.count Do (
fseek f (KSEM_array[a].Pos + 8)#seek_set
Size1 = ReadBElong f
Null1 = ReadBElong f
SkinName = ReadFixedString f 32	
MeshSections = ReadBElong f
unk01 = ReadBElong f
MeshCount = ReadBEword f
fseek f 0x6#seek_cur
for b = 1 to MeshSections Do (
SceneName = ReadFixedString f 32
VertTotal = ReadBElong f
FaceTotal = ReadBElong f
vertsize = ReadBEword f
facesize = ReadBEword f
Unk01 = ReadBElong f
Vert_Start = (ftell f)
fseek f (Vert_Start + VertTotal)#seek_set
if mod (ftell f) 16 != 0 do (
fseek f (16 - (mod (ftell f) 16))#seek_cur
)
FaceStart = (ftell f)
fseek f (FaceStart + FaceTotal)#seek_set
if mod (ftell f) 16 != 0 do (
fseek f (16 - (mod (ftell f) 16))#seek_cur
)
append Mesh_Info2_Array (Mesh_Info2_Struct Vert_Start:Vert_Start FaceStart:FaceStart VertTotal:VertTotal FaceTotal:FaceTotal vertsize:vertsize)
)
MeshInfoOff = (ftell f)
Mesh_Info_Array = #()
PrintOffset (ftell f)

for b = 1 to MeshCount Do (
InfoStart = (ftell f)
Mesh_Name = ReadFixedString f 32
facecount = ReadBEword f
vertstart = ReadBEword f
vertend = ReadBEword f
vertcount = ReadBEword f
Unk03 = readbyte f#unsigned
Unk04 = readbyte f#unsigned
Unk05 = readbyte f#unsigned
MeshGroup = ((readbyte f#unsigned) + 1)
Unk01 = ReadBElong f
Unk02 = ReadBElong f
FaceStart = ReadBElong f
fseek f 0x68#seek_cur
append Mesh_Info_Array (Mesh_Info_Struct Mesh_Name:Mesh_Name vertstart:vertstart vertend:vertend vertcount:vertcount facecount:facecount InfoStart:InfoStart MeshGroup:MeshGroup FaceStart:FaceStart)
)
print Mesh_Info_Array


for b = 1 to MeshCount do (
Vert_array = #()
Normal_array = #()
UV_array = #()
Face_array = #()
Weight_array = #()
BaseVert = Mesh_Info2_Array[(Mesh_Info_Array[b].MeshGroup)].Vert_Start
vertsize =  Mesh_Info2_Array[(Mesh_Info_Array[b].MeshGroup)].vertsize
fseek f (BaseVert + (Mesh_Info_Array[b].vertstart * vertsize))#seek_set
printoffset (ftell f)
for c = 1 to Mesh_Info_Array[b].vertcount do (

if vertsize == 48 do (
vx = ReadBEfloat f
vy = ReadBEfloat f 
vz = ReadBEfloat f
COLOR1 = readlong f
weight1 = readbyte f#unsigned
weight2 = readbyte f#unsigned
weight3 = readbyte f#unsigned
weight4 = readbyte f#unsigned
bone1 = readbyte f#unsigned
bone2 = readbyte f#unsigned
bone3 = readbyte f#unsigned
bone4 = readbyte f#unsigned
xy = ReadBEfloat f
xz = ReadBEfloat f
tu = (ReadBEHalfFloat f) * 2
tv = (ReadBEHalfFloat f) * -2
nx = ReadBEfloat f
ny = ReadBEfloat f
nz = ReadBEfloat f

)

if vertsize == 44 do (
vx = ReadBEfloat f
vy = ReadBEfloat f 
vz = ReadBEfloat f
COLOR1 = readlong f
weight1 = readbyte f#unsigned
weight2 = readbyte f#unsigned
weight3 = readbyte f#unsigned
weight4 = readbyte f#unsigned
bone1 = readbyte f#unsigned
bone2 = readbyte f#unsigned
bone3 = readbyte f#unsigned
bone4 = readbyte f#unsigned
xy = ReadBEfloat f
xz = ReadBEfloat f
tu = (ReadBEHalfFloat f) * 2
tv = (ReadBEHalfFloat f) * -2
nx = ReadBEfloat f
ny = ReadBEfloat f
nz = ReadBEfloat f
)

if 	vertsize == 40 do (
vx = ReadBEfloat f
vy = ReadBEfloat f 
vz = ReadBEfloat f
COLOR1 = readlong f
weight1 = readbyte f#unsigned
weight2 = readbyte f#unsigned
weight3 = readbyte f#unsigned
weight4 = readbyte f#unsigned
bone1 = readbyte f#unsigned
bone2 = readbyte f#unsigned
bone3 = readbyte f#unsigned
bone4 = readbyte f#unsigned
tu = (ReadBEHalfFloat f) * 2
tv = (ReadBEHalfFloat f) * -2
nx = ReadBEfloat f
ny = ReadBEfloat f
nz = ReadBEfloat f
)
if 	vertsize == 36 do (
vx = ReadBEfloat f
vy = ReadBEfloat f 
vz = ReadBEfloat f
COLOR1 = readlong f
weight1 = readbyte f#unsigned
weight2 = readbyte f#unsigned
weight3 = readbyte f#unsigned
weight4 = readbyte f#unsigned
bone1 = readbyte f#unsigned
bone2 = readbyte f#unsigned
bone3 = readbyte f#unsigned
bone4 = readbyte f#unsigned
tu = (ReadBEHalfFloat f) * 2
tv = (ReadBEHalfFloat f) * -2
fseek f 0x8#seek_cur
)
if 	vertsize == 32 do (
vx = ReadBEfloat f
vy = ReadBEfloat f 
vz = ReadBEfloat f
COLOR1 = readlong f
weight1 = 255.0
weight2 = 0
weight3 = 0
weight4 = 0
bone1 = 0
bone2 = 0
bone3 = 0
bone4 = 0
tu = (ReadBEHalfFloat f) * 2
tv = (ReadBEHalfFloat f) * -2
fseek f 0x4#seek_cur
COLOR2 = readlong f
COLOR3 = readlong f
)
w = (weight_data boneids:#() weights:#())
maxweight = 0
if(weight1 != 0) then
	maxweight = maxweight + weight1
if(weight2 != 0) then
	maxweight = maxweight + weight2
if(weight3 != 0) then
	maxweight = maxweight + weight3
if(weight4 != 0) then
	maxweight = maxweight + weight4

if(maxweight != 0) then (
		if(weight1 != 0) then (
			w1 = weight1 as float
			append w.boneids (bone1 + 1)
			append w.weights w1
		)
		if(weight2 != 0) then (
			w2 = weight2 as float
			append w.boneids (bone2 + 1)
			append w.weights w2
		)
		if(weight3 != 0) then (
			w3 = weight3 as float
			append w.boneids (bone3 + 1)
			append w.weights w3
		)
		if(weight4 != 0) then (
			w4 = weight4 as float
			append w.boneids (bone4 + 1)
			append w.weights w4
		)		
	)
append Weight_array w
append Vert_array [vx,vy,vz]
--append Normal_array [nx,ny,nz]
append UV_array [tu,tv,0]

)
BaseFace = Mesh_Info2_Array[(Mesh_Info_Array[b].MeshGroup)].FaceStart
fseek f ((Mesh_Info_Array[b].FaceStart * 2) + BaseFace)#seek_set
for d = 1 to Mesh_Info_Array[b].facecount do (
f1 = ReadBEword f + 1
f2 = ReadBEword f + 1
f3 = ReadBEword f + 1
append Face_array [f1,f2,f3]
)

fseek f (Mesh_Info_Array[b].InfoStart + 0x50)#seek_set
usedbones = ReadBElong f
null = ReadBElong f
bidArray = #()
for c = 1 to usedbones do (
bid = ((readbyte f#unsigned) + 1)
append bidArray bid
)
msh = mesh vertices:Vert_array faces:Face_array
msh.numTVerts = UV_array.count
buildTVFaces msh
msh.name = Mesh_Info_Array[b].Mesh_Name + "_" + b as string
for j = 1 to UV_array.count do setTVert msh j UV_array[j]
for j = 1 to Face_array.count do setTVFace msh j Face_array[j]
for j = 1 to Normal_array.count do setNormal msh j Normal_array[j]
	
max modify mode
select msh
skinMod = skin ()
addModifier msh skinMod
for i = 1 to bidArray.count do
(
	maxbone = BNArr[(bidArray[i])]
	if i != bidArray.count then
		skinOps.addBone skinMod maxbone 0
	else
		skinOps.addBone skinMod maxbone 1
)
modPanel.setCurrentObject skinMod
for i = 1 to Weight_array.count do
(
	w = Weight_array[i]
	bi = #()
	wv = #()
	for j = 1 to w.boneids.count do
	(
		boneid = w.boneids[j]
		weight = w.weights[j]
		append bi boneid
		append wv weight
	)	
	skinOps.ReplaceVertexWeights skinMod i bi wv
)


modPanel.setCurrentObject $.baseObject prompt:false
modPanel.addModToSelection (Vertex_Weld ()) ui:on
$.modifiers[#Vertex_Weld].threshold = 0.001
max create mode

)

)

fclose f
mariokart64n
ultra-veteran
ultra-veteran
Posts: 586
Joined: Sun Jun 05, 2005 12:00 pm
Location: Ontario, Canada
Has thanked: 36 times
Been thanked: 244 times

Re: No More Heroes: Heroes' Paradise

Post by mariokart64n »

awesome, thanks man. NMH is my favorite game, such a shame the dev closed the book on the series.

EDIT
Image

Code: Select all

if vertsize == 0x20 do
(
vx = ReadBEfloat f
vy = ReadBEfloat f
vz = ReadBEfloat f
fseek f 0x4#seek_cur -- FFs
tu = (ReadBEHalfFloat f) * 2
tv = (ReadBEHalfFloat f) * -2
nx = ReadBEfloat f
ny = ReadBEfloat f
nz = ReadBEfloat f
)
Maxscript and other finished work I've done can be found on my DeviantArt account
Nazaroff
advanced
Posts: 40
Joined: Mon Oct 11, 2010 12:30 pm
Has thanked: 7 times
Been thanked: 12 times

Re: No More Heroes: Heroes' Paradise

Post by Nazaroff »

Hi, chrrox.
You always write
Supports bones and weights.
But never write about animation. You never tried to import animations too? I mean not this game only. :roll:
Ares722
veteran
Posts: 154
Joined: Thu Jul 15, 2010 2:15 pm
Has thanked: 25 times
Been thanked: 9 times

Re: No More Heroes: Heroes' Paradise

Post by Ares722 »

Thank you so much^^ amazing work as usually,...
daisuki
ultra-n00b
Posts: 9
Joined: Thu Mar 03, 2011 6:12 am

Re: No More Heroes: Heroes' Paradise

Post by daisuki »

Could you explain how to extract the model file ,please?
chrrox
Moderator
Posts: 2602
Joined: Sun May 18, 2008 3:01 pm
Has thanked: 57 times
Been thanked: 1428 times

Re: No More Heroes: Heroes' Paradise

Post by chrrox »

Model BMS
run it on the 360 file default.fpd

Code: Select all

#Quickbms script
#No more heroes xbox 360 .model extractor
#by chrrox
for
findloc start string "MNKS0101"
goto start
savepos offset
findloc npos string KSEM
math npos + 0x40
goto npos
getdstring name 0x20
string name + .model
findloc end string " FOE"
set size end
math size - start
log name offset size
goto end
next
You do not have the required permissions to view the files attached to this post.
daisuki
ultra-n00b
Posts: 9
Joined: Thu Mar 03, 2011 6:12 am

Re: No More Heroes: Heroes' Paradise

Post by daisuki »

Thank you very much.
Master chrrox.
noazett
advanced
Posts: 55
Joined: Mon Dec 14, 2009 1:09 am
Has thanked: 19 times
Been thanked: 1 time

Re: No More Heroes: Heroes' Paradise

Post by noazett »

The contents of this post was deleted because of possible forum rules violation.
chrrox
Moderator
Posts: 2602
Joined: Sun May 18, 2008 3:01 pm
Has thanked: 57 times
Been thanked: 1428 times

Re: No More Heroes: Heroes' Paradise

Post by chrrox »

You extracted 360 models correct?
the ps3 models will not work.
noazett
advanced
Posts: 55
Joined: Mon Dec 14, 2009 1:09 am
Has thanked: 19 times
Been thanked: 1 time

Re: No More Heroes: Heroes' Paradise

Post by noazett »

yes these are model files from 360 version. I used xbox backup creator to extract default.fpd from the game
The Chief
veteran
Posts: 101
Joined: Fri Oct 09, 2009 3:44 am
Has thanked: 90 times
Been thanked: 10 times

Re: No More Heroes: Heroes' Paradise

Post by The Chief »

I test the files you posted on max 9 and 2009 but they dont work , max just freez every
time i test one of the files.
noazett
advanced
Posts: 55
Joined: Mon Dec 14, 2009 1:09 am
Has thanked: 19 times
Been thanked: 1 time

Re: No More Heroes: Heroes' Paradise

Post by noazett »

The Chief wrote:I test the files you posted on max 9 and 2009 but they dont work , max just freez every
time i test one of the files.

yes this is exactly the same issue i 've got. maybe the files are corrupted or something.
i will try to extract them with another tool.
thx
chrrox
Moderator
Posts: 2602
Joined: Sun May 18, 2008 3:01 pm
Has thanked: 57 times
Been thanked: 1428 times

Re: No More Heroes: Heroes' Paradise

Post by chrrox »

Ah i fixed the bms one line copy paste error now it should work.
noazett
advanced
Posts: 55
Joined: Mon Dec 14, 2009 1:09 am
Has thanked: 19 times
Been thanked: 1 time

Re: No More Heroes: Heroes' Paradise

Post by noazett »

thanks a lot chrrox :)
rexil
veteran
Posts: 124
Joined: Tue Mar 15, 2011 3:14 pm
Has thanked: 36 times
Been thanked: 4 times

Re: No More Heroes: Heroes' Paradise

Post by rexil »

Thanks, awesome as always.
Post Reply