Javascript ES6, 229 * 80% * 75% * 50% = 68.7 bytes
Test Input
I'm using the following test data:
var A1=[
5,6,7, // => 5-7 # (a) group pages
2,3, // => 2-3,5-7 # (b) must be properly sorted
-9,-8,-7, // => -10--8 # (c) allow negative numbers
29,30,31,32, // => 29-2 # (d) lower last digit implies increasing the 10s place
9,10,11,12, // => 9-11 # NOT 9-2
36,37,38,39,40,41,42,43,44,45,46,47,
// => 36-47 # NOT 36-7
99,100,101,102, // => 99-102 # NOT 99-2
109,110,111,112, // => 109-2 # NOT 109-12
],
// more tests, not specified in the question
A2=[
120,124, // => 120,124 # (e) handle single pages
],
A3=[
135,136,135 // => 135-6 # (f) handle duplicates
];
Basic: 229 bytes
This version satisfies the requirements of the question (a) with all bonuses (c,d,e), but hangs on single pages. It can also handle duplicates(f). It hangs negative pages down to -10,000, which can be easily increased with (large) loss of speed.
F=(a)=>{var R=[],i=NaN,l,u;a.map(x=>R[1e4+x]=x);R.concat('').map(x=>(i!=i&&(l=x,u=l-1),i=0,u=(x+="")-u-1?l=console.log(l+'-'+(u>0?(l.length-u.length||(z=>{for(;l[i]==u[i];i++);})(),u.length-i-2||u-l>9||i++,u.slice(i)):u))||x:x))}
F(A1.concat(A3)) --> -9--7 2-3 5-7 9-12 29-2 36-47 99-102 109-2 135-136
(The output above shows spaces instead of actual newlines for brevity)
Single pages: 233 bytes
This slightly longer version additionally satisfies (e) and displays single pages as a range with equal lower and upper limits
G=(a)=>{var R=[],i=NaN,l,u;a.map(x=>R[1e4+x]=x);R.concat('').map(x=>(i!=i&&(l=x,u=l-1),i=0,u=(x+="")-u-1?l=console.log(l+'-'+(u-l&u>0?(l.length-u.length||(z=>{for(;l[i]==u[i];i++);})(),u.length-i-2||u-l>9||i++,u.slice(i)):u))||x:x))}
G(A1.concat(A2,A3)) --> -9--7 2-3 5-7 9-12 29-2 36-47 99-102 109-2 120 124